From 18a498b6cdbae130ed0871b06ad508b77b2a1b00 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Thu, 15 Aug 2024 20:31:09 +0000 Subject: [PATCH 001/275] Merged PR 32128: Update third party notices #### AI description (iteration 1) #### PR Classification Documentation update #### PR Summary This pull request updates the third-party notices to reflect changes in dependencies and their respective licenses. - Updated `ThirdPartyNotices.txt` to reflect new versions and copyright holders for several dependencies. - Removed detailed Apache License text for `Microsoft.Extensions.ObjectPool` and replaced it with a summary. - Added new entries for `Microsoft.Extensions.ObjectPool 8.0.4` and updated versions for other dependencies like `Microsoft.Bcl.AsyncInterfaces`, `System.Security.AccessControl`, and various `Json` libraries. --- ThirdPartyNotices.txt | 307 ++++++++++++++++++------------------------ 1 file changed, 129 insertions(+), 178 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 4c6db295cec..27dd8ead268 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -17,125 +17,7 @@ required to debug changes to any libraries licensed under the GNU Lesser General --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 5.0.10 - Apache-2.0 - - -(c) Microsoft Corporation -Copyright (c) Andrew Arnott -Copyright (c) 2019 David Fowler -Copyright (c) 2016 Richard Morris -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) Microsoft Corporation -Copyright (c) 2014-2018 Michael Daines -Copyright (c) 2013-2017, Milosz Krajewski -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2019-2020 West Wind Technologies -Copyright (c) 2010-2019 Google LLC. http://angular.io/license -Copyright (c) Sindre Sorhus (https://sindresorhus.com) - -Apache License - -Version 2.0, January 2004 - -http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - - - "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - - - - "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - - - - "Legal Entity" 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, "control" 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. - - - - "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - - - - "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - - - - "Object" 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. - - - - "Work" 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). - - - - "Derivative Works" 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. - - - - "Contribution" 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, "submitted" 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 "Not a Contribution." - - - - "Contributor" 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: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) 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 - - (d) If the Work includes a "NOTICE" 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 "AS IS" 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 - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); - -you may not use this file except in compliance with the License. - -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software - -distributed under the License is distributed on an "AS IS" BASIS, - -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -See the License for the specific language governing permissions and - -limitations under the License. - ---------------------------------------------------------- - ---------------------------------------------------------- - -Markdig.Signed 0.34.0 - BSD-2-Clause +Markdig.Signed 0.37.0 - BSD-2-Clause @@ -173,15 +55,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Json.More.Net 2.0.0 - MIT +Json.More.Net 2.0.1.2 - MIT -(c) Microsoft 2024 -Copyright (c) 2022 Greg Dennis +Copyright (c) 2024 Greg Dennis MIT License -Copyright (c) 2022 Greg Dennis +Copyright (c) 2024 Greg Dennis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -206,15 +87,14 @@ SOFTWARE. --------------------------------------------------------- -JsonPointer.Net 4.0.0 - MIT +JsonPointer.Net 5.0.0 - MIT -(c) Microsoft 2024 -Copyright (c) 2022 Greg Dennis +Copyright (c) 2024 Greg Dennis MIT License -Copyright (c) 2022 Greg Dennis +Copyright (c) 2024 Greg Dennis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -239,7 +119,7 @@ SOFTWARE. --------------------------------------------------------- -JsonSchema.Net 6.0.2 - MIT +JsonSchema.Net 7.0.1 - MIT @@ -276,45 +156,62 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Bcl.AsyncInterfaces 5.0.0 - MIT +Microsoft.Bcl.AsyncInterfaces 8.0.0 - MIT -(c) Microsoft Corporation. +Copyright (c) Six Labors +(c) Microsoft Corporation Copyright (c) Andrew Arnott +Copyright 2019 LLVM Project Copyright 2018 Daniel Lemire -Copyright 2012 the V8 project -Copyright (c) .NET Foundation. +Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. +Copyright (c) 2020 Dan Shechter +(c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To -(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) 2022, Geoff Langdale +Copyright (c) 2005-2020 Rich Felker +Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 2012-2014, Yann Collet +Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright 2012 the V8 project authors +Copyright (c) 1999 Lucent Technologies +Copyright (c) 2008-2016, Wojciech Mula +Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula +Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin +Copyright (c) The Internet Society 1997 Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. -Copyright (c) The Internet Society 1997. Copyright (c) 2004-2006 Intel Corporation +Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors -Copyright (c) The Internet Society (2003). +Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors +Copyright (c) 2012 - present, Victor Zverovich +Copyright (c) 2006 Jb Evain (jbevain@gmail.com) +Copyright (c) 2008-2020 Advanced Micro Devices, Inc. +Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California. -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip +Copyright (c) 1980, 1986, 1993 The Regents of the University of California +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass The MIT License (MIT) @@ -345,7 +242,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.CodeAnalysis.Common 4.8.0 - MIT +Microsoft.CodeAnalysis.Common 4.9.2 - MIT (c) Microsoft Corporation @@ -365,7 +262,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.CodeAnalysis.CSharp 4.8.0 - MIT +Microsoft.CodeAnalysis.CSharp 4.9.2 - MIT (c) Microsoft Corporation @@ -387,6 +284,56 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- +Microsoft.Extensions.ObjectPool 8.0.4 - MIT + + +Copyright 2019 The gRPC +Copyright Jorn Zaefferer +(c) Microsoft Corporation +Copyright (c) Andrew Arnott +Copyright (c) 2015, Google Inc. +Copyright (c) 2019 David Fowler +Copyright (c) HTML5 Boilerplate +Copyright (c) 2016 Richard Morris +Copyright (c) 1998 John D. Polstra +Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) Microsoft Corporation +Copyright (c) 2007 James Newton-King +Copyright (c) 2013 - 2018 AngleSharp +Copyright (c) 2000-2013 Julian Seward +Copyright (c) 2011-2021 Twitter, Inc. +Copyright (c) 2014-2018 Michael Daines +Copyright (c) 1996-1998 John D. Polstra +Copyright (c) 2013-2017, Milosz Krajewski +Copyright (c) .NET Foundation Contributors +Copyright (c) 2011-2021 The Bootstrap Authors +Copyright (c) 2019-2023 The Bootstrap Authors +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2019-2020 West Wind Technologies +Copyright (c) 2007 John Birrell (jb@freebsd.org) +Copyright (c) 2011 Alex MacCaw (info@eribium.org) +Copyright (c) Nicolas Gallagher and Jonathan Neal +Copyright (c) 2010-2019 Google LLC. http://angular.io/license +Copyright (c) 2011 Nicolas Gallagher (nicolas@nicolasgallagher.com) +Copyright (c) 1989, 1993 The Regents of the University of California +Copyright (c) 1990, 1993 The Regents of the University of California +Copyright OpenJS Foundation and other contributors, https://openjsf.org +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 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 "AS IS", 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. + +--------------------------------------------------------- + +--------------------------------------------------------- + Microsoft.PowerShell.MarkdownRender 7.2.1 - MIT @@ -652,7 +599,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Windows.Compatibility 8.0.2 - MIT +Microsoft.Windows.Compatibility 8.0.8 - MIT (c) Microsoft Corporation @@ -705,7 +652,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.android-arm.runtime.native.System.IO.Ports 9.0.0-preview.1.24080.9 - MIT +runtime.android-arm.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT Copyright (c) Six Labors @@ -794,7 +741,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-arm64.runtime.native.System.IO.Ports 9.0.0-preview.1.24080.9 - MIT +runtime.android-arm64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT Copyright (c) Six Labors @@ -883,7 +830,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x64.runtime.native.System.IO.Ports 9.0.0-preview.1.24080.9 - MIT +runtime.android-x64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT Copyright (c) Six Labors @@ -972,7 +919,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x86.runtime.native.System.IO.Ports 9.0.0-preview.1.24080.9 - MIT +runtime.android-x86.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT Copyright (c) Six Labors @@ -1233,7 +1180,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.0-preview.1.24080.9 - MIT +runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT Copyright (c) Six Labors @@ -1322,7 +1269,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.0-preview.1.24080.9 - MIT +runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT Copyright (c) Six Labors @@ -1411,7 +1358,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.0-preview.1.24080.9 - MIT +runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT Copyright (c) Six Labors @@ -1500,7 +1447,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.0-preview.1.24080.9 - MIT +runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT Copyright (c) Six Labors @@ -1589,7 +1536,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.0-preview.1.24080.9 - MIT +runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT Copyright (c) Six Labors @@ -1764,7 +1711,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.0-preview.1.24080.9 - MIT +runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT Copyright (c) Six Labors @@ -1853,7 +1800,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.0-preview.1.24080.9 - MIT +runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT Copyright (c) Six Labors @@ -2908,7 +2855,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.DiagnosticSource 8.0.0 - MIT +System.Diagnostics.DiagnosticSource 8.0.1 - MIT Copyright (c) Six Labors @@ -3424,7 +3371,7 @@ SOFTWARE. --------------------------------------------------------- -System.Drawing.Common 8.0.2 - MIT +System.Drawing.Common 8.0.8 - MIT (c) Microsoft Corporation @@ -3459,7 +3406,7 @@ SOFTWARE. --------------------------------------------------------- -System.Formats.Asn1 8.0.0 - MIT +System.Formats.Asn1 8.0.1 - MIT Copyright (c) Six Labors @@ -3803,7 +3750,7 @@ SOFTWARE. --------------------------------------------------------- -System.Net.Http.WinHttpHandler 8.0.0 - MIT +System.Net.Http.WinHttpHandler 8.0.2 - MIT Copyright (c) Six Labors @@ -4360,45 +4307,50 @@ SOFTWARE. --------------------------------------------------------- -System.Security.AccessControl 6.0.0 - MIT +System.Security.AccessControl 6.0.1 - MIT -(c) Microsoft Corporation. +(c) Microsoft Corporation Copyright (c) Andrew Arnott +Copyright 2019 LLVM Project Copyright 2018 Daniel Lemire -Copyright 2012 the V8 project -Copyright (c) .NET Foundation. +Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. +Copyright (c) 2020 Dan Shechter +(c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To -(c) 1997-2005 Sean Eron Anderson. Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) 2005-2020 Rich Felker Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 2012-2014, Yann Collet +Copyright (c) 1991-2020 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright 2012 the V8 project authors +Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin +Copyright (c) The Internet Society 1997 Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. -Copyright (c) The Internet Society 1997. Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors -Copyright (c) The Internet Society (2003). Copyright (c) .NET Foundation and Contributors Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California. -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -4602,7 +4554,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Xml 8.0.0 - MIT +System.Security.Cryptography.Xml 8.0.1 - MIT Copyright (c) Six Labors @@ -5795,4 +5747,3 @@ 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. - From 22285f5c423e7f3d8a243b786e93c9de7a20dc8e Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Wed, 21 Aug 2024 18:22:22 +0000 Subject: [PATCH 002/275] Merged PR 32244: Fix Validate SDK step by removing unncessary nuget file modification #### AI description (iteration 1) #### PR Classification Bug fix to remove unnecessary NuGet file modification in the Validate SDK step. #### PR Summary This pull request removes redundant modifications to the NuGet configuration file in the release validation pipeline. - `.pipelines/templates/release-validate-sdk.yml`: Commented out the code that modifies the NuGet configuration file to prevent unnecessary changes. --- .pipelines/templates/release-validate-sdk.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index 4903f78d57f..3cd5425478e 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -87,11 +87,11 @@ jobs: Start-PSBootstrap $localLocation = "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" - $xmlElement = @" - - - - "@ + # $xmlElement = @" + # + # + # + # "@ $releaseVersion = '$(Version)' @@ -102,12 +102,12 @@ jobs: Get-ChildItem ## register the packages download directory in the nuget file - $nugetConfigContent = Get-Content ./NuGet.Config -Raw - $updateNugetContent = $nugetConfigContent.Replace("", $xmlElement) + # $nugetConfigContent = Get-Content ./NuGet.Config -Raw + # $updateNugetContent = $nugetConfigContent.Replace("", $xmlElement) - $updateNugetContent | Out-File ./NuGet.Config -Encoding ascii + # $updateNugetContent | Out-File ./NuGet.Config -Encoding ascii - Get-Content ./NuGet.Config + # Get-Content ./NuGet.Config # Add workaround to unblock xUnit testing see issue: https://github.com/dotnet/sdk/issues/26462 $dotnetPath = if ($IsWindows) { "$env:LocalAppData\Microsoft\dotnet" } else { "$env:HOME/.dotnet" } From 6695ffb6a80038753c8a8bec65eba7f760609d81 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Wed, 21 Aug 2024 19:30:56 +0000 Subject: [PATCH 003/275] Merged PR 32255: Add `PSRedirectToVariable` to experimental features json file #### AI description (iteration 1) #### PR Classification New feature #### PR Summary This pull request adds a new experimental feature to the configuration files for both Linux and Windows platforms. - `experimental-feature-linux.json`: Added `PSRedirectToVariable` to the list of experimental features. - `experimental-feature-windows.json`: Added `PSRedirectToVariable` to the list of experimental features. --- experimental-feature-linux.json | 3 ++- experimental-feature-windows.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/experimental-feature-linux.json b/experimental-feature-linux.json index 291d28159e4..b5af1955d29 100644 --- a/experimental-feature-linux.json +++ b/experimental-feature-linux.json @@ -5,5 +5,6 @@ "PSLoadAssemblyFromNativeCode", "PSModuleAutoLoadSkipOfflineFiles", "PSNativeWindowsTildeExpansion", - "PSSubsystemPluginModel" + "PSSubsystemPluginModel", + "PSRedirectToVariable" ] diff --git a/experimental-feature-windows.json b/experimental-feature-windows.json index 291d28159e4..b5af1955d29 100644 --- a/experimental-feature-windows.json +++ b/experimental-feature-windows.json @@ -5,5 +5,6 @@ "PSLoadAssemblyFromNativeCode", "PSModuleAutoLoadSkipOfflineFiles", "PSNativeWindowsTildeExpansion", - "PSSubsystemPluginModel" + "PSSubsystemPluginModel", + "PSRedirectToVariable" ] From e00157e7aa439e3a14aff9f76b560154af55a24d Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Wed, 28 Aug 2024 18:24:04 +0000 Subject: [PATCH 004/275] Merged PR 32242: Update CHANGELOG for v7.5.0-preview.4 release #### AI description (iteration 1) #### PR Classification Documentation update for the v7.5.0-preview.4 release. #### PR Summary This pull request updates the changelog to document the changes and improvements introduced in the v7.5.0-preview.4 release. - `CHANGELOG/preview.md`: Added entries for engine updates, general cmdlet updates, code cleanup, tools, tests, build and packaging improvements, and documentation updates. --- CHANGELOG/preview.md | 119 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index 444b58e5b9e..73d39ba122a 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,124 @@ # Preview Changelog +## [7.5.0-preview.4] - 2024-08-28 + +### Engine Updates and Fixes + +- RecommendedAction: Explicitly start and stop ANSI Error Color (#24065) (Thanks @JustinGrote!) +- Improve .NET overload definition of generic methods (#21326) (Thanks @jborean93!) +- Optimize the `+=` operation for a collection when it's an object array (#23901) (Thanks @jborean93!) +- Allow redirecting to a variable as experimental feature `PSRedirectToVariable` (#20381) + +### General Cmdlet Updates and Fixes + +- Change type of `LineNumber` to `ulong` in `Select-String` (#24075) (Thanks @Snowman-25!) +- Fix `Invoke-RestMethod` to allow `-PassThru` and `-Outfile` work together (#24086) (Thanks @jshigetomi!) +- Fix Hyper-V Remoting when the module is imported via implicit remoting (#24032) (Thanks @jborean93!) +- Add `ConvertTo-CliXml` and `ConvertFrom-CliXml` cmdlets (#21063) (Thanks @ArmaanMcleod!) +- Add `OutFile` property in `WebResponseObject` (#24047) (Thanks @jshigetomi!) +- Show filename in `Invoke-WebRequest -OutFile -Verbose` (#24041) (Thanks @jshigetomi!) +- `Set-Acl`: Do not fail on untranslatable SID (#21096) (Thanks @jborean93!) +- Fix the extent of the parser error when a number constant is invalid (#24024) +- Fix `Move-Item` to throw error when moving into itself (#24004) +- Fix up .NET method invocation with `Optional` argument (#21387) (Thanks @jborean93!) +- Fix progress calculation on `Remove-Item` (#23869) (Thanks @jborean93!) +- Fix WebCmdlets when `-Body` is specified but `ContentType` is not (#23952) (Thanks @CarloToso!) +- Enable `-NoRestart` to work with `Register-PSSessionConfiguration` (#23891) +- Add `IgnoreComments` and `AllowTrailingCommas` options to `Test-Json` cmdlet (#23817) (Thanks @ArmaanMcleod!) +- Get-Help may report parameters with `ValueFromRemainingArguments` attribute as pipeline-able (#23871) + +### Code Cleanup + +
+ + + +

We thank the following contributors!

+

@xtqqczze, @eltociear

+ +
+ +
    +
  • Minor cleanup on local variable names within a method (#24105)
  • +
  • Remove explicit IDE1005 suppressions (#21217) (Thanks @xtqqczze!)
  • +
  • Fix a typo in WebRequestSession.cs (#23963) (Thanks @eltociear!)
  • +
+ +
+ +### Tools + +- devcontainers: mount workspace in /PowerShell (#23857) (Thanks @rzippo!) + +### Tests + +- Add debugging to the MTU size test (#21463) + +### Build and Packaging Improvements + +
+ + + +

We thank the following contributors!

+

@bosesubham2011

+ +
+ +
    +
  • Update third party notices (Internal 32128)
  • +
  • Update cgmanifest (#24163)
  • +
  • Fixes to Azure Public feed usage (#24149)
  • +
  • Add support for back porting PRs from GitHub or the Private Azure Repos (#20670)
  • +
  • Move to 9.0.0-preview.6.24327.7 (#24133)
  • +
  • update path (#24134)
  • +
  • Update to the latest NOTICES file (#24131)
  • +
  • Fix semver issue with updating cgmanifest (#24132)
  • +
  • Add ability to capture MSBuild Binary logs when restore fails (#24128)
  • +
  • add ability to skip windows stage (#24116)
  • +
  • chore: Refactor Nuget package source creation to use New-NugetPackageSource function (#24104)
  • +
  • Make Microsoft feeds the default (#24098)
  • +
  • Cleanup unused csproj (#23951)
  • +
  • Add script to update SDK version during release (#24034)
  • +
  • Enumerate over all signed zip packages (#24063)
  • +
  • Update metadata.json for PowerShell July releases (#24082)
  • +
  • Add macos signing for package files (#24015)
  • +
  • Update install-powershell.sh to support azure-linux (#23955) (Thanks @bosesubham2011!)
  • +
  • Skip build steps that do not have exe packages (#23945)
  • +
  • Update metadata.json for PowerShell June releases (#23973)
  • +
  • Create powershell.config.json for PowerShell.Windows.x64 global tool (#23941)
  • +
  • Fix error in the vPack release, debug script that blocked release (#23904)
  • +
  • Add vPack release (#23898)
  • +
  • Fix exe signing with third party signing for WiX engine (#23878)
  • +
  • Update wix installation in CI (#23870)
  • +
  • Add checkout to fix TSA config paths (#23865)
  • +
  • Merge the v7.5.0-preview.3 release branch to GitHub master branch
  • +
  • Update metadata.json for the v7.5.0-preview.3 release (#23862)
  • +
  • Bump PSResourceGet to 1.1.0-preview1 (#24129)
  • +
  • Bump github/codeql-action from 3.25.8 to 3.26.0 (#23953) (#23999) (#24053) (#24069) (#24095) (#24118)
  • +
  • Bump actions/upload-artifact from 4.3.3 to 4.3.6 (#24019) (#24113) (#24119)
  • +
  • Bump agrc/create-reminder-action from 1.1.13 to 1.1.15 (#24029) (#24043)
  • +
  • Bump agrc/reminder-action from 1.0.12 to 1.0.14 (#24028) (#24042)
  • +
  • Bump super-linter/super-linter from 5.7.2 to 6.8.0 (#23809) (#23856) (#23894) (#24030) (#24103)
  • +
  • Bump ossf/scorecard-action from 2.3.1 to 2.4.0 (#23802) (#24096)
  • +
  • Bump actions/dependency-review-action from 4.3.2 to 4.3.4 (#23897) (#24046)
  • +
  • Bump actions/checkout from 4.1.5 to 4.1.7 (#23813) (#23947)
  • +
  • Bump github/codeql-action from 3.25.4 to 3.25.8 (#23801) (#23893)
  • +
+ +
+ +### Documentation and Help Content + +- Update docs sample nuget.config (#24109) +- Update Code of Conduct and Security Policy (#23811) +- Update working-group-definitions.md for the Security WG (#23884) +- Fix up broken links in Markdown files (#23863) +- Update Engine Working Group Members (#23803) (Thanks @kilasuit!) +- Remove outdated and contradictory information from `README` (#23812) + +[7.5.0-preview.4]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-preview.3...v7.5.0-preview.4 + ## [7.5.0-preview.3] - 2024-05-16 ### Breaking Changes From 792945e63781ae6103d58367d483fd7d9efeef8b Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:36:08 -0700 Subject: [PATCH 005/275] Check `Create and Submit` in vPack build by default (#24181) (#24305) --- .pipelines/PowerShell-vPack-Official.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index b9444497614..bb780a6f203 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -6,7 +6,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time - name: 'createVPack' displayName: 'Create and Submit VPack' type: boolean - default: false + default: true - name: 'debug' displayName: 'Enable debug output' type: boolean From f0461bc00f673ac20c2531d3006813ba692e7ba1 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:36:49 -0700 Subject: [PATCH 006/275] Add windows signing for pwsh.exe (#24219) (#24306) --- .pipelines/templates/obp-file-signing.yml | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.pipelines/templates/obp-file-signing.yml b/.pipelines/templates/obp-file-signing.yml index ba761633b29..7ed973ddf5a 100644 --- a/.pipelines/templates/obp-file-signing.yml +++ b/.pipelines/templates/obp-file-signing.yml @@ -84,6 +84,31 @@ steps: files_to_sign: '**\*.psd1;**\*.psm1;**\*.ps1xml;**\*.ps1;**\*.dll;**\*.exe;**\pwsh' search_root: $(Pipeline.Workspace)/toBeSigned +- task: onebranch.pipeline.signing@1 + displayName: Sign pwsh.exe with Windows cert + inputs: + command: 'sign' + cp_code: '203' + files_to_sign: '**\pwsh.exe' + search_root: $(Pipeline.Workspace)/toBeSigned + +- pwsh: | + if (Test-Path $(Pipeline.Workspace)/toBeSigned/pwsh.exe) { + Write-Verbose -Verbose "pwsh.exe is found, verifying signature" + $signature = Get-AuthenticodeSignature -FilePath $(Pipeline.Workspace)/toBeSigned/pwsh.exe + if ($signature.SignerCertificate.Issuer -notmatch '^CN=Microsoft Windows Production.*') { + Write-Error -ErrorAction Stop "pwsh.exe is not signed by Microsoft" + } + else { + Write-Verbose -Verbose "pwsh.exe is signed by Microsoft" + } + } + else { + Write-Verbose -Verbose "pwsh.exe is not found, skipping" + } + + displayName: 'Verify windows signature' + - pwsh : | Get-ChildItem -Path env: displayName: Capture environment From a095a054b097f703a90a7d70c0d175701d7978d8 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:37:16 -0700 Subject: [PATCH 007/275] Handle global tool specially when prepending `PSHome` to `PATH` (#24228) (#24307) --- .../host/msh/ConsoleHost.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index 3a9ab8e7f45..8cc7ee00f57 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -123,11 +123,23 @@ internal static int Start( throw new ConsoleHostStartupException(ConsoleHostStrings.ShellCannotBeStartedWithConfigConflict); } - // put PSHOME in front of PATH so that calling `powershell` within `powershell` always starts the same running version + // Put PSHOME in front of PATH so that calling `pwsh` within `pwsh` always starts the same running version. string path = Environment.GetEnvironmentVariable("PATH"); - string pshome = Utils.DefaultPowerShellAppBase + Path.PathSeparator; + string pshome = Utils.DefaultPowerShellAppBase; + string dotnetToolsPathSegment = $"{Path.DirectorySeparatorChar}.store{Path.DirectorySeparatorChar}powershell{Path.DirectorySeparatorChar}"; - // to not impact startup perf, we don't remove duplicates, but we avoid adding a duplicate to the front + int index = pshome.IndexOf(dotnetToolsPathSegment, StringComparison.Ordinal); + if (index > 0) + { + // We're running PowerShell global tool. In this case the real entry executable should be the 'pwsh' + // or 'pwsh.exe' within the tool folder which should be the path right before the '\.store', not what + // PSHome is pointing to. + pshome = pshome[0..index]; + } + + pshome += Path.PathSeparator; + + // To not impact startup perf, we don't remove duplicates, but we avoid adding a duplicate to the front // we also don't handle the edge case where PATH only contains $PSHOME if (string.IsNullOrEmpty(path)) { From 068f524bfccd53d00b837bf00b4311e6593d8a3f Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:37:35 -0700 Subject: [PATCH 008/275] Use Managed Identity for APIScan authentication (#24243) (#24308) --- tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml b/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml index 585b640d48f..1b4f9067266 100644 --- a/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml +++ b/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml @@ -148,7 +148,7 @@ jobs: # write a status update every 5 minutes. Default is 1 minute statusUpdateInterval: '00:05:00' env: - AzureServicesAuthConnectionString: RunAs=App;AppId=$(APIScanClient);TenantId=$(APIScanTenant);AppKey=$(APIScanSecret) + AzureServicesAuthConnectionString: RunAs=App - task: securedevelopmentteam.vss-secure-development-tools.build-task-report.SdtReport@2 continueOnError: true From fa6f09f59a5e244cc08b8f6e67910e012b497f91 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:37:57 -0700 Subject: [PATCH 009/275] Add specific path for issues in tsaconfig (#24244) (#24309) Co-authored-by: Travis Plunk --- .config/tsaoptions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/tsaoptions.json b/.config/tsaoptions.json index bd2a6a00984..7552bd7226c 100644 --- a/.config/tsaoptions.json +++ b/.config/tsaoptions.json @@ -1,7 +1,7 @@ { "instanceUrl": "https://msazure.visualstudio.com", "projectName": "One", - "areaPath": "One\\MGMT\\Compute\\Powershell\\Powershell\\PowerShell Core", + "areaPath": "One\\MGMT\\Compute\\Powershell\\Powershell\\PowerShell Core\\pwsh", "notificationAliases": [ "adityap@microsoft.com", "dongbow@microsoft.com", From 099ed06fbf6311cf4dd3ae68e5643960a11b3f38 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:38:25 -0700 Subject: [PATCH 010/275] Make features `PSCommandNotFoundSuggestion`, `PSCommandWithArgs`, and `PSModuleAutoLoadSkipOfflineFiles` stable (#24246) (#24310) Co-authored-by: Steve Lee --- .../ExperimentalFeature.cs | 11 ------ .../engine/Modules/ModuleUtils.cs | 17 ++++----- .../FeedbackSubsystem/IFeedbackProvider.cs | 35 +++++++++---------- .../engine/hostifaces/HostUtilities.cs | 21 +++++------ 4 files changed, 31 insertions(+), 53 deletions(-) diff --git a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs index 176089d29cf..7e358e94e94 100644 --- a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs +++ b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs @@ -21,9 +21,7 @@ public class ExperimentalFeature #region Const Members internal const string EngineSource = "PSEngine"; - internal const string PSModuleAutoLoadSkipOfflineFilesFeatureName = "PSModuleAutoLoadSkipOfflineFiles"; internal const string PSFeedbackProvider = "PSFeedbackProvider"; - internal const string PSCommandWithArgs = "PSCommandWithArgs"; internal const string PSNativeWindowsTildeExpansion = nameof(PSNativeWindowsTildeExpansion); internal const string PSRedirectToVariable = "PSRedirectToVariable"; @@ -108,24 +106,15 @@ static ExperimentalFeature() name: "PSFileSystemProviderV2", description: "Replace the old FileSystemProvider with cleaner design and faster code"), */ - new ExperimentalFeature( - name: "PSCommandNotFoundSuggestion", - description: "Recommend potential commands based on fuzzy search on a CommandNotFoundException"), new ExperimentalFeature( name: "PSSubsystemPluginModel", description: "A plugin model for registering and un-registering PowerShell subsystems"), new ExperimentalFeature( name: "PSLoadAssemblyFromNativeCode", description: "Expose an API to allow assembly loading from native code"), - new ExperimentalFeature( - name: PSModuleAutoLoadSkipOfflineFilesFeatureName, - description: "Module discovery will skip over files that are marked by cloud providers as not fully on disk."), new ExperimentalFeature( name: PSFeedbackProvider, description: "Replace the hard-coded suggestion framework with the extensible feedback provider"), - new ExperimentalFeature( - name: PSCommandWithArgs, - description: "Enable `-CommandWithArgs` parameter for pwsh"), new ExperimentalFeature( name: PSNativeWindowsTildeExpansion, description: "On windows, expand unquoted tilde (`~`) with the user's current home folder."), diff --git a/src/System.Management.Automation/engine/Modules/ModuleUtils.cs b/src/System.Management.Automation/engine/Modules/ModuleUtils.cs index d8e2b24e016..f58f51dfd37 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleUtils.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleUtils.cs @@ -39,18 +39,13 @@ internal static class ModuleUtils static ModuleUtils() { - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSModuleAutoLoadSkipOfflineFilesFeatureName)) - { - FileAttributesToSkip = FileAttributes.Hidden - // Skip OneDrive files/directories that are not fully on disk. - | FileAttributes.Offline - | (FileAttributes)FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS - | (FileAttributes)FILE_ATTRIBUTE_RECALL_ON_OPEN; - - return; - } + FileAttributesToSkip = FileAttributes.Hidden + // Skip OneDrive files/directories that are not fully on disk. + | FileAttributes.Offline + | (FileAttributes)FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS + | (FileAttributes)FILE_ATTRIBUTE_RECALL_ON_OPEN; - FileAttributesToSkip = FileAttributes.Hidden; + return; } /// diff --git a/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs b/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs index 1446983f791..aba105c8faa 100644 --- a/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs +++ b/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs @@ -276,26 +276,23 @@ internal GeneralCommandErrorFeedback() } // Check fuzzy matching command names. - if (ExperimentalFeature.IsEnabled("PSCommandNotFoundSuggestion")) + var pwsh = PowerShell.Create(RunspaceMode.CurrentRunspace); + var results = pwsh.AddCommand("Get-Command") + .AddParameter("UseFuzzyMatching") + .AddParameter("FuzzyMinimumDistance", 1) + .AddParameter("Name", target) + .AddCommand("Select-Object") + .AddParameter("First", 5) + .AddParameter("Unique") + .AddParameter("ExpandProperty", "Name") + .Invoke(); + + if (results.Count > 0) { - var pwsh = PowerShell.Create(RunspaceMode.CurrentRunspace); - var results = pwsh.AddCommand("Get-Command") - .AddParameter("UseFuzzyMatching") - .AddParameter("FuzzyMinimumDistance", 1) - .AddParameter("Name", target) - .AddCommand("Select-Object") - .AddParameter("First", 5) - .AddParameter("Unique") - .AddParameter("ExpandProperty", "Name") - .Invoke(); - - if (results.Count > 0) - { - return new FeedbackItem( - SuggestionStrings.Suggestion_CommandNotFound, - new List(results), - FeedbackDisplayLayout.Landscape); - } + return new FeedbackItem( + SuggestionStrings.Suggestion_CommandNotFound, + new List(results), + FeedbackDisplayLayout.Landscape); } return null; diff --git a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs index 4398269842b..9e5612189fa 100644 --- a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs +++ b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs @@ -110,18 +110,15 @@ private static List InitializeSuggestions() enabled: true) }); - if (ExperimentalFeature.IsEnabled("PSCommandNotFoundSuggestion")) - { - suggestions.Add( - NewSuggestion( - id: 4, - category: "General", - matchType: SuggestionMatchType.ErrorId, - rule: "CommandNotFoundException", - suggestion: ScriptBlock.CreateDelayParsedScriptBlock(s_getFuzzyMatchedCommands, isProductCode: true), - suggestionArgs: new object[] { CodeGeneration.EscapeSingleQuotedStringContent(SuggestionStrings.Suggestion_CommandNotFound) }, - enabled: true)); - } + suggestions.Add( + NewSuggestion( + id: 4, + category: "General", + matchType: SuggestionMatchType.ErrorId, + rule: "CommandNotFoundException", + suggestion: ScriptBlock.CreateDelayParsedScriptBlock(s_getFuzzyMatchedCommands, isProductCode: true), + suggestionArgs: new object[] { CodeGeneration.EscapeSingleQuotedStringContent(SuggestionStrings.Suggestion_CommandNotFound) }, + enabled: true)); return suggestions; } From a82b7972f2177020a6c9de524515fa71d6ce124e Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:40:04 -0700 Subject: [PATCH 011/275] Create new pipeline for compliance (#24252) (#24312) --- .pipelines/apiscan-gen-notice.yml | 79 ++++++++ .pipelines/templates/compliance/apiscan.yml | 181 ++++++++++++++++++ .../templates/compliance/generateNotice.yml | 154 +++++++++++++++ 3 files changed, 414 insertions(+) create mode 100644 .pipelines/apiscan-gen-notice.yml create mode 100644 .pipelines/templates/compliance/apiscan.yml create mode 100644 .pipelines/templates/compliance/generateNotice.yml diff --git a/.pipelines/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml new file mode 100644 index 00000000000..02ab4ba3796 --- /dev/null +++ b/.pipelines/apiscan-gen-notice.yml @@ -0,0 +1,79 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +trigger: none + +variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + # Defines the variables AzureFileCopySubscription, StorageAccount, StorageAccountKey, StorageResourceGroup, StorageSubscriptionName + - group: 'Azure Blob variable group' + # Defines the variables CgPat, CgOrganization, and CgProject + - group: 'ComponentGovernance' + - group: 'PoolNames' + - name: LinuxContainerImage + value: onebranch.azurecr.io/linux/ubuntu-2004:latest + - name: WindowsContainerImage + value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest + +resources: + repositories: + - repository: templates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@templates + parameters: + featureFlags: + WindowsHostVersion: + Version: 2022 + globalSdl: + compiled: + enabled: true + armory: + enabled: false + sbom: + enabled: false + cg: + enabled: true + ignoreDirectories: '.devcontainer,demos,docker,docs,src,test,tools/packaging' + tsa: + enabled: true # onebranch publish all SDL results to TSA. If TSA is disabled all SDL tools will forced into 'break' build mode. + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + break: true # always break the build on binskim issues in addition to TSA upload + policheck: + break: true # always break the build on policheck issues. You can disable it by setting to 'false' + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: true + softwareName: "PowerShell" # Default is repo name + versionNumber: "7.5" # Default is build number + isLargeApp: false # Default: false. +#softwareFolder - relative path to a folder to be scanned. Default value is root of artifacts folder. +#symbolsFolder - relative path to a folder that contains symbols. Default value is root of artifacts folder. + + tsaOptionsFile: .config\tsaoptions.json + + stages: + - stage: APIScan + displayName: 'ApiScan' + dependsOn: [] + jobs: + - template: /.pipelines/templates/compliance/apiscan.yml@self + parameters: + parentJobs: [] + - stage: notice + displayName: Generate Notice File + dependsOn: [] + jobs: + - template: /.pipelines/templates/compliance/generateNotice.yml@self + parameters: + parentJobs: [] diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml new file mode 100644 index 00000000000..a96471aecd9 --- /dev/null +++ b/.pipelines/templates/compliance/apiscan.yml @@ -0,0 +1,181 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +jobs: + - job: APIScan + variables: + - name: runCodesignValidationInjection + value : false + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: ReleaseTagVar + value: fromBranch + # Defines the variables APIScanClient, APIScanTenant and APIScanSecret + - group: PS-PS-APIScan + # PAT permissions NOTE: Declare a SymbolServerPAT variable in this group with a 'microsoft' organizanization scoped PAT with 'Symbols' Read permission. + # A PAT in the wrong org will give a single Error 203. No PAT will give a single Error 401, and individual pdbs may be missing even if permissions are correct. + - group: symbols + - name: branchCounterKey + value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] + - name: branchCounter + value: $[counter(variables['branchCounterKey'], 1)] + - group: DotNetPrivateBuildAccess + - group: Azure Blob variable group + - group: ReleasePipelineSecrets + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: repoRoot + value: '$(Build.SourcesDirectory)\PowerShell' + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + + pool: + type: windows + + # APIScan can take a long time + timeoutInMinutes: 180 + + steps: + - checkout: self + clean: true + fetchTags: true + fetchDepth: 1000 + displayName: Checkout PowerShell + retryCountOnTaskFailure: 1 + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + + - template: ../SetVersionVariables.yml + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: yes + UseJson: no + + - template: ../insert-nuget-config-azfeed.yml + parameters: + repoRoot: '$(repoRoot)' + + - pwsh: | + Import-Module .\build.psm1 -force + Start-PSBootstrap + workingDirectory: '$(repoRoot)' + retryCountOnTaskFailure: 2 + displayName: 'Bootstrap' + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + + - pwsh: | + Import-Module .\build.psm1 -force + Find-DotNet + dotnet tool install dotnet-symbol --tool-path $(Agent.ToolsDirectory)\tools\dotnet-symbol + $symbolToolPath = Get-ChildItem -Path $(Agent.ToolsDirectory)\tools\dotnet-symbol\dotnet-symbol.exe | Select-Object -First 1 -ExpandProperty FullName + Write-Host "##vso[task.setvariable variable=symbolToolPath]$symbolToolPath" + displayName: Install dotnet-symbol + workingDirectory: '$(repoRoot)' + retryCountOnTaskFailure: 2 + + - pwsh: | + $modules = 'Az.Accounts', 'Az.Storage' + foreach($module in $modules) { + if(!(get-module $module -listavailable)) { + Write-Verbose "installing $module..." -verbose + Install-Module $module -force -AllowClobber + } else { + Write-Verbose "$module already installed." -verbose + } + } + displayName: Install PowerShell modules + workingDirectory: '$(repoRoot)' + + - task: AzurePowerShell@5 + displayName: Download winverify-private Artifacts + inputs: + azureSubscription: az-blob-cicd-infra + scriptType: inlineScript + azurePowerShellVersion: LatestVersion + workingDirectory: '$(repoRoot)' + pwsh: true + inline: | + # download smybols for getfilesiginforedist.dll + $downloadsDirectory = '$(Build.ArtifactStagingDirectory)/downloads' + $uploadedDirectory = '$(Build.ArtifactStagingDirectory)/uploaded' + $storageAccountName = "pscoretestdata" + $containerName = 'winverify-private' + $winverifySymbolsPath = New-Item -ItemType Directory -Path '$(System.ArtifactsDirectory)/winverify-symbols' -Force + $dllName = 'getfilesiginforedist.dll' + $winverifySymbolsDllPath = Join-Path $winverifySymbolsPath $dllName + + $context = New-AzStorageContext -StorageAccountName $storageAccountName -UseConnectedAccount + + Get-AzStorageBlobContent -Container $containerName -Blob $dllName -Destination $winverifySymbolsDllPath -Context $context + + - pwsh: | + Get-ChildItem -Path '$(System.ArtifactsDirectory)/winverify-symbols' + displayName: Capture winverify-private Artifacts + workingDirectory: '$(repoRoot)' + condition: succeededOrFailed() + + - pwsh: | + Import-Module .\build.psm1 -force + Find-DotNet + Start-PSBuild -Configuration StaticAnalysis -PSModuleRestore -Clean -Runtime fxdependent-win-desktop + + $OutputFolder = Split-Path (Get-PSOutput) + + Write-Verbose -Verbose -Message "Deleting ref folder from output folder" + if (Test-Path $OutputFolder/ref) { + Remove-Item -Recurse -Force $OutputFolder/ref + } + + Copy-Item -Path "$OutputFolder\*" -Destination '$(ob_outputDirectory)' -Recurse -Verbose + + workingDirectory: '$(repoRoot)' + displayName: 'Build PowerShell Source' + + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + workingDirectory: '$(repoRoot)' + displayName: Capture Environment + condition: succeededOrFailed() + + # Explicitly download symbols for the drop since the SDL image doesn't have http://SymWeb access and APIScan cannot handle https yet. + - pwsh: | + Import-Module .\build.psm1 -force + Find-DotNet + $pat = '$(SymbolServerPAT)' + if ($pat -like '*PAT*' -or $pat -eq '') + { + throw 'No PAT defined' + } + $url = 'https://microsoft.artifacts.visualstudio.com/defaultcollection/_apis/symbol/symsrv' + $(symbolToolPath) --authenticated-server-path $(SymbolServerPAT) $url --symbols -d "$env:ob_outputDirectory\*" --recurse-subdirectories + displayName: 'Download Symbols for binaries' + retryCountOnTaskFailure: 2 + workingDirectory: '$(repoRoot)' + + - pwsh: | + Get-ChildItem '$(ob_outputDirectory)' -File -Recurse | + Foreach-Object { + [pscustomobject]@{ + Path = $_.FullName + Version = $_.VersionInfo.FileVersion + Md5Hash = (Get-FileHash -Algorithm MD5 -Path $_.FullName).Hash + Sha512Hash = (Get-FileHash -Algorithm SHA512 -Path $_.FullName).Hash + } + } | Export-Csv -Path '$(Build.SourcesDirectory)/ReleaseFileHash.csv' + workingDirectory: '$(repoRoot)' + displayName: 'Create release file hash artifact' + + - pwsh: | + Copy-Item -Path '$(Build.SourcesDirectory)/ReleaseFileHash.csv' -Destination '$(ob_outputDirectory)' -Verbose + displayName: 'Publish Build File Hash artifact' + + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture Environment + condition: succeededOrFailed() + workingDirectory: '$(repoRoot)' diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml new file mode 100644 index 00000000000..0c1282ea8ce --- /dev/null +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -0,0 +1,154 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +parameters: + - name: parentJobs + type: jobList + +jobs: +- job: generateNotice + variables: + - name: runCodesignValidationInjection + value : false + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT/notice' + - name: ob_sdl_apiscan_enabled + value: false + - name: repoRoot + value: '$(Build.SourcesDirectory)\PowerShell' + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + + displayName: Generate Notice + dependsOn: + ${{ parameters.parentJobs }} + pool: + type: windows + + timeoutInMinutes: 15 + + steps: + - checkout: self + clean: true + + - pwsh: | + [string]$Branch=$env:BUILD_SOURCEBRANCH + $branchOnly = $Branch -replace '^refs/heads/'; + $branchOnly = $branchOnly -replace '[_\-]' + + if ($branchOnly -eq 'master') { + $container = 'tpn' + } else { + $branchOnly = $branchOnly -replace '[\./]', '-' + $container = "tpn-$branchOnly" + } + + $vstsCommandString = "vso[task.setvariable variable=tpnContainer]$container" + Write-Verbose -Message $vstsCommandString -Verbose + Write-Host -Object "##$vstsCommandString" + displayName: Set ContainerName + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + inputs: + sourceScanPath: '$(repoRoot)\tools' + + - pwsh: | + $(repoRoot)/tools/clearlyDefined/ClearlyDefined.ps1 -TestAndHarvest + displayName: Verify that packages have license data + + + - task: msospo.ospo-extension.8d7f9abb-6896-461d-9e25-4f74ed65ddb2.notice@0 + displayName: 'NOTICE File Generator' + inputs: + outputfile: '$(ob_outputDirectory)\ThirdPartyNotices.txt' + # output format can be html or text + outputformat: text + # this isn't working + # additionaldata: $(Build.SourcesDirectory)\assets\additionalAttributions.txt + + + - pwsh: | + Get-Content -Raw -Path $(repoRoot)\assets\additionalAttributions.txt | Out-File '$(ob_outputDirectory)\ThirdPartyNotices.txt' -Encoding utf8NoBOM -Force -Append + Get-Content -Raw -Path $(repoRoot)\assets\additionalAttributions.txt + displayName: Append Additional Attributions + continueOnError: true + + - pwsh: | + Get-Content -Raw -Path '$(ob_outputDirectory)\ThirdPartyNotices.txt' + displayName: Capture Notice + continueOnError: true + + - powershell: | + [System.Net.ServicePointManager]::SecurityProtocol = + [System.Net.ServicePointManager]::SecurityProtocol -bor + [System.Security.Authentication.SslProtocols]::Tls12 -bor + [System.Security.Authentication.SslProtocols]::Tls11 + + Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord + Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord + Get-PackageProvider -Name NuGet -ForceBootstrap + displayName: Initalize PowerShellGet + + - powershell: | + $modules = 'Az.Accounts', 'Az.Storage' + foreach($module in $modules) { + if(!(get-module $module -listavailable)) { + Write-Verbose "installing $module..." -verbose + Install-Module $module -force -AllowClobber + } else { + Write-Verbose "$module already installed." -verbose + #Update-Module $module -verbose + } + } + displayName: Install PowerShell modules + + - powershell: | + if(Get-Command -Name Uninstall-AzureRm -ErrorAction Ignore){ + Write-Verbose "running Uninstall-AzureRm" -verbose + Uninstall-AzureRm + } else { + Write-Verbose "Uninstall-AzureRm not present" -verbose + } + displayName: Uninstall Uninstall-AzureRm + continueOnError: true + + - task: AzurePowerShell@5 + displayName: Upload Notice + inputs: + azureSubscription: az-blob-cicd-infra + scriptType: inlineScript + azurePowerShellVersion: LatestVersion + workingDirectory: '$(repoRoot)' + pwsh: true + inline: | + try { + $downloadsDirectory = '$(Build.ArtifactStagingDirectory)/downloads' + $uploadedDirectory = '$(Build.ArtifactStagingDirectory)/uploaded' + $storageAccountName = "pscoretestdata" + $containerName = '$(tpnContainer)' + $blobName = 'ThirdPartyNotices.txt' + $noticePath = "$(ob_outputDirectory)\$blobName" + + Write-Verbose -Verbose "creating context ($storageAccountName) ..." + $context = New-AzStorageContext -StorageAccountName $storageAccountName -UseConnectedAccount + + Write-Verbose -Verbose "checking if container ($containerName) exists ..." + $containerExists = Get-AzStorageContainer -Name $containerName -Context $context -ErrorAction SilentlyContinue + if (-not $containerExists) { + Write-Verbose -Verbose "Creating container ..." + $null = New-AzStorageContainer -Name $containerName -Context $context + Write-Verbose -Verbose "Blob container $containerName created successfully." + } + + Write-Verbose -Verbose "Setting blob ($blobName) content ($noticePath) ..." + $null = Set-AzStorageBlobContent -File $noticePath -Container $containerName -Blob $blobName -Context $context -confirm:$false -force + Write-Verbose -Verbose "Done" + } catch { + Get-Error + throw + } From 1b895ef858149dfa60a3d6fc346dd2c902d99a45 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:40:19 -0700 Subject: [PATCH 012/275] Delete assets/AppImageThirdPartyNotices.txt (#24256) (#24313) --- assets/AppImageThirdPartyNotices.txt | 506 --------------------------- 1 file changed, 506 deletions(-) delete mode 100644 assets/AppImageThirdPartyNotices.txt diff --git a/assets/AppImageThirdPartyNotices.txt b/assets/AppImageThirdPartyNotices.txt deleted file mode 100644 index d492e7c3b53..00000000000 --- a/assets/AppImageThirdPartyNotices.txt +++ /dev/null @@ -1,506 +0,0 @@ -------------------------------------------- START OF THIRD PARTY NOTICE ----------------------------------------- - - This file is based on or incorporates material from the projects listed below (Third Party IP). The original copyright notice and the license under which Microsoft received such Third Party IP, are set forth below. Such licenses and notices are provided for informational purposes only. Microsoft licenses the Third Party IP to you under the licensing terms for the Microsoft product. Microsoft reserves all other rights not expressly granted under this agreement, whether by implication, estoppel or otherwise. - - - - -Copyright (c) 1991-2016 Unicode, Inc. All rights reserved. -Distributed under the Terms of Use in http://www.unicode.org/copyright.html - -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Unicode data files and any associated documentation -(the "Data Files") or Unicode software and any associated documentation -(the "Software") to deal in the Data Files or Software -without restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, and/or sell copies of -the Data Files or Software, and to permit persons to whom the Data Files -or Software are furnished to do so, provided that either -(a) this copyright and permission notice appear with all copies -of the Data Files or Software, or -(b) this copyright and permission notice appear in associated -Documentation. - -THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT OF THIRD PARTY RIGHTS. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS -NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 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 THE DATA FILES OR SOFTWARE. - -Except as contained in this notice, the name of a copyright holder -shall not be used in advertising or otherwise to promote the sale, -use or other dealings in these Data Files or Software without prior -written authorization of the copyright holder. - ---------------------- - -Third-Party Software Licenses - -This section contains third-party software notices and/or additional -terms for licensed third-party software components included within ICU -libraries. - -1. ICU License - ICU 1.8.1 to ICU 57.1 - -COPYRIGHT AND PERMISSION NOTICE - -Copyright (c) 1995-2016 International Business Machines Corporation and others -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, and/or sell copies of the Software, and to permit persons -to whom the Software is furnished to do so, provided that the above -copyright notice(s) and this permission notice appear in all copies of -the Software and that both the above copyright notice(s) and this -permission notice appear in supporting documentation. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY -SPECIAL 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. - -Except as contained in this notice, the name of a copyright holder -shall not be used in advertising or otherwise to promote the sale, use -or other dealings in this Software without prior written authorization -of the copyright holder. - -All trademarks and registered trademarks mentioned herein are the -property of their respective owners. - -2. Chinese/Japanese Word Break Dictionary Data (cjdict.txt) - - # The Google Chrome software developed by Google is licensed under - # the BSD license. Other software included in this distribution is - # provided under other licenses, as set forth below. - # - # The BSD License - # https://opensource.org/licenses/bsd-license.php - # Copyright (C) 2006-2008, Google Inc. - # - # All rights reserved. - # - # Redistribution and use 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 Google Inc. 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 "AS IS" 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. - # - # - # The word list in cjdict.txt are generated by combining three word lists - # listed below with further processing for compound word breaking. The - # frequency is generated with an iterative training against Google web - # corpora. - # - # * Libtabe (Chinese) - # - https://sourceforge.net/project/?group_id=1519 - # - Its license terms and conditions are shown below. - # - # * IPADIC (Japanese) - # - http://chasen.aist-nara.ac.jp/chasen/distribution.html - # - Its license terms and conditions are shown below. - # - # ---------COPYING.libtabe ---- BEGIN-------------------- - # - # /* - # * Copyrighy (c) 1999 TaBE Project. - # * Copyright (c) 1999 Pai-Hsiang Hsiao. - # * All rights reserved. - # * - # * Redistribution and use 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 the TaBE Project 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 - # * "AS IS" 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 - # * REGENTS 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. - # */ - # - # /* - # * Copyright (c) 1999 Computer Systems and Communication Lab, - # * Institute of Information Science, Academia - # * Sinica. All rights reserved. - # * - # * Redistribution and use 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 the Computer Systems and Communication Lab - # * 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 - # * "AS IS" 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 - # * REGENTS 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. - # */ - # - # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, - # University of Illinois - # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 - # - # ---------------COPYING.libtabe-----END-------------------------------- - # - # - # ---------------COPYING.ipadic-----BEGIN------------------------------- - # - # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science - # and Technology. All Rights Reserved. - # - # Use, reproduction, and distribution of this software is permitted. - # Any copy of this software, whether in its original form or modified, - # must include both the above copyright notice and the following - # paragraphs. - # - # Nara Institute of Science and Technology (NAIST), - # the copyright holders, disclaims all warranties with regard to this - # software, including all implied warranties of merchantability and - # fitness, in no event shall NAIST be liable for - # any special, 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 tortuous action, arising out - # of or in connection with the use or performance of this software. - # - # A large portion of the dictionary entries - # originate from ICOT Free Software. The following conditions for ICOT - # Free Software applies to the current dictionary as well. - # - # Each User may also freely distribute the Program, whether in its - # original form or modified, to any third party or parties, PROVIDED - # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear - # on, or be attached to, the Program, which is distributed substantially - # in the same form as set out herein and that such intended - # distribution, if actually made, will neither violate or otherwise - # contravene any of the laws and regulations of the countries having - # jurisdiction over the User or the intended distribution itself. - # - # NO WARRANTY - # - # The program was produced on an experimental basis in the course of the - # research and development conducted during the project and is provided - # to users as so produced on an experimental basis. Accordingly, the - # program is provided without any warranty whatsoever, whether express, - # implied, statutory or otherwise. The term "warranty" used herein - # includes, but is not limited to, any warranty of the quality, - # performance, merchantability and fitness for a particular purpose of - # the program and the nonexistence of any infringement or violation of - # any right of any third party. - # - # Each user of the program will agree and understand, and be deemed to - # have agreed and understood, that there is no warranty whatsoever for - # the program and, accordingly, the entire risk arising from or - # otherwise connected with the program is assumed by the user. - # - # Therefore, neither ICOT, the copyright holder, or any other - # organization that participated in or was otherwise related to the - # development of the program and their respective officials, directors, - # officers and other employees shall be held liable for any and all - # damages, including, without limitation, general, special, incidental - # and consequential damages, arising out of or otherwise in connection - # with the use or inability to use the program or any product, material - # or result produced or otherwise obtained by using the program, - # regardless of whether they have been advised of, or otherwise had - # knowledge of, the possibility of such damages at any time during the - # project or thereafter. Each user will be deemed to have agreed to the - # foregoing by his or her commencement of use of the program. The term - # "use" as used herein includes, but is not limited to, the use, - # modification, copying and distribution of the program and the - # production of secondary products from the program. - # - # In the case where the program, whether in its original form or - # modified, was distributed or delivered to or received by a user from - # any person, organization or entity other than ICOT, unless it makes or - # grants independently of ICOT any specific warranty to the user in - # writing, such person, organization or entity, will also be exempted - # from and not be held liable to the user for any such damages as noted - # above as far as the program is concerned. - # - # ---------------COPYING.ipadic-----END---------------------------------- - -3. Lao Word Break Dictionary Data (laodict.txt) - - # Copyright (c) 2013 International Business Machines Corporation - # and others. All Rights Reserved. - # - # Project: https://code.google.com/p/lao-dictionary/ - # Dictionary: http://lao-dictionary.googlecode.com/git/Lao-Dictionary.txt - # License: http://lao-dictionary.googlecode.com/git/Lao-Dictionary-LICENSE.txt - # (copied below) - # - # This file is derived from the above dictionary, with slight - # modifications. - # ---------------------------------------------------------------------- - # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. - # All rights reserved. - # - # Redistribution and use 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. - # - # - # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - # "AS IS" 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 HOLDER 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. - # -------------------------------------------------------------------------- - -4. Burmese Word Break Dictionary Data (burmesedict.txt) - - # Copyright (c) 2014 International Business Machines Corporation - # and others. All Rights Reserved. - # - # This list is part of a project hosted at: - # github.com/kanyawtech/myanmar-karen-word-lists - # - # -------------------------------------------------------------------------- - # Copyright (c) 2013, LeRoy Benjamin Sharon - # All rights reserved. - # - # Redistribution and use 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 Myanmar Karen Word Lists, 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 "AS IS" 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 HOLDER 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. - # -------------------------------------------------------------------------- - -5. Time Zone Database - - ICU uses the public domain data and code derived from Time Zone -Database for its time zone support. The ownership of the TZ database -is explained in BCP 175: Procedure for Maintaining the Time Zone -Database section 7. - - # 7. Database Ownership - # - # The TZ database itself is not an IETF Contribution or an IETF - # document. Rather it is a pre-existing and regularly updated work - # that is in the public domain, and is intended to remain in the - # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do - # not apply to the TZ Database or contributions that individuals make - # to it. Should any claims be made and substantiated against the TZ - # Database, the organization that is providing the IANA - # Considerations defined in this RFC, under the memorandum of - # understanding with the IETF, currently ICANN, may act in accordance - # with all competent court orders. No ownership claims will be made - # by ICANN or the IETF Trust on the database or the code. Any person - # making a contribution to the database or code waives all rights to - # future claims in that contribution or in the TZ Database. - - -8. liblzma - -XZ Utils Licensing -================== - - Different licenses apply to different files in this package. Here - is a rough summary of which licenses apply to which parts of this - package (but check the individual files to be sure!): - - - liblzma is in the public domain. - - - xz, xzdec, and lzmadec command line tools are in the public - domain unless GNU getopt_long had to be compiled and linked - in from the lib directory. The getopt_long code is under - GNU LGPLv2.1+. - - - The scripts to grep, diff, and view compressed files have been - adapted from gzip. These scripts and their documentation are - under GNU GPLv2+. - - - All the documentation in the doc directory and most of the - XZ Utils specific documentation files in other directories - are in the public domain. - - - Translated messages are in the public domain. - - - The build system contains public domain files, and files that - are under GNU GPLv2+ or GNU GPLv3+. None of these files end up - in the binaries being built. - - - Test files and test code in the tests directory, and debugging - utilities in the debug directory are in the public domain. - - - The extra directory may contain public domain files, and files - that are under various free software licenses. - - You can do whatever you want with the files that have been put into - the public domain. If you find public domain legally problematic, - take the previous sentence as a license grant. If you still find - the lack of copyright legally problematic, you have too many - lawyers. - - As usual, this software is provided "as is", without any warranty. - - If you copy significant amounts of public domain code from XZ Utils - into your project, acknowledging this somewhere in your software is - polite (especially if it is proprietary, non-free software), but - naturally it is not legally required. Here is an example of a good - notice to put into "about box" or into documentation: - - This software includes code from XZ Utils . - - The following license texts are included in the following files: - - COPYING.LGPLv2.1: GNU Lesser General Public License version 2.1 - - COPYING.GPLv2: GNU General Public License version 2 - - COPYING.GPLv3: GNU General Public License version 3 - - Note that the toolchain (compiler, linker etc.) may add some code - pieces that are copyrighted. Thus, it is possible that e.g. liblzma - binary wouldn't actually be in the public domain in its entirety - even though it contains no copyrighted code from the XZ Utils source - package. - - If you have questions, don't hesitate to ask the author(s) for more - information. - - -BSD License - -All rights reserved. - -Redistribution and use 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. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" 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 HOLDER 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. - -9. libunwind - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), 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 "AS IS", 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. - -Provided for Informational Purposes Only - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), 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 "AS IS", 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. - - - - ------------------------------------------------ END OF THIRD PARTY NOTICE ------------------------------------------ From ec222e62b1ac00bd505525c4d1827ccdf8b731c2 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:40:38 -0700 Subject: [PATCH 013/275] Delete demos directory (#24258) (#24314) --- demos/Apache/Apache/Apache.psm1 | 236 ---------------- demos/Apache/apache-demo.ps1 | 33 --- demos/Apache/readme.md | 18 -- demos/Azure/Azure-Demo.ps1 | 70 ----- demos/Azure/Compute-Linux.json | 200 ------------- demos/Azure/README.md | 11 - demos/DSC/dsc-demo.ps1 | 124 -------- demos/DSC/readme.md | 15 - demos/Docker-PowerShell/Docker-PowerShell.ps1 | 32 --- demos/README.md | 4 - demos/SystemD/SystemD/SystemD.psm1 | 21 -- demos/SystemD/journalctl-demo.ps1 | 12 - demos/SystemD/readme.md | 10 - demos/WindowsPowerShellModules/README.md | 54 ---- demos/crontab/CronTab/CronTab.ps1xml | 69 ----- demos/crontab/CronTab/CronTab.psd1 | 61 ---- demos/crontab/CronTab/CronTab.psm1 | 264 ------------------ demos/crontab/README.md | 15 - demos/crontab/crontab.ps1 | 32 --- demos/dsc.ps1 | 14 - demos/powershellget/PowerShellGet.ps1 | 80 ------ demos/powershellget/README.md | 5 - demos/python/README.md | 8 - demos/python/class1.ps1 | 14 - demos/python/class1.py | 19 -- demos/python/demo_script.ps1 | 63 ----- demos/python/inline_python.ps1 | 19 -- demos/rest/README.md | 7 - demos/rest/rest.ps1 | 45 --- 29 files changed, 1555 deletions(-) delete mode 100644 demos/Apache/Apache/Apache.psm1 delete mode 100644 demos/Apache/apache-demo.ps1 delete mode 100644 demos/Apache/readme.md delete mode 100644 demos/Azure/Azure-Demo.ps1 delete mode 100644 demos/Azure/Compute-Linux.json delete mode 100644 demos/Azure/README.md delete mode 100644 demos/DSC/dsc-demo.ps1 delete mode 100644 demos/DSC/readme.md delete mode 100644 demos/Docker-PowerShell/Docker-PowerShell.ps1 delete mode 100644 demos/README.md delete mode 100644 demos/SystemD/SystemD/SystemD.psm1 delete mode 100644 demos/SystemD/journalctl-demo.ps1 delete mode 100644 demos/SystemD/readme.md delete mode 100644 demos/WindowsPowerShellModules/README.md delete mode 100644 demos/crontab/CronTab/CronTab.ps1xml delete mode 100755 demos/crontab/CronTab/CronTab.psd1 delete mode 100644 demos/crontab/CronTab/CronTab.psm1 delete mode 100644 demos/crontab/README.md delete mode 100644 demos/crontab/crontab.ps1 delete mode 100644 demos/dsc.ps1 delete mode 100644 demos/powershellget/PowerShellGet.ps1 delete mode 100644 demos/powershellget/README.md delete mode 100644 demos/python/README.md delete mode 100644 demos/python/class1.ps1 delete mode 100755 demos/python/class1.py delete mode 100644 demos/python/demo_script.ps1 delete mode 100644 demos/python/inline_python.ps1 delete mode 100644 demos/rest/README.md delete mode 100644 demos/rest/rest.ps1 diff --git a/demos/Apache/Apache/Apache.psm1 b/demos/Apache/Apache/Apache.psm1 deleted file mode 100644 index 5f980f26bae..00000000000 --- a/demos/Apache/Apache/Apache.psm1 +++ /dev/null @@ -1,236 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -#Region utility functions - -$global:sudocmd = "sudo" - -Function GetApacheCmd{ - if (Test-Path "/usr/sbin/apache2ctl"){ - $cmd = "/usr/sbin/apache2ctl" - }elseif(Test-Path "/usr/sbin/httpd"){ - $cmd = "/usr/sbin/httpd" - }else{ - Write-Error "Unable to find httpd or apache2ctl program. Unable to continue" - exit -1 - } - $cmd -} - -Function GetApacheVHostDir{ - if (Test-Path "/etc/httpd/conf.d"){ - Return "/etc/httpd/conf.d/" - } - if (Test-Path "/etc/apache2/sites-enabled"){ - Return "/etc/apache2/sites-enabled" - } -} - -Function CleanInputString([string]$inputStr){ - $outputStr = $inputStr.Trim().Replace('`n','').Replace('\n','') - $outputStr -} - -#EndRegion utility functions - -#Region Class specifications - -Class ApacheModule{ - [string]$ModuleName - - ApacheModule([string]$aModule){ - $this.ModuleName = $aModule - } -} - -Class ApacheVirtualHost{ - [string]$ServerName - [string]$DocumentRoot - [string]$VirtualHostIPAddress = "*" - [string[]]$ServerAliases - [int]$VirtualHostPort = "80" - [string]$ServerAdmin - [string]$CustomLogPath - [string]$ErrorLogPath - [string]$ConfigurationFile - - #region class constructors - ApacheVirtualHost([string]$ServerName, [string]$ConfFile, [string]$VirtualHostIPAddress,[int]$VirtualHostPort){ - $this.ServerName = $ServerName - $this.ConfigurationFile = $ConfFile - $this.VirtualHostIPAddress = $VirtualHostIPAddress - $this.VirtualHostPort = $VirtualHostPort - } - - #Full specification - ApacheVirtualHost([string]$ServerName, [string]$DocumentRoot, [string[]]$ServerAliases, [string]$ServerAdmin, [string]$CustomLogPath, [string]$ErrorLogPath, [string]$VirtualHostIPAddress, [int]$VirtualHostPort, [string]$ConfigurationFile){ - $this.ServerName = $ServerName - $this.DocumentRoot = $DocumentRoot - $this.ServerAliases = $ServerAliases - $this.ServerAdmin = $ServerAdmin - $this.CustomLogPath = $CustomLogPath - $this.ErrorLogPath = $ErrorLogPath - $this.VirtualHostIPAddress = $VirtualHostIPAddress - $this.VirtualHostPort = $VirtualHostPort - $this.ConfigurationFile = $ConfigurationFile - } - - #Default Port and IP - #endregion - - #region class methods - Save($ConfigurationFile){ - if (!(Test-Path $this.DocumentRoot)){ New-Item -Type Directory $this.DocumentRoot } - - $VHostsDirectory = GetApacheVHostDir - if (!(Test-Path $VHostsDirectory)){ - Write-Error "Specified virtual hosts directory does not exist: $VHostsDirectory" - exit 1 - } - $VHostIPAddress = $this.VirtualHostIPAddress - [string]$VhostPort = $this.VirtualHostPort - $VHostDef = "`n" - $vHostDef += "DocumentRoot " + $this.DocumentRoot + "`n" - ForEach ($Alias in $this.ServerAliases){ - if ($Alias.trim() -ne ""){ - $vHostDef += "ServerAlias " + $Alias + "`n" - } - } - $vHostDef += "ServerName " + $this.ServerName +"`n" - if ($this.ServerAdmin.Length -gt 1){$vHostDef += "ServerAdmin " + $this.ServerAdmin +"`n"} - if ($this.CustomLogPath -like "*/*"){$vHostDef += "CustomLog " + $this.CustomLogPath +"`n"} - if ($this.ErrorLogPath -like "*/*"){$vHostDef += "ErrorLog " + $this.ErrorLogpath +"`n"} - $vHostDef += "" - $filName = $ConfigurationFile - $VhostDef | Out-File "/tmp/${filName}" -Force -Encoding:ascii - & $global:sudocmd "mv" "/tmp/${filName}" "${VhostsDirectory}/${filName}" - Write-Information "Restarting Apache HTTP Server" - Restart-ApacheHTTPServer - } - - #endregion -} - -#EndRegion Class Specifications - -Function New-ApacheVHost { - [CmdletBinding()] - param( - [parameter (Mandatory = $true)][string]$ServerName, - [parameter (Mandatory = $true)][string]$DocumentRoot, - [string]$VirtualHostIPAddress, - [string[]]$ServerAliases, - [int]$VirtualHostPort, - [string]$ServerAdmin, - [string]$CustomLogPath, - [string]$ErrorLogPath - ) - - $NewConfFile = $VHostsDirectory + "/" + $ServerName + ".conf" - if(!($VirtualHostIPAddress)){$VirtualHostIPAddress = "*"} - if(!($VirtualHostPort)){$VirtualHostPort = "80"} - $newVHost = [ApacheVirtualHost]::new("$ServerName","$DocumentRoot","$ServerAliases","$ServerAdmin","$CustomLogPath","$ErrorLogPath","$VirtualHostIPAddress",$VirtualHostPort,"$NewConfFile") - $newVHost.Save("$ServerName.conf") -} - -Function GetVHostProps([string]$ConfFile,[string]$ServerName,[string]$Listener){ - $confContents = Get-Content $ConfFile - [boolean]$Match = $false - $DocumentRoot = "" - $CustomLogPath = "" - $ErrorLogPath = "" - $ServerAdmin = "" - ForEach ($confline in $confContents){ - if ($confLine -like "*"){ - $Match = $false - } - } - } - @{"DocumentRoot" = "$DocumentRoot"; "CustomLogPath" = "$CustomLogPath"; "ErrorLogPath" = "$ErrorLogPath"; "ServerAdmin" = $ServerAdmin} - -} - -Function Get-ApacheVHost{ - $cmd = GetApacheCmd - - $Vhosts = @() - $res = & $global:sudocmd $cmd -t -D DUMP_VHOSTS - - ForEach ($line in $res){ - $ServerName = $null - if ($line -like "*:*.conf*"){ - $RMatch = $line -match "(?.*:[0-9]*)(?.*)\((?.*)\)" - $ListenAddress = $Matches.Listen.trim() - $ServerName = $Matches.ServerName.trim() - $ConfFile = $Matches.ConfFile.trim().split(":")[0].Replace('(','') - }else{ - if ($line.trim().split()[0] -like "*:*"){ - $ListenAddress = $line.trim().split()[0] - }elseif($line -like "*.conf*"){ - if ($line -like "*default*"){ - $ServerName = "_Default" - $ConfFile = $line.trim().split()[3].split(":")[0].Replace('(','') - }elseif($line -like "*namevhost*"){ - $ServerName = $line.trim().split()[3] - $ConfFile = $line.trim().split()[4].split(":")[0].Replace('(','') - } - } - } - - if ($null -ne $ServerName){ - $vHost = [ApacheVirtualHost]::New($ServerName, $ConfFile, $ListenAddress.Split(":")[0],$ListenAddress.Split(":")[1]) - $ExtProps = GetVHostProps $ConfFile $ServerName $ListenAddress - $vHost.DocumentRoot = $ExtProps.DocumentRoot - #Custom log requires additional handling. NYI - #$vHost.CustomLogPath = $ExtProps.CustomLogPath - $vHost.ErrorLogPath = $ExtProps.ErrorLogPath - $vHost.ServerAdmin = $ExtProps.ServerAdmin - $Vhosts += $vHost - } - } - - Return $Vhosts - } - -Function Restart-ApacheHTTPServer{ - [CmdletBinding()] - Param( - [switch]$Graceful - ) - - if ($null -eq $Graceful){$Graceful = $false} - $cmd = GetApacheCmd - if ($Graceful){ - & $global:sudocmd $cmd -k graceful - }else{ - & $global:sudocmd $cmd -k restart - } - -} - -Function Get-ApacheModule{ - $cmd = GetApacheCmd - - $ApacheModules = @() - - $Results = & $global:sudocmd $cmd -M |grep -v Loaded - - Foreach ($mod in $Results){ - $modInst = [ApacheModule]::new($mod.trim()) - $ApacheModules += ($modInst) - } - - $ApacheModules - -} diff --git a/demos/Apache/apache-demo.ps1 b/demos/Apache/apache-demo.ps1 deleted file mode 100644 index 299ce0cc0de..00000000000 --- a/demos/Apache/apache-demo.ps1 +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module $PSScriptRoot/Apache/Apache.psm1 - -#list Apache Modules -Write-Host -Foreground Blue "Get installed Apache Modules like *proxy* and Sort by name" -Get-ApacheModule | Where-Object {$_.ModuleName -like "*proxy*"} | Sort-Object ModuleName | Out-Host - -#Graceful restart of Apache -Write-Host -Foreground Blue "Restart Apache Server gracefully" -Restart-ApacheHTTPServer -Graceful | Out-Host - -#Enumerate current virtual hosts (web sites) -Write-Host -Foreground Blue "Enumerate configured Apache Virtual Hosts" -Get-ApacheVHost |Out-Host - -#Add a new virtual host -Write-Host -Foreground Yellow "Create a new Apache Virtual Host" -New-ApacheVHost -ServerName "mytestserver" -DocumentRoot /var/www/html/mytestserver -VirtualHostIPAddress * -VirtualHostPort 8090 | Out-Host - -#Enumerate new set of virtual hosts -Write-Host -Foreground Blue "Enumerate Apache Virtual Hosts Again" -Get-ApacheVHost |Out-Host - -#Cleanup -Write-Host -Foreground Blue "Remove demo virtual host" -if (Test-Path "/etc/httpd/conf.d"){ - & sudo rm "/etc/httpd/conf.d/mytestserver.conf" -} -if (Test-Path "/etc/apache2/sites-enabled"){ - & sudo rm "/etc/apache2/sites-enabled/mytestserver.conf" -} diff --git a/demos/Apache/readme.md b/demos/Apache/readme.md deleted file mode 100644 index 30e36b3811a..00000000000 --- a/demos/Apache/readme.md +++ /dev/null @@ -1,18 +0,0 @@ -## Apache Management Demo - -This demo shows management of Apache HTTP Server with PowerShell cmdlets implemented in a script module. - -- **Get-ApacheVHost**: Enumerate configured Apache Virtual Host (website) instances as objects. -- **Get-ApacheModule**: Enumerate loaded Apache modules -- **Restart-ApacheHTTPserver**: Restart the Apache web server -- **New-ApacheVHost**: Create a new Apache Virtual Host (website) based on supplied parameters - - -## Prerequisites ## -- Install PowerShell -- Install Apache packages - - `sudo apt-get install apache2` - - `sudo yum install httpd` - - -Note: Management of Apache requires privileges. The user must have authorization to elevate with sudo. You will be prompted for a sudo password when running the demo. \ No newline at end of file diff --git a/demos/Azure/Azure-Demo.ps1 b/demos/Azure/Azure-Demo.ps1 deleted file mode 100644 index 22b316686a7..00000000000 --- a/demos/Azure/Azure-Demo.ps1 +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -### The techniques used in this demo are documented at -### https://azure.microsoft.com/documentation/articles/powershell-azure-resource-manager/ - -### Import AzureRM.Profile.NetCore.Preview and AzureRM.Resources.NetCore.Preview modules. -### AzureRM.NetCore.Preview is a wrapper module that pulls in these modules -### -### Because of issue https://github.com/PowerShell/PowerShell/issues/1618, -### currently you will not be able to use "Install-Module AzureRM.NetCore.Preview" from -### PowerShellGallery. You can use the following workaround until the issue is fixed: -### -### Install-Package -Name AzureRM.NetCore.Preview -Source https://www.powershellgallery.com/api/v2 -ProviderName NuGet -ExcludeVersion -Destination -### -### Ensure $env:PSModulePath is updated with the location you used to install. -Import-Module AzureRM.NetCore.Preview - -### Supply your Azure Credentials -Login-AzureRmAccount - -### Specify a name for Azure Resource Group -$resourceGroupName = "PSAzDemo" + (New-Guid | ForEach-Object guid) -replace "-","" -$resourceGroupName - -### Create a new Azure Resource Group -New-AzureRmResourceGroup -Name $resourceGroupName -Location "West US" - -### Deploy an Ubuntu 14.04 VM using Resource Manager cmdlets -### Template is available at -### http://armviz.io/#/?load=https:%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2F101-vm-simple-linux%2Fazuredeploy.json -$dnsLabelPrefix = $resourceGroupName | ForEach-Object tolower -$dnsLabelPrefix - -#[SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Demo/doc secret.")] -$password = ConvertTo-SecureString -String "PowerShellRocks!" -AsPlainText -Force -New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile ./Compute-Linux.json -adminUserName psuser -adminPassword $password -dnsLabelPrefix $dnsLabelPrefix - -### Monitor the status of the deployment -Get-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName - -### Discover the resources we created by the previous deployment -Find-AzureRmResource -ResourceGroupName $resourceGroupName | Select-Object Name,ResourceType,Location - -### Get the state of the VM we created -### Notice: The VM is in running state -Get-AzureRmResource -ResourceName MyUbuntuVM -ResourceType Microsoft.Compute/virtualMachines -ResourceGroupName $resourceGroupName -ODataQuery '$expand=instanceView' | ForEach-Object properties | ForEach-Object instanceview | ForEach-Object statuses - -### Discover the operations we can perform on the compute resource -### Notice: Operations like "Power Off Virtual Machine", "Start Virtual Machine", "Create Snapshot", "Delete Snapshot", "Delete Virtual Machine" -Get-AzureRmProviderOperation -OperationSearchString Microsoft.Compute/* | Select-Object OperationName,Operation - -### Power Off the Virtual Machine we created -Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroupName -ResourceType Microsoft.Compute/virtualMachines -ResourceName MyUbuntuVM -Action poweroff - -### Check the VM state again. It should be stopped now. -Get-AzureRmResource -ResourceName MyUbuntuVM -ResourceType Microsoft.Compute/virtualMachines -ResourceGroupName $resourceGroupName -ODataQuery '$expand=instanceView' | ForEach-Object properties | ForEach-Object instanceview | ForEach-Object statuses - -### As you know, you may still be incurring charges even if the VM is in stopped state -### Deallocate the resource to avoid this charge -Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroupName -ResourceType Microsoft.Compute/virtualMachines -ResourceName MyUbuntuVM -Action deallocate - -### The following command removes the Virtual Machine -Remove-AzureRmResource -ResourceName MyUbuntuVM -ResourceType Microsoft.Compute/virtualMachines -ResourceGroupName $resourceGroupName - -### Look at the resources that still exists -Find-AzureRmResource -ResourceGroupName $resourceGroupName | Select-Object Name,ResourceType,Location - -### Remove the resource group and its resources -Remove-AzureRmResourceGroup -Name $resourceGroupName diff --git a/demos/Azure/Compute-Linux.json b/demos/Azure/Compute-Linux.json deleted file mode 100644 index a0e9e27b85e..00000000000 --- a/demos/Azure/Compute-Linux.json +++ /dev/null @@ -1,200 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "adminUsername": { - "type": "string", - "metadata": { - "description": "User name for the Virtual Machine." - } - }, - "adminPassword": { - "type": "securestring", - "metadata": { - "description": "Password for the Virtual Machine." - } - }, - "dnsLabelPrefix": { - "type": "string", - "metadata": { - "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." - } - }, - "ubuntuOSVersion": { - "type": "string", - "defaultValue": "14.04.2-LTS", - "allowedValues": [ - "12.04.5-LTS", - "14.04.2-LTS", - "15.10", - "16.04.0-LTS" - ], - "metadata": { - "description": "The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version. Allowed values: 12.04.5-LTS, 14.04.2-LTS, 15.10, 16.04.0-LTS." - } - } - }, - "variables": { - "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'salinuxvm')]", - "dataDisk1VhdName": "datadisk1", - "imagePublisher": "Canonical", - "imageOffer": "UbuntuServer", - "OSDiskName": "osdiskforlinuxsimple", - "nicName": "myVMNic", - "addressPrefix": "10.0.0.0/16", - "subnetName": "Subnet", - "subnetPrefix": "10.0.0.0/24", - "storageAccountType": "Standard_LRS", - "publicIPAddressName": "myPublicIP", - "publicIPAddressType": "Dynamic", - "vmStorageAccountContainerName": "vhds", - "vmName": "MyUbuntuVM", - "vmSize": "Standard_D1", - "virtualNetworkName": "MyVNET", - "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "apiVersion": "2015-06-15" - }, - "resources": [ - { - "type": "Microsoft.Storage/storageAccounts", - "name": "[variables('storageAccountName')]", - "apiVersion": "2016-01-01", - "location": "[resourceGroup().location]", - "sku": { - "name": "[variables('storageAccountType')]" - }, - "kind": "Storage", - "properties": {} - }, - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Network/publicIPAddresses", - "name": "[variables('publicIPAddressName')]", - "location": "[resourceGroup().location]", - "properties": { - "publicIPAllocationMethod": "[variables('publicIPAddressType')]", - "dnsSettings": { - "domainNameLabel": "[parameters('dnsLabelPrefix')]" - } - } - }, - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Network/virtualNetworks", - "name": "[variables('virtualNetworkName')]", - "location": "[resourceGroup().location]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetPrefix')]" - } - } - ] - } - }, - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Network/networkInterfaces", - "name": "[variables('nicName')]", - "location": "[resourceGroup().location]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - } - }, - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Compute/virtualMachines", - "name": "[variables('vmName')]", - "location": "[resourceGroup().location]", - "dependsOn": [ - "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", - "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" - ], - "properties": { - "hardwareProfile": { - "vmSize": "[variables('vmSize')]" - }, - "osProfile": { - "computerName": "[variables('vmName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]" - }, - "storageProfile": { - "imageReference": { - "publisher": "[variables('imagePublisher')]", - "offer": "[variables('imageOffer')]", - "sku": "[parameters('ubuntuOSVersion')]", - "version": "latest" - }, - "osDisk": { - "name": "osdisk", - "vhd": { - "uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')), variables('apiVersion')).primaryEndpoints.blob, variables('vmStorageAccountContainerName'),'/',variables('OSDiskName'),'.vhd')]" - }, - "caching": "ReadWrite", - "createOption": "FromImage" - }, - "dataDisks": [ - { - "name": "datadisk1", - "diskSizeGB": "100", - "lun": 0, - "vhd": { - "uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')), variables('apiVersion')).primaryEndpoints.blob, variables('vmStorageAccountContainerName'),'/',variables('dataDisk1VhdName'),'.vhd')]" - }, - "createOption": "Empty" - } - ] - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]" - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": "true", - "storageUri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')), variables('apiVersion')).primaryEndpoints.blob)]" - } - } - } - } - ], - "outputs": { - "hostname": { - "type": "string", - "value": "[concat(parameters('dnsLabelPrefix'), '.', resourceGroup().location, '.cloudapp.azure.com')]" - }, - "sshCommand": { - "type": "string", - "value": "[concat('ssh ', parameters('adminUsername'), '@', parameters('dnsLabelPrefix'), '.', resourceGroup().location, '.cloudapp.azure.com')]" - } - } -} diff --git a/demos/Azure/README.md b/demos/Azure/README.md deleted file mode 100644 index d2c8155f6f4..00000000000 --- a/demos/Azure/README.md +++ /dev/null @@ -1,11 +0,0 @@ -## Demo: Managing Azure using PowerShell - -This demo (Azure-Demo.ps1) shows management of Azure Compute resource using Azure Resource Management (ARM) cmdlets. - -## Prerequisites ## -- Install the latest PowerShell Core. -- Install AzureRM.NetCore.Preview, AzureRM.Profile.NetCore.Preview and AzureRM.Resources.NetCore.Preview modules to a local directory. - - The instructions for downloading these modules are in Azure-Demo.ps1 file. - - You have to use the command "Install-Package -Name AzureRM.NetCore.Preview -Source https://www.powershellgallery.com/api/v2 -ProviderName NuGet -ExcludeVersion -Destination " - - diff --git a/demos/DSC/dsc-demo.ps1 b/demos/DSC/dsc-demo.ps1 deleted file mode 100644 index 3abd642a3b4..00000000000 --- a/demos/DSC/dsc-demo.ps1 +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -#Get Distro type and set distro-specific variables -$OSname = Get-Content "/etc/os-release" |Select-String -Pattern "^Name=" -$OSName = $OSName.tostring().split("=")[1].Replace('"','') -if ($OSName -like "Ubuntu*"){ - $distro = "Ubuntu" - $ApachePackages = @("apache2","php5","libapache2-mod-php5") - $ServiceName = "apache2" - $VHostDir = "/etc/apache2/sites-enabled" - $PackageManager = "apt" -}elseif (($OSName -like "CentOS*") -or ($OSName -like "Red Hat*") -or ($OSname -like "Oracle*")){ - $distro = "Fedora" - $ApachePackages = @("httpd","mod_ssl","php","php-mysql") - $ServiceName = "httpd" - $VHostDir = "/etc/httpd/conf.d" - $PackageManager = "yum" -}else{ - Write-Error "Unknown Linux operating system. Cannot continue." -} - -#Get Service Controller -if ((Test-Path "/bin/systemctl") -or (Test-Path "/usr/bin/systemctl")){ - $ServiceCtl = "SystemD" -}else{ - $ServiceCtl = "init" -} - -#Get FQDN -$hostname = & hostname --fqdn - -Write-Host -ForegroundColor Blue "Compile a DSC MOF for the Apache Server configuration" -Configuration ApacheServer{ - Node localhost{ - - ForEach ($Package in $ApachePackages){ - nxPackage $Package{ - Ensure = "Present" - Name = $Package - PackageManager = $PackageManager - } - } - - nxFile vHostDirectory{ - DestinationPath = $VhostDir - Type = "Directory" - Ensure = "Present" - Owner = "root" - Mode = "744" - } - - #Ensure default content does not exist - nxFile DefVHost{ - DestinationPath = "${VhostDir}/000-default.conf" - Ensure = "Absent" - } - - nxFile Welcome.conf{ - DestinationPath = "${VhostDir}/welcome.conf" - Ensure = "Absent" - } - - nxFile UserDir.conf{ - DestinationPath = "${VhostDir}/userdir.conf" - Ensure = "Absent" - } - - #Ensure website is defined - nxFile DefaultSiteDir{ - DestinationPath = "/var/www/html/defaultsite" - Type = "Directory" - Owner = "root" - Mode = "744" - Ensure = "Present" - } - - nxFile DefaultSite.conf{ - Destinationpath = "${VhostDir}/defaultsite.conf" - Owner = "root" - Mode = "744" - Ensure = "Present" - Contents = @" - -DocumentRoot /var/www/html/defaultsite -ServerName $hostname - - -"@ - DependsOn = "[nxFile]DefaultSiteDir" - } - - nxFile TestPhp{ - DestinationPath = "/var/www/html/defaultsite/test.php" - Ensure = "Present" - Owner = "root" - Mode = "744" - Contents = @' - - -'@ - } - - #Configure Apache Service - nxService ApacheService{ - Name = "$ServiceName" - Enabled = $true - State = "running" - Controller = $ServiceCtl - DependsOn = "[nxFile]DefaultSite.conf" - } - - } -} - -ApacheServer -OutputPath "/tmp" - -Pause -Write-Host -ForegroundColor Blue "Apply the configuration locally" -& sudo /opt/microsoft/dsc/Scripts/StartDscConfiguration.py -configurationmof /tmp/localhost.mof | Out-Host - -Pause -Write-Host -ForegroundColor Blue "Get the current configuration" -& sudo /opt/microsoft/dsc/Scripts/GetDscConfiguration.py | Out-Host diff --git a/demos/DSC/readme.md b/demos/DSC/readme.md deleted file mode 100644 index 3a13cc6f2fe..00000000000 --- a/demos/DSC/readme.md +++ /dev/null @@ -1,15 +0,0 @@ -# DSC MOF Compilation Demo - -[PowerShell Desired State Configuration](https://learn.microsoft.com/powershell/dsc/overview) is a declarative configuration platform for Windows and Linux. -DSC configurations can be authored in PowerShell and compiled into the resultant MOF document. - -This demo shows use of PowerShell to author a DSC configuration to set the configuration of an Apache web server. PowerShell scripting is used to assess distribution and version-specific properties, -such as the service controller and repo manager tools, for use in the configuration. - -## Prerequisites - -- PowerShell >= 6.0.0-alpha.8 [https://github.com/PowerShell/PowerShell/releases](https://github.com/PowerShell/PowerShell/releases) -- OMI: >= 1.1.0 [https://www.github.com/microsoft/omi/releases](https://www.github.com/microsoft/omi/releases) -- Desired State Configuration for Linux >= 1.1.1-278 [https://github.com/Microsoft/PowerShell-DSC-for-Linux/releases](https://github.com/Microsoft/PowerShell-DSC-for-Linux/releases) - -> Note: applying the DSC configuration requires privileges. The user must have sudo authorization capabilities. You will be prompted for a sudo password when running the demo. diff --git a/demos/Docker-PowerShell/Docker-PowerShell.ps1 b/demos/Docker-PowerShell/Docker-PowerShell.ps1 deleted file mode 100644 index 18eb844fd32..00000000000 --- a/demos/Docker-PowerShell/Docker-PowerShell.ps1 +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# This is a short example of the Docker-PowerShell module. The same cmdlets may be used to manage both local & remote machines, including both Windows & Linux hosts -# The only difference between them is the example container image is pulled & run. - -# Import the Docker module -# It's available at https://github.com/Microsoft/Docker-PowerShell -Import-Module Docker - -# Pull the 'hello-world' image from Docker Hub -Pull-ContainerImage hello-world # Linux -# Pull-ContainerImage patricklang/hello-world # Windows - -# Now run it -Run-ContainerImage hello-world # Linux -# Run-ContainerImage patricklang/hello-world # Windows - -# Make some room on the screen -cls - -# List all containers that have exited -Get-Container | Where-Object State -EQ "exited" - -# That found the right one, so go ahead and remove it -Get-Container | Where-Object State -EQ "exited" | Remove-Container - -# Now remove the container image -Remove-ContainerImage hello-world - -# And list the container images left on the container host -Get-ContainerImage diff --git a/demos/README.md b/demos/README.md deleted file mode 100644 index 53882c047c6..00000000000 --- a/demos/README.md +++ /dev/null @@ -1,4 +0,0 @@ -This folder contains demos primarily targeted for Linux systems. -Each demo showcases how to use PowerShell to be more productive by -leveraging objects and how it can integrate with existing Linux -scripts and/or commands. diff --git a/demos/SystemD/SystemD/SystemD.psm1 b/demos/SystemD/SystemD/SystemD.psm1 deleted file mode 100644 index d1bf0d8e890..00000000000 --- a/demos/SystemD/SystemD/SystemD.psm1 +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Function Get-SystemDJournal { - [CmdletBinding()] - param ( - [Alias("args")][string]$journalctlParameters - ) - $sudocmd = "sudo" - $cmd = "journalctl" - $Result = & $sudocmd $cmd $journalctlParameters -o json --no-pager - Try - { - $JSONResult = $Result|ConvertFrom-Json - $JSONResult - } - Catch - { - $Result - } -} diff --git a/demos/SystemD/journalctl-demo.ps1 b/demos/SystemD/journalctl-demo.ps1 deleted file mode 100644 index 2597bdc3b66..00000000000 --- a/demos/SystemD/journalctl-demo.ps1 +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module $PSScriptRoot/SystemD/SystemD.psm1 - -#list recent journal events -Write-Host -Foreground Blue "Get recent SystemD journal messages" -Get-SystemDJournal -args "-xe" |Out-Host - -#Drill into SystemD unit messages -Write-Host -Foreground Blue "Get recent SystemD journal messages for services and return Unit, Message" -Get-SystemDJournal -args "-xe" | Where-Object {$_._SYSTEMD_UNIT -like "*.service"} | Format-Table _SYSTEMD_UNIT, MESSAGE | Select-Object -First 10 | Out-Host diff --git a/demos/SystemD/readme.md b/demos/SystemD/readme.md deleted file mode 100644 index 87580efbae3..00000000000 --- a/demos/SystemD/readme.md +++ /dev/null @@ -1,10 +0,0 @@ -## SystemD: journalctl demo - -This demo shows use of a PowerShell script module to wrap a native tool (journalctl) so that the output is structured for filtering and presentation control. `journalctl` is expressed as a cmdlet: Get-SystemDJournal, and the JSON output of journalctl is converted to a PowerShell object. - -## Prerequisites ## -- Requires a SystemD-based operating system (Red Hat or CentOS 7, Ubuntu 16.04) -- Install PowerShell - - -Note: Accessing the SystemD journal requires privileges. The user must have authorization to elevate with sudo. You will be prompted for a sudo password when running the demo. \ No newline at end of file diff --git a/demos/WindowsPowerShellModules/README.md b/demos/WindowsPowerShellModules/README.md deleted file mode 100644 index 3cf63bd947e..00000000000 --- a/demos/WindowsPowerShellModules/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# Using Windows PowerShell modules with PowerShell Core - -## Windows PowerShell vs PowerShell Core - -Existing Windows PowerShell users are familiar with the large number of modules available, however, they are not necessarily compatible with PowerShell Core. -More information regarding compatibility is in a [blog post](https://devblogs.microsoft.com/powershell/powershell-6-0-roadmap-coreclr-backwards-compatibility-and-more/). - -Windows PowerShell 5.1 is based on .Net Framework 4.6.1, while PowerShell Core is based on .Net Core 2.x. -Although both adhere to .Net Standard 2.0 and can be compatible, some modules may be using APIs or cmdlets not supported on CoreCLR or using APIs from Windows PowerShell that have been deprecated and removed from PowerShell Core (for example, PSSnapins). - -## Importing a Windows PowerShell module - -Since compatibility cannot be ensured, PowerShell Core, by default, does not look in the Windows PowerShell module path to find those modules. -However, advanced users can explicitly enable PowerShell Core to include the Windows PowerShell module path and attempt to import those modules. - -First, install the [WindowsPSModulePath](https://www.powershellgallery.com/packages/WindowsPSModulePath) module from the PowerShellGallery: - -```powershell -Install-Module WindowsPSModulePath -Scope CurrentUser -``` - -Then run `Add-WindowsPSModulePath` cmdlet to add the Windows PowerShell module path to your PowerShell Core module path: - -```powershell -Add-WindowsPSModulePath -``` - -Note that this is only effective in the current PowerShell session. -If you want to persist this, you can add `Add-WindowsPSModulePath` to your profile: - -```powershell -"Add-WindowsPSModulePath" >> $profile -``` - -Once the module path has been updated, you can list available modules: - -```powershell -Get-Module -ListAvailable -``` - -Note that PowerShell Core is not aware which Windows PowerShell modules will work and which will not so all are listed. -We plan to improve this experience in the future. -You can now import a Windows PowerShell module or just execute a known cmdlet and allow auto-module loading to take care of importing the module: - -```powershell -Get-VM -# this will automatically load the Hyper-V module -``` - -Most of the cmdlets based on CDXML will work just fine, as well as some C# based cmdlets that happen to be .NET Standard 2.0 compatible (for example, Hyper-V module) but the Active Directory module, for example, won't work. - -## How you can help - -Provide comments on Windows PowerShell modules that work or don't work in our [tracking issue](https://github.com/PowerShell/PowerShell/issues/4062). diff --git a/demos/crontab/CronTab/CronTab.ps1xml b/demos/crontab/CronTab/CronTab.ps1xml deleted file mode 100644 index 4246b1f62af..00000000000 --- a/demos/crontab/CronTab/CronTab.ps1xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - Default - - CronJob - - - - - - 10 - Left - - - - 10 - Left - - - - 10 - Left - - - - 10 - Left - - - - 10 - Left - - - - Left - - - - - - - Minute - - - Hour - - - DayOfMonth - - - Month - - - DayOfWeek - - - Command - - - - - - - - \ No newline at end of file diff --git a/demos/crontab/CronTab/CronTab.psd1 b/demos/crontab/CronTab/CronTab.psd1 deleted file mode 100755 index aabc48e572e..00000000000 --- a/demos/crontab/CronTab/CronTab.psd1 +++ /dev/null @@ -1,61 +0,0 @@ -@{ - -# Script module or binary module file associated with this manifest. -RootModule = 'CronTab.psm1' - -# Version number of this module. -ModuleVersion = '0.1.0.0' - -# Supported PSEditions -CompatiblePSEditions = @('Core') - -# ID used to uniquely identify this module -GUID = '508bb97f-de2e-482e-aae2-01caec0be8c7' - -# Author of this module -Author = 'PowerShell' - -# Company or vendor of this module -CompanyName = 'Microsoft Corporation' - -# Copyright statement for this module -Copyright = 'Copyright (c) Microsoft Corporation.' - -# Description of the functionality provided by this module -Description = 'Sample module for managing CronTab' - -# Format files (.ps1xml) to be loaded when importing this module -FormatsToProcess = 'CronTab.ps1xml' - -# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = 'New-CronJob','Remove-CronJob','Get-CronJob','Get-CronTabUser' - -# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. -PrivateData = @{ - - PSData = @{ - - # Tags applied to this module. These help with module discovery in online galleries. - # Tags = @() - - # A URL to the license for this module. - # LicenseUri = '' - - # A URL to the main website for this project. - # ProjectUri = '' - - # A URL to an icon representing this module. - # IconUri = '' - - # ReleaseNotes of this module - # ReleaseNotes = '' - - } # End of PSData hashtable - -} # End of PrivateData hashtable - -# HelpInfo URI of this module -# HelpInfoURI = '' - -} - diff --git a/demos/crontab/CronTab/CronTab.psm1 b/demos/crontab/CronTab/CronTab.psm1 deleted file mode 100644 index 4cb88e586b9..00000000000 --- a/demos/crontab/CronTab/CronTab.psm1 +++ /dev/null @@ -1,264 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -using namespace System.Collections.Generic -using namespace System.Management.Automation - -$crontabcmd = "/usr/bin/crontab" - -class CronJob { - [string] $Minute - [string] $Hour - [string] $DayOfMonth - [string] $Month - [string] $DayOfWeek - [string] $Command - - [string] ToString() - { - return "{0} {1} {2} {3} {4} {5}" -f - $this.Minute, $this.Hour, $this.DayOfMonth, $this.Month, $this.DayOfWeek, $this.Command - } -} - -# Internal helper functions - -function Get-CronTab ([String] $user) { - $crontab = Invoke-CronTab -user $user -arguments "-l" -noThrow - if ($crontab -is [ErrorRecord]) { - if ($crontab.Exception.Message.StartsWith("no crontab for ")) { - $crontab = @() - } - else { - throw $crontab.Exception - } - } - [string[]] $crontab -} - -function ConvertTo-CronJob ([String] $crontab) { - $split = $crontab -split " ", 6 - $cronjob = [CronJob]@{ - Minute = $split[0]; - Hour = $split[1]; - DayOfMonth= $split[2]; - Month =$split[3]; - DayOfWeek = $split[4]; - Command = $split[5] - } - $cronjob -} - -function Invoke-CronTab ([String] $user, [String[]] $arguments, [Switch] $noThrow) { - If ($user -ne [String]::Empty) { - $arguments = Write-Output "-u" $UserName $arguments - } - - Write-Verbose "Running: $crontabcmd $arguments" - $output = & $crontabcmd @arguments 2>&1 - if ($LASTEXITCODE -ne 0 -and -not $noThrow) { - $e = New-Object System.InvalidOperationException -ArgumentList $output.Exception.Message - throw $e - } else { - $output - } -} - -function Import-CronTab ([String] $user, [String[]] $crontab) { - $temp = New-TemporaryFile - [String]::Join([Environment]::NewLine,$crontab) | Set-Content $temp.FullName - Invoke-CronTab -user $user $temp.FullName - Remove-Item $temp -} - -# Public functions - -function Remove-CronJob { -<# -.SYNOPSIS - Removes the exactly matching cron job from the cron table - -.DESCRIPTION - Removes the exactly matching cron job from the cron table - -.EXAMPLE - Get-CronJob | Where-Object {%_.Command -like 'foo *'} | Remove-CronJob - -.RETURNVALUE - None - -.PARAMETER UserName - Optional parameter to specify a specific user's cron table - -.PARAMETER Job - Cron job object returned from Get-CronJob - -.PARAMETER Force - Don't prompt when removing the cron job -#> - [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact="High")] - param ( - [ArgumentCompleter( { $wordToComplete = $args[2]; Get-CronTabUser | Where-Object { $_ -like "$wordToComplete*" } | Sort-Object } )] - [Alias("u")] - [Parameter(Mandatory=$false)] - [String] - $UserName, - - [Alias("j")] - [Parameter(Mandatory=$true,ValueFromPipeline=$true)] - [CronJob] - $Job, - - [Switch] - $Force - ) - process { - - [string[]] $crontab = Get-CronTab -user $UserName - $newcrontab = [List[string]]::new() - $found = $false - - $JobAsString = $Job.ToString() - foreach ($line in $crontab) { - if ($JobAsString -ceq $line) { - $found = $true - } else { - $newcrontab.Add($line) - } - } - - if (-not $found) { - $e = New-Object System.Exception -ArgumentList "Job not found" - throw $e - } - if ($Force -or $PSCmdlet.ShouldProcess($Job.Command,"Remove")) { - Import-CronTab -user $UserName -crontab $newcrontab - } - } -} - -function New-CronJob { -<# -.SYNOPSIS - Create a new cron job -.DESCRIPTION - Create a new job in the cron table. Date and time parameters can be specified - as ranges such as 10-30, as a list: 5,6,7, or combined 1-5,10-15. An asterisk - means 'first through last' (the entire allowed range). Step values can be used - with ranges or with an asterisk. Every 2 hours can be specified as either - 0-23/2 or */2. -.EXAMPLE - New-CronJob -Minute 10-30 -Hour 10-20/2 -DayOfMonth */2 -Command "/bin/bash -c 'echo hello' > ~/hello" - -.RETURNVALUE - If successful, an object representing the cron job is returned - -.PARAMETER UserName - Optional parameter to specify a specific user's cron table - -.PARAMETER Minute - Valid values are 0 to 59. If not specified, defaults to *. - -.PARAMETER Hour - Valid values are 0-23. If not specified, defaults to *. - -.PARAMETER DayOfMonth - Valid values are 1-31. If not specified, defaults to *. - -.PARAMETER Month - Valid values are 1-12. If not specified, defaults to *. - -.PARAMETER DayOfWeek - Valid values are 0-7. 0 and 7 are both Sunday. If not specified, defaults to *. - -.PARAMETER Command - Command to execute at the scheduled time and day. -#> - [CmdletBinding()] - param ( - [ArgumentCompleter( { $wordToComplete = $args[2]; Get-CronTabUser | Where-Object { $_ -like "$wordToComplete*" } | Sort-Object } )] - [Alias("u")] - [Parameter(Mandatory=$false)] - [String] - $UserName, - - [Alias("mi")][Parameter(Position=1)][String[]] $Minute = "*", - [Alias("h")][Parameter(Position=2)][String[]] $Hour = "*", - [Alias("dm")][Parameter(Position=3)][String[]] $DayOfMonth = "*", - [Alias("mo")][Parameter(Position=4)][String[]] $Month = "*", - [Alias("dw")][Parameter(Position=5)][String[]] $DayOfWeek = "*", - [Alias("c")][Parameter(Mandatory=$true,Position=6)][String] $Command - ) - process { - # TODO: validate parameters, note that different versions of crontab support different capabilities - $line = "{0} {1} {2} {3} {4} {5}" -f [String]::Join(",",$Minute), [String]::Join(",",$Hour), - [String]::Join(",",$DayOfMonth), [String]::Join(",",$Month), [String]::Join(",",$DayOfWeek), $Command - [string[]] $crontab = Get-CronTab -user $UserName - $crontab += $line - Import-CronTab -User $UserName -crontab $crontab - ConvertTo-CronJob -crontab $line - } -} - -function Get-CronJob { -<# -.SYNOPSIS - Returns the current cron jobs from the cron table - -.DESCRIPTION - Returns the current cron jobs from the cron table - -.EXAMPLE - Get-CronJob -UserName Steve - -.RETURNVALUE - CronJob objects - -.PARAMETER UserName - Optional parameter to specify a specific user's cron table -#> - [CmdletBinding()] - [OutputType([CronJob])] - param ( - [Alias("u")][Parameter(Mandatory=$false)][String] $UserName - ) - process { - $crontab = Get-CronTab -user $UserName - ForEach ($line in $crontab) { - if ($line.Trim().Length -gt 0) - { - ConvertTo-CronJob -crontab $line - } - } - } -} - -function Get-CronTabUser { -<# -.SYNOPSIS - Returns the users allowed to use crontab -#> - [CmdletBinding()] - [OutputType([String])] - param() - - $allow = '/etc/cron.allow' - if (Test-Path $allow) - { - Get-Content $allow - } - else - { - $users = Get-Content /etc/passwd | ForEach-Object { ($_ -split ':')[0] } - $deny = '/etc/cron.deny' - if (Test-Path $deny) - { - $denyUsers = Get-Content $deny - $users | Where-Object { $denyUsers -notcontains $_ } - } - else - { - $users - } - } -} diff --git a/demos/crontab/README.md b/demos/crontab/README.md deleted file mode 100644 index bdfb16dbb06..00000000000 --- a/demos/crontab/README.md +++ /dev/null @@ -1,15 +0,0 @@ -## CronTab demo - -This demo shows examining, creating, and removing cron jobs via crontab. - -Output of Get-CronJob is a strongly typed object with properties like DayOfWeek or Command. -Remove-CronJob prompts before removing the job unless you specify -Force. - -Tab completion of -UserName is supported, e.g. - -Get-CronJob -u - -NYI: no way to run crontab with sudo if necessary -NYI: ignoring shell variables or comments -NYI: New-CronJob -Description "..." (save in comments" -NYI: @reboot,@daily,@hourly,etc diff --git a/demos/crontab/crontab.ps1 b/demos/crontab/crontab.ps1 deleted file mode 100644 index 3d0ee0741ea..00000000000 --- a/demos/crontab/crontab.ps1 +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module $PSScriptRoot/CronTab/CronTab.psd1 - -Write-Host -Foreground Yellow "Get the existing cron jobs" -Get-CronJob | Out-Host - -Write-Host -Foreground Yellow "New cron job to clean out tmp every day at 1am" -New-CronJob -Command 'rm -rf /tmp/*; #demo' -Hour 1 | Out-Host - -Write-Host -Foreground Yellow "Add some more jobs" -New-CronJob -Command 'python -c ~/scripts/backup_users; #demo' -Hour 2 -DayOfWeek 1-5 | Out-Host -New-CronJob -Command 'powershell -c "cd ~/src/PowerShell; ipmo ./build.psm1; Start-PSBuild"; #demo' -Hour 2 -DayOfWeek * | Out-Host - -Write-Host -Foreground Yellow "Show in bash that the new cron job exists" -crontab -l - -Write-Host -Foreground Yellow "Get jobs that run every day" -Get-CronJob | Where-Object { $_.DayOfWeek -eq '*' -or $_.DayOfWeek -eq '1-7' } | Out-Host - -Write-Host -Foreground Yellow "Remove one cron job, with prompting to confirm" -Get-CronJob | Where-Object { $_.Command -match '^powershell.*' } | Remove-CronJob | Out-Host - -Write-Host -Foreground Yellow "And the other job remains" -Get-CronJob | Out-Host - -Write-Host -Foreground Yellow "Remove remaining demo jobs without prompting" -Get-CronJob | Where-Object { $_.Command -match '#demo'} | Remove-CronJob -Force - -Write-Host -Foreground Yellow "Show in bash that cron should be clean" -crontab -l diff --git a/demos/dsc.ps1 b/demos/dsc.ps1 deleted file mode 100644 index c59be643edc..00000000000 --- a/demos/dsc.ps1 +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# DSC MOF Compilation -# DSC Configuration() script that: -# Defines base configuration users, groups, settings -# Uses PS function to set package configuration (ensure=Present) for an array of packages -# Probes for the existence of a package (Apache or MySQL) and conditionally configures the workload. I.e., if Apache is installed, configure Apache settings - -# Demo execution: -# Show the .ps1 -# Run the .ps1 to generate a MOF -# Apply the MOF locally with Start-DSCConfiguration -# Show the newly configured state diff --git a/demos/powershellget/PowerShellGet.ps1 b/demos/powershellget/PowerShellGet.ps1 deleted file mode 100644 index e93216851da..00000000000 --- a/demos/powershellget/PowerShellGet.ps1 +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -#region find, install, update, uninstall the PowerShell scripts from an online repository. -# Value: equivalent of pypi - -# List of PowerShellGet commands -Get-Command -Module PowerShellGet - -# Discover PowerShell Scripts -Find-Script -Find-Script -Name Start-Demo - -# Save scripts to a specified location -Save-Script Start-Demo -Repository PSGallery -Path /tmp -Get-ChildItem -Path /tmp/Start-Demo.ps1 - -# Install a script to the common scripts location -Find-Script -Name Start-Demo -Repository PSGallery | Install-Script -Get-InstalledScript - -# Install another script to show the update functionality -Install-Script Fabrikam-Script -RequiredVersion 1.0 -Get-InstalledScript -Get-InstalledScript Fabrikam-Script | Format-List * - -# Update the installed scripts -Update-Script -WhatIf -Update-Script -Get-InstalledScript - -# Uninstall a script file -Uninstall-Script Fabrikam-Script -Verbose - -#endregion - -#region Using PowerShellGet find and install modules - -# Value: equivalent of pypi -# Look for all the modules we'll be demoing today -Find-Module -Tag 'PowerShellCore_Demo' - -# Save module to specified location -Save-Module -Tag 'PowerShellCore_Demo' -Path /tmp - -# Pipe this to Install-Module to install them -Find-Module -Tag 'PowerShellCore_Demo' | Install-Module -Verbose -Get-InstalledModule - -# Update all installed modules -Update-Module - -#endregion - -#region Using PowerShellGet with tags - -# Look for all the scripts we'll be demoing today -Find-Script -Tag 'PowerShellCore_Demo' - -# Pipe this to Install-Script to install them -Find-Script -Tag 'PowerShellCore_Demo' | Install-Script -Verbose -Get-InstalledScript - -#endregion - -#region Working with PowerShellGet repositories - -# List available PS repositories -Get-PSRepository - -# Register a new private feed -Register-PSRepository -Name "myPrivateGallery" –SourceLocation "https://www.myget.org/F/powershellgetdemo/api/v2" -InstallationPolicy Trusted - -# Change the trust level for a repositories -Set-PSRepository -Name "myPrivateGallery" -InstallationPolicy "Untrusted" - -# Remove a private feed -Unregister-PSRepository -Name "myPrivateGallery" - -#endregion diff --git a/demos/powershellget/README.md b/demos/powershellget/README.md deleted file mode 100644 index f225610169b..00000000000 --- a/demos/powershellget/README.md +++ /dev/null @@ -1,5 +0,0 @@ -## PowerShellGet demo - -PowerShellGet is a PowerShell module with the commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, DSC Resources, Role Capabilities and Scripts. - -This demo shows discovering, installing, updating, uninstalling the PowerShell scripts from an online repository. diff --git a/demos/python/README.md b/demos/python/README.md deleted file mode 100644 index d2d1486e2fe..00000000000 --- a/demos/python/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# PowerShell/Python Interoperation Demo - -The `demo_script.ps1` file in this directory walks through a -demonstration of basic interoperation between PowerShell and Python -including how to use JSON to exchange structured objects between -Python and PowerShell. - -The other files in this directory are referenced by `demo_script.ps1`. diff --git a/demos/python/class1.ps1 b/demos/python/class1.ps1 deleted file mode 100644 index b74c0c8d5d6..00000000000 --- a/demos/python/class1.ps1 +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# -# Wrap Python script in such a way to make it easy to -# consume from PowerShell -# -# The variable $PSScriptRoot points to the directory -# from which the script was executed. This allows -# picking up the Python script from the same directory -# - -& $PSScriptRoot/class1.py | ConvertFrom-Json - diff --git a/demos/python/class1.py b/demos/python/class1.py deleted file mode 100755 index ad923449455..00000000000 --- a/demos/python/class1.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/python3 - -import json - -# Define a class with a method that returns JSON -class returnsjson: - def __init__(self): - the_object = self - def method1(self): - return json.dumps(['foo', - { - 'bar': ('baz', None, 1.0, 2), - 'buz': ('foo1', 'foo2', 'foo3') - }, - 'alpha', - 1,2,3]) - -c = returnsjson() -print(c.method1()) diff --git a/demos/python/demo_script.ps1 b/demos/python/demo_script.ps1 deleted file mode 100644 index af2067642a1..00000000000 --- a/demos/python/demo_script.ps1 +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# -# Demo simple interoperation between PowerShell and Python - -# Basic execution of a Python script fragment -python -c "print('Hi!')" - -# Capture output in a variable -$data = python -c "print('Hi!')" - -# And show the data -$data - -# Use in expressions -5 + (python -c "print(2 + 3)") + 7 - -# Create a Python script using a PowerShell here-string, no extension -@" -#!/usr/bin/python3 -print('Hi!') -"@ | Out-File -Encoding ascii hi - -# Make it executable -chmod +x hi - -# Run it - shows that PowerShell really is a shell -./hi - -# A more complex script that outputs JSON -cat class1.py - -# Run the script -./class1.py - -# Capture the data as structured objects (arrays and hashtables) -$data = ./class1.py | ConvertFrom-Json - -# look at the first element of the returned array -$data[0] - -# Look at the second -$data[1] - -# Get a specific element from the data -$data[1].buz[1] - -# Finally wrap it all up so it looks like a simple PowerShell command -cat class1.ps1 - -# And run it, treating the output as structured data. -(./class1)[1].buz[1] - -# Finally a PowerShell script with in-line Python -cat inline_python.ps1 - -# and run it -./inline_python - -#################################### -# cleanup -rm hi diff --git a/demos/python/inline_python.ps1 b/demos/python/inline_python.ps1 deleted file mode 100644 index 71b65215f74..00000000000 --- a/demos/python/inline_python.ps1 +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# -# An example showing inline Python code in a PowerShell script -# - -"Hello from PowerShell!" - -# Inline Python code in a "here string" which allows for a multi-line script -python3 -c @" -print(' Hello from Python!') -print(' Python and PowerShell get along great!') -"@ - -# Back to PowerShell... -"Back to PowerShell." -"Bye now!" - diff --git a/demos/rest/README.md b/demos/rest/README.md deleted file mode 100644 index 03bb103889e..00000000000 --- a/demos/rest/README.md +++ /dev/null @@ -1,7 +0,0 @@ -## REST demo - -This demo shows how to interact with the GitHub API using the Invoke-WebRequest cmdlet. - -rest.ps1: -Invoke-WebRequest and ConvertFrom-Json cmdlets are used to get the issues of a repo. -The issues are processed as objects to find the most commented on issues. diff --git a/demos/rest/rest.ps1 b/demos/rest/rest.ps1 deleted file mode 100644 index f40b49b6538..00000000000 --- a/demos/rest/rest.ps1 +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -#----------------- - -function Get-Issue -{ - param([string]$UserName, - [string]$Repo, - [ValidateRange(1,100)][int]$PerPage = 100) - - $body = @{ - per_page = $PerPage - } - - $uri = "https://api.github.com/repos/$UserName/$Repo/issues" - while ($uri) - { - $response = Invoke-WebRequest -Uri $uri -Body $body - $response.Content | ConvertFrom-Json | Write-Output - - $uri = $null - foreach ($link in $response.Headers.Link -split ',') - { - if ($link -match '\s*<(.*)>;\s+rel="next"') - { - $uri = $Matches[1] - } - } - } -} - -$issues = Get-Issue -UserName lzybkr -Repo PSReadline - -$issues.Count - -$issues | Sort-Object -Descending comments | Select-Object -First 15 | ft number,comments,title - -foreach ($issue in $issues) -{ - if ($issue.labels.name -contains 'bug' -and $issue.labels.name -contains 'vi mode') - { - "{0} is a vi mode bug" -f $issue.url - } -} From ea39b567a5d8aeb190fdb87f97bc7c998023fed9 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:40:59 -0700 Subject: [PATCH 014/275] Do not build the exe for Global tool shim project (#24263) (#24315) --- build.psm1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build.psm1 b/build.psm1 index 36f958bab84..dd815da872a 100644 --- a/build.psm1 +++ b/build.psm1 @@ -587,6 +587,13 @@ Fix steps: try { Push-Location $globalToolSrcFolder + + if ($Options.Runtime -like 'fxdependent*') { + if ($Arguments -contains '/property:UseAppHost=true') { + $Arguments = @($Arguments | Where-Object { $_ -notlike '/property:UseAppHost=true' }) + } + } + if ($Arguments -notcontains '--output') { $Arguments += "--output", $publishPath } From 95850df6e9cbe1690990f9763545823256a2a39a Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:42:16 -0700 Subject: [PATCH 015/275] Fix how processor architecture is validated in `Import-Module` (#24265) (#24317) --- .../engine/Modules/ModuleCmdletBase.cs | 10 ++++++---- .../Import-Module.Tests.ps1 | 12 ++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 3bbb9126fac..00b02368270 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -16,6 +16,7 @@ using System.Management.Automation.Runspaces; using System.Management.Automation.Security; using System.Reflection; +using System.Runtime.InteropServices; using System.Text; using System.Xml; using System.Diagnostics; @@ -1920,11 +1921,12 @@ internal PSModuleInfo LoadModuleManifest( else if ((requiredProcessorArchitecture != ProcessorArchitecture.None) && (requiredProcessorArchitecture != ProcessorArchitecture.MSIL)) { - #pragma warning disable SYSLIB0037 - ProcessorArchitecture currentArchitecture = typeof(object).Assembly.GetName().ProcessorArchitecture; - #pragma warning restore SYSLIB0037 + Architecture currentArchitecture = RuntimeInformation.ProcessArchitecture; - if (currentArchitecture != requiredProcessorArchitecture) + if ((requiredProcessorArchitecture == ProcessorArchitecture.X86 && currentArchitecture != Architecture.X86) || + (requiredProcessorArchitecture == ProcessorArchitecture.Amd64 && currentArchitecture != Architecture.X64) || + (requiredProcessorArchitecture == ProcessorArchitecture.Arm && (currentArchitecture != Architecture.Arm && currentArchitecture != Architecture.Arm64)) || + requiredProcessorArchitecture == ProcessorArchitecture.IA64) { containedErrors = true; if (writingErrors) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 index d7216720dd7..6885abe847d 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 @@ -56,6 +56,18 @@ Describe "Import-Module" -Tags "CI" { Import-Module TestModule -RequiredVersion 1.1 (Get-Module TestModule).Version | Should -BeIn "1.1" } + + It 'ProcessorArchitecture should work' { + $currentProcessorArchitecture = switch ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture) { + 'X86' { 'x86' } + 'X64' { 'amd64' } + 'Arm64' { 'arm' } + default { throw "Unknown processor architecture" } + } + New-ModuleManifest -Path "$TestDrive\TestModule.psd1" -ProcessorArchitecture $currentProcessorArchitecture + $module = Import-Module -Name "$TestDrive\TestModule.psd1" -PassThru + $module.ProcessorArchitecture | Should -Be $currentProcessorArchitecture + } } Describe "Import-Module with ScriptsToProcess" -Tags "CI" { From ca88d3c4a722e5c16804ff8ce22650ecf65ae650 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:42:42 -0700 Subject: [PATCH 016/275] Make some release tests run in a hosted pools (#24270) (#24318) Co-authored-by: Travis Plunk --- .pipelines/PowerShell-Release-Official.yml | 10 ++-- .pipelines/templates/release-validate-sdk.yml | 46 +++++++++++-------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 223517f2e96..eb21b407ba7 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -51,6 +51,7 @@ variables: value: mcr.microsoft.com/onebranch/cbl-mariner/build:2.0 - name: ReleaseTagVar value: ${{ parameters.ReleaseTagVar }} + - group: PoolNames resources: repositories: @@ -111,19 +112,22 @@ extends: parameters: jobName: "windowsSDK" displayName: "Windows SDK Validation" - jobtype: windows + imageName: PSMMS2019-Secure + poolName: $(windowsPool) - template: /.pipelines/templates/release-validate-sdk.yml@self parameters: jobName: "MacOSSDK" displayName: "MacOS SDK Validation" - jobtype: macos + imageName: macOS-latest + poolName: Azure Pipelines - template: /.pipelines/templates/release-validate-sdk.yml@self parameters: jobName: "LinuxSDK" displayName: "Linux SDK Validation" - jobtype: linux + imageName: PSMMSUbuntu20.04-Secure + poolName: $(ubuntuPool) - stage: gbltool displayName: 'Validate Global tools' diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index 3cd5425478e..f626051b543 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -1,34 +1,36 @@ parameters: jobName: "" displayName: "" - jobtype: "windows" + poolName: "windows" + imageName: 'none' jobs: - job: ${{ parameters.jobName }} displayName: ${{ parameters.displayName }} pool: - ${{ if eq(parameters.jobtype, 'macos') }}: - type: linux - isCustom: true - name: Azure Pipelines - vmImage: 'macOS-latest' + type: linux + isCustom: true + ${{ if eq( parameters.poolName, 'Azure Pipelines') }}: + name: ${{ parameters.poolName }} + vmImage: ${{ parameters.imageName }} ${{ else }}: - type: ${{ parameters.jobtype }} + name: ${{ parameters.poolName }} + demands: + - ImageOverride -equals ${{ parameters.imageName }} variables: - group: mscodehub-feed-read-general - group: mscodehub-feed-read-akv - group: DotNetPrivateBuildAccess - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json steps: - checkout: self clean: true + lfs: false + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: "$(Build.SourcesDirectory)" - template: release-SetReleaseTagandContainerName.yml@self @@ -45,7 +47,7 @@ jobs: displayName: 'Capture Downloaded Artifacts' - pwsh: | - $repoRoot = $isMacOS ? "$(Build.SourcesDirectory)" : "$(Build.SourcesDirectory)/PowerShell" + $repoRoot = "$(Build.SourcesDirectory)" $dotnetMetadataPath = "$repoRoot/DotnetRuntimeMetadata.json" $dotnetMetadataJson = Get-Content $dotnetMetadataPath -Raw | ConvertFrom-Json @@ -80,7 +82,7 @@ jobs: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - pwsh: | - $repoRoot = $isMacOS ? "$(Build.SourcesDirectory)" : "$(Build.SourcesDirectory)/PowerShell" + $repoRoot = "$(Build.SourcesDirectory)" $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 Import-Module "$repoRoot/build.psm1" -Force @@ -102,12 +104,17 @@ jobs: Get-ChildItem ## register the packages download directory in the nuget file - # $nugetConfigContent = Get-Content ./NuGet.Config -Raw - # $updateNugetContent = $nugetConfigContent.Replace("", $xmlElement) + $nugetPath = './NuGet.Config' + if(!(test-path $nugetPath)) { + $nugetPath = "$repoRoot/nuget.config" + } + Write-Verbose -Verbose "nugetPath: $nugetPath" + $nugetConfigContent = Get-Content $nugetPath -Raw + $updateNugetContent = $nugetConfigContent.Replace("", $xmlElement) - # $updateNugetContent | Out-File ./NuGet.Config -Encoding ascii + $updateNugetContent | Out-File $nugetPath -Encoding ascii - # Get-Content ./NuGet.Config + Get-Content $nugetPath # Add workaround to unblock xUnit testing see issue: https://github.com/dotnet/sdk/issues/26462 $dotnetPath = if ($IsWindows) { "$env:LocalAppData\Microsoft\dotnet" } else { "$env:HOME/.dotnet" } @@ -116,7 +123,6 @@ jobs: dotnet --info dotnet restore dotnet test /property:RELEASE_VERSION=$releaseVersion --test-adapter-path:. "--logger:xunit;LogFilePath=$(System.DefaultWorkingDirectory)/test-hosting.xml" - displayName: Restore and execute tests env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) From 77422389593a3363805a36af807d5a958ab9c3b5 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:43:08 -0700 Subject: [PATCH 017/275] Update experimental-feature json files (#24271) (#24319) --- experimental-feature-linux.json | 7 ++----- experimental-feature-windows.json | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/experimental-feature-linux.json b/experimental-feature-linux.json index b5af1955d29..f97b56b6013 100644 --- a/experimental-feature-linux.json +++ b/experimental-feature-linux.json @@ -1,10 +1,7 @@ [ - "PSCommandNotFoundSuggestion", - "PSCommandWithArgs", "PSFeedbackProvider", "PSLoadAssemblyFromNativeCode", - "PSModuleAutoLoadSkipOfflineFiles", "PSNativeWindowsTildeExpansion", - "PSSubsystemPluginModel", - "PSRedirectToVariable" + "PSRedirectToVariable", + "PSSubsystemPluginModel" ] diff --git a/experimental-feature-windows.json b/experimental-feature-windows.json index b5af1955d29..f97b56b6013 100644 --- a/experimental-feature-windows.json +++ b/experimental-feature-windows.json @@ -1,10 +1,7 @@ [ - "PSCommandNotFoundSuggestion", - "PSCommandWithArgs", "PSFeedbackProvider", "PSLoadAssemblyFromNativeCode", - "PSModuleAutoLoadSkipOfflineFiles", "PSNativeWindowsTildeExpansion", - "PSSubsystemPluginModel", - "PSRedirectToVariable" + "PSRedirectToVariable", + "PSSubsystemPluginModel" ] From f484c607d277bfecc11552f03029eca96799709f Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 12:43:27 -0700 Subject: [PATCH 018/275] Bump .NET 9 to `9.0.100-rc.1.24452.12` (#24273) (#24320) --- global.json | 2 +- ...rosoft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...crosoft.PowerShell.Commands.Management.csproj | 2 +- .../cimSupport/cmdletization/cim/cimConverter.cs | 2 ++ .../Microsoft.PowerShell.Commands.Utility.csproj | 4 ++-- .../Microsoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 8 ++++---- .../security/CertificateCommands.cs | 3 +++ .../Microsoft.WSMan.Management.csproj | 2 +- .../System.Management.Automation.csproj | 16 ++++++++-------- .../engine/serialization.cs | 2 ++ .../security/SecuritySupport.cs | 9 +++++++-- test/powershell/Host/Startup.Tests.ps1 | 1 + test/tools/TestService/TestService.csproj | 4 ++-- test/tools/WebListener/Program.cs | 12 ++++++++++++ test/tools/WebListener/WebListener.csproj | 4 ++-- 16 files changed, 50 insertions(+), 25 deletions(-) diff --git a/global.json b/global.json index de9b44d3e3b..0519736ab95 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.100-preview.6.24328.19" + "version": "9.0.100-rc.1.24452.12" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index a438fa73e0d..9f36b8134d1 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index cfa5ea247dc..695ed6f21e4 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs index 5522049a48f..17a085b7ce5 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs @@ -425,7 +425,9 @@ internal static object ConvertFromCimToDotNet(object cimObject, Type expectedDot var cimIntrinsicValue = (byte[])LanguagePrimitives.ConvertTo(cimObject, typeof(byte[]), CultureInfo.InvariantCulture); return exceptionSafeReturn(delegate { + #pragma warning disable SYSLIB0057 return new X509Certificate2(cimIntrinsicValue); + #pragma warning restore SYSLIB0057 }); } diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 9dd33935fc2..113d62231f0 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -33,8 +33,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 4271ef37843..1296b1e28ba 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 4bc37fa3d11..34c462edbd4 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -21,9 +21,9 @@ - - - + + + - + diff --git a/src/Microsoft.PowerShell.Security/security/CertificateCommands.cs b/src/Microsoft.PowerShell.Security/security/CertificateCommands.cs index 4d65d628ad3..e3a386ee507 100644 --- a/src/Microsoft.PowerShell.Security/security/CertificateCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/CertificateCommands.cs @@ -208,8 +208,11 @@ protected override void ProcessRecord() private static X509Certificate2 GetCertFromPfxFile(string path, SecureString password) { + // No overload found in X509CertificateLoader that takes SecureString + #pragma warning disable SYSLIB0057 var cert = new X509Certificate2(path, password, X509KeyStorageFlags.DefaultKeySet); return cert; + #pragma warning restore SYSLIB0057 } } } diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 382b7c63913..9a8f4973d1a 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 3319c928fa2..e4b0c5d7e48 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -34,16 +34,16 @@ - - - - + + + + - + - - - + + + diff --git a/src/System.Management.Automation/engine/serialization.cs b/src/System.Management.Automation/engine/serialization.cs index 244e83d6af9..9e2fe5db58a 100644 --- a/src/System.Management.Automation/engine/serialization.cs +++ b/src/System.Management.Automation/engine/serialization.cs @@ -7292,7 +7292,9 @@ internal static PSSenderInfo RehydratePSSenderInfo(PSObject pso) private static System.Security.Cryptography.X509Certificates.X509Certificate2 RehydrateX509Certificate2(PSObject pso) { byte[] rawData = GetPropertyValue(pso, "RawData"); + #pragma warning disable SYSLIB0057 return new System.Security.Cryptography.X509Certificates.X509Certificate2(rawData); + #pragma warning restore SYSLIB0057 } private static System.Security.Cryptography.X509Certificates.X500DistinguishedName RehydrateX500DistinguishedName(PSObject pso) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 2089c2217ed..0c563eb46b3 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -1104,7 +1104,10 @@ private void ResolveFromBase64Encoding(ResolutionPurpose purpose, out ErrorRecor var certificatesToProcess = new X509Certificate2Collection(); try { + #pragma warning disable SYSLIB0057 X509Certificate2 newCertificate = new X509Certificate2(messageBytes); + #pragma warning restore SYSLIB0057 + certificatesToProcess.Add(newCertificate); } catch (Exception) @@ -1182,7 +1185,9 @@ private void ResolveFromPath(SessionState sessionState, ResolutionPurpose purpos try { + #pragma warning disable SYSLIB0057 certificate = new X509Certificate2(path); + #pragma warning restore SYSLIB0057 } catch (Exception) { @@ -1337,7 +1342,7 @@ internal static class AmsiUtils static AmsiUtils() { #if !UNIX - try + try { s_amsiInitFailed = !CheckAmsiInit(); } @@ -1347,7 +1352,7 @@ static AmsiUtils() s_amsiInitFailed = true; return; } - + PSEtwLog.LogAmsiUtilStateEvent($"init-{s_amsiInitFailed}", $"{s_amsiContext}-{s_amsiSession}"); #endif } diff --git a/test/powershell/Host/Startup.Tests.ps1 b/test/powershell/Host/Startup.Tests.ps1 index 2845e79cccd..35c22fefe58 100644 --- a/test/powershell/Host/Startup.Tests.ps1 +++ b/test/powershell/Host/Startup.Tests.ps1 @@ -71,6 +71,7 @@ Describe "Validate start of console host" -Tag CI { } else { $allowedAssemblies += @( + 'System.Diagnostics.DiagnosticSource.dll' 'System.Net.Sockets.dll' ) } diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 38deb50c615..f6ca75e1dae 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,8 +15,8 @@ - - + + diff --git a/test/tools/WebListener/Program.cs b/test/tools/WebListener/Program.cs index a2d49a45fc5..500e1c7062c 100644 --- a/test/tools/WebListener/Program.cs +++ b/test/tools/WebListener/Program.cs @@ -44,7 +44,10 @@ public static IWebHost BuildWebHost(string[] args) => int.Parse(args[3]), listenOptions => { + #pragma warning disable SYSLIB0057 var certificate = new X509Certificate2(args[0], args[1]); + #pragma warning restore SYSLIB0057 + HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); httpsOption.SslProtocols = SslProtocols.Tls12; httpsOption.ClientCertificateMode = ClientCertificateMode.AllowCertificate; @@ -60,7 +63,10 @@ public static IWebHost BuildWebHost(string[] args) => int.Parse(args[4]), listenOptions => { + #pragma warning disable SYSLIB0057 var certificate = new X509Certificate2(args[0], args[1]); + #pragma warning restore SYSLIB0057 + HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); // TLS 1.1 is obsolete. Using this value now defaults to TLS 1.2. @@ -79,7 +85,10 @@ public static IWebHost BuildWebHost(string[] args) => int.Parse(args[5]), listenOptions => { + #pragma warning disable SYSLIB0057 var certificate = new X509Certificate2(args[0], args[1]); + #pragma warning restore SYSLIB0057 + HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); // TLS is obsolete. Using this value now defaults to TLS 1.2. @@ -98,7 +107,10 @@ public static IWebHost BuildWebHost(string[] args) => int.Parse(args[6]), listenOptions => { + #pragma warning disable SYSLIB0057 var certificate = new X509Certificate2(args[0], args[1]); + #pragma warning restore SYSLIB0057 + HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); httpsOption.SslProtocols = SslProtocols.Tls13; httpsOption.ClientCertificateMode = ClientCertificateMode.AllowCertificate; diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index c6cd9d4c6eb..791be2fd228 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,7 +7,7 @@ - - + + From fd4e71b1fac68d667bc40967ecfaa05d4cf33eeb Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 14:48:06 -0700 Subject: [PATCH 019/275] Update and add new NuGet package sources for different environments. (#24264) (#24316) --- build.psm1 | 2 ++ test/tools/Modules/nuget.config | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/build.psm1 b/build.psm1 index dd815da872a..2d038367713 100644 --- a/build.psm1 +++ b/build.psm1 @@ -767,11 +767,13 @@ function Switch-PSNugetConfig { New-NugetConfigFile -NugetPackageSource $nugetorg, $dotnetSdk -Destination "$PSScriptRoot/" @extraParams New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/src/Modules/" @extraParams + New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/test/tools/Modules/" @extraParams } elseif ( $Source -eq 'Private') { $powerShellPackages = [NugetPackageSource] @{Url = 'https://pkgs.dev.azure.com/powershell/PowerShell/_packaging/PowerShell-7-5-preview-test-2/nuget/v3/index.json'; Name = 'powershell' } New-NugetConfigFile -NugetPackageSource $powerShellPackages -Destination "$PSScriptRoot/" @extraParams New-NugetConfigFile -NugetPackageSource $powerShellPackages -Destination "$PSScriptRoot/src/Modules/" @extraParams + New-NugetConfigFile -NugetPackageSource $powerShellPackages -Destination "$PSScriptRoot/test/tools/Modules/" @extraParams } else { throw "Unknown source: $Source" } diff --git a/test/tools/Modules/nuget.config b/test/tools/Modules/nuget.config index b0fc73009da..3ca2bee3c18 100644 --- a/test/tools/Modules/nuget.config +++ b/test/tools/Modules/nuget.config @@ -2,7 +2,7 @@ - + From 7d1ab31ce256ca5598845b4b50753b3cc1d4ec96 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 14:54:42 -0700 Subject: [PATCH 020/275] Add mapping to `AzureLinux` repo (#24290) (#24322) Co-authored-by: Anam Navied --- tools/packages.microsoft.com/mapping.json | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tools/packages.microsoft.com/mapping.json b/tools/packages.microsoft.com/mapping.json index d0be6c8e93f..b904aa9d63b 100644 --- a/tools/packages.microsoft.com/mapping.json +++ b/tools/packages.microsoft.com/mapping.json @@ -53,6 +53,38 @@ "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.x86_64.rpm", "channel": "preview" }, + { + "url": "azurelinux-3.0-prod-ms-oss-aarch64", + "distribution": [ + "bionic" + ], + "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.aarch64.rpm", + "channel": "stable" + }, + { + "url": "azurelinux-3.0-prod-ms-oss-x86_64", + "distribution": [ + "bionic" + ], + "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.x86_64.rpm", + "channel": "stable" + }, + { + "url": "azurelinux-3.0-preview-ms-oss-aarch64", + "distribution": [ + "bionic" + ], + "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.aarch64.rpm", + "channel": "preview" + }, + { + "url": "azurelinux-3.0-preview-ms-oss-x86_64", + "distribution": [ + "bionic" + ], + "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.x86_64.rpm", + "channel": "preview" + }, { "url": "microsoft-debian-stretch-prod", "distribution": [ From 4ac60c954831bd7fb8809f94f9036e5b4c2df24c Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 14:55:20 -0700 Subject: [PATCH 021/275] Add updated `libicu` dependency for Debian packages (#24301) (#24324) --- tools/packages.microsoft.com/mapping.json | 7 +++++++ tools/packaging/packaging.psm1 | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/packages.microsoft.com/mapping.json b/tools/packages.microsoft.com/mapping.json index b904aa9d63b..b3753722a59 100644 --- a/tools/packages.microsoft.com/mapping.json +++ b/tools/packages.microsoft.com/mapping.json @@ -120,6 +120,13 @@ ], "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" }, + { + "url": "microsoft-ubuntu-noble-prod", + "distribution": [ + "noble" + ], + "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" + }, { "url": "microsoft-ubuntu-xenial-prod", "distribution": [ diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index c12974a6880..1c3686591f0 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1598,7 +1598,7 @@ function Get-PackageDependencies "libgssapi-krb5-2", "libstdc++6", "zlib1g", - "libicu72|libicu71|libicu70|libicu69|libicu68|libicu67|libicu66|libicu65|libicu63|libicu60|libicu57|libicu55|libicu52", + "libicu74|libicu72|libicu71|libicu70|libicu69|libicu68|libicu67|libicu66|libicu65|libicu63|libicu60|libicu57|libicu55|libicu52", "libssl3|libssl1.1|libssl1.0.2|libssl1.0.0" ) From 8ff65501a4eefef3972e8da64b090c8877f6eee2 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 14:55:44 -0700 Subject: [PATCH 022/275] Treat large Enum values as numbers in `ConvertTo-Json` (#20999) (#24304) --- experimental-feature-linux.json | 1 + experimental-feature-windows.json | 1 + .../commands/utility/WebCmdlet/JsonObject.cs | 2 +- .../ExperimentalFeature.cs | 5 +++ ....PSSerializeJSONLongEnumAsNumber.Tests.ps1 | 34 +++++++++++++++++ .../Json.Tests.ps1 | 38 ++++++++++--------- test/tools/TestMetadata.json | 3 +- 7 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.PSSerializeJSONLongEnumAsNumber.Tests.ps1 diff --git a/experimental-feature-linux.json b/experimental-feature-linux.json index f97b56b6013..232109de447 100644 --- a/experimental-feature-linux.json +++ b/experimental-feature-linux.json @@ -3,5 +3,6 @@ "PSLoadAssemblyFromNativeCode", "PSNativeWindowsTildeExpansion", "PSRedirectToVariable", + "PSSerializeJSONLongEnumAsNumber", "PSSubsystemPluginModel" ] diff --git a/experimental-feature-windows.json b/experimental-feature-windows.json index f97b56b6013..232109de447 100644 --- a/experimental-feature-windows.json +++ b/experimental-feature-windows.json @@ -3,5 +3,6 @@ "PSLoadAssemblyFromNativeCode", "PSNativeWindowsTildeExpansion", "PSRedirectToVariable", + "PSSerializeJSONLongEnumAsNumber", "PSSubsystemPluginModel" ] diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs index 8e0e7e7776d..33465683153 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs @@ -577,7 +577,7 @@ private static object ProcessValue(object obj, int currentDepth, in ConvertToJso { Type t = obj.GetType(); - if (t.IsPrimitive) + if (t.IsPrimitive || (t.IsEnum && ExperimentalFeature.IsEnabled(ExperimentalFeature.PSSerializeJSONLongEnumAsNumber))) { rv = obj; } diff --git a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs index 7e358e94e94..dd26e609641 100644 --- a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs +++ b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs @@ -24,6 +24,7 @@ public class ExperimentalFeature internal const string PSFeedbackProvider = "PSFeedbackProvider"; internal const string PSNativeWindowsTildeExpansion = nameof(PSNativeWindowsTildeExpansion); internal const string PSRedirectToVariable = "PSRedirectToVariable"; + internal const string PSSerializeJSONLongEnumAsNumber = nameof(PSSerializeJSONLongEnumAsNumber); #endregion @@ -121,6 +122,10 @@ static ExperimentalFeature() new ExperimentalFeature( name: PSRedirectToVariable, description: "Add support for redirecting to the variable drive"), + new ExperimentalFeature( + name: PSSerializeJSONLongEnumAsNumber, + description: "Serialize enums based on long or ulong as an numeric value rather than the string representation when using ConvertTo-Json." + ) }; EngineExperimentalFeatures = new ReadOnlyCollection(engineFeatures); diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.PSSerializeJSONLongEnumAsNumber.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.PSSerializeJSONLongEnumAsNumber.Tests.ps1 new file mode 100644 index 00000000000..d21b87ce221 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.PSSerializeJSONLongEnumAsNumber.Tests.ps1 @@ -0,0 +1,34 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +Describe 'ConvertTo-Json with PSSerializeJSONLongEnumAsNumber' -tags "CI" { + + BeforeAll { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() + $PSDefaultParameterValues['It:Skip'] = -not [ExperimentalFeature]::IsEnabled('PSSerializeJSONLongEnumAsNumber') + } + + AfterAll { + $global:PSDefaultParameterValues = $originalDefaultParameterValues + } + + It 'Should treat enums as integers' { + enum LongEnum : long { + LongValue = -1 + } + + enum ULongEnum : ulong { + ULongValue = 18446744073709551615 + } + + $obj = [Ordered]@{ + Long = [LongEnum]::LongValue + ULong = [ULongEnum]::ULongValue + } + + $actual = ConvertTo-Json -InputObject $obj -Compress + $actual | Should -Be '{"Long":-1,"ULong":18446744073709551615}' + + $actual = ConvertTo-Json -InputObject $obj -EnumsAsStrings -Compress + $actual | Should -Be '{"Long":"LongValue","ULong":"ULongValue"}' + } +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Json.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Json.Tests.ps1 index 5f33e1b6b75..46ce42c223c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Json.Tests.ps1 @@ -58,7 +58,9 @@ Describe "Json Tests" -Tags "Feature" { $valueFromNotCompressedResult.FirstName | Should -Match $valueFromCompressedResult.FirstName } - It "Convertto-Json should handle Enum based on Int64" { + It "Convertto-Json should handle Enum based on Int64" -Skip:( + [ExperimentalFeature]::IsEnabled("PSSerializeJSONLongEnumAsNumber") + ) { # Test follow-up for bug Win8: 378368 Convertto-Json problems with Enum based on Int64. if ( $null -eq ("JsonEnumTest" -as "Type")) { @@ -355,7 +357,7 @@ Describe "Json Tests" -Tags "Feature" { { "date-s-should-parse-as-datetime": "2008-09-22T14:01:54", "date-upperO-should-parse-as-datetime": "2008-09-22T14:01:54.9571247Z", - + "date-o-should-parse-as-string": "2019-12-17T06:14:06 +06:00", "date-upperD-should-parse-as-string": "Monday, September 22, 2008", "date-f-should-parse-as-string": "Monday, September 22, 2008 2:01 PM", @@ -399,7 +401,7 @@ Describe "Json Tests" -Tags "Feature" { $result."date-s-should-parse-as-datetime".ToString("Y") | Should -Be "September 2008" $result."date-s-should-parse-as-datetime".ToString("y") | Should -Be "September 2008" $result."date-s-should-parse-as-datetime" | Should -BeOfType [DateTime] - + $result."date-upperO-should-parse-as-datetime" = [datetime]::SpecifyKind($result."date-upperO-should-parse-as-datetime", [System.DateTimeKind]::Utc) $result."date-upperO-should-parse-as-datetime".ToString("d") | Should -Be "9/22/2008" $result."date-upperO-should-parse-as-datetime".ToString("D") | Should -Be "Monday, September 22, 2008" @@ -420,7 +422,7 @@ Describe "Json Tests" -Tags "Feature" { $result."date-upperO-should-parse-as-datetime".ToString("Y") | Should -Be "September 2008" $result."date-upperO-should-parse-as-datetime".ToString("y") | Should -Be "September 2008" $result."date-upperO-should-parse-as-datetime" | Should -BeOfType [DateTime] - + $result."date-o-should-parse-as-string" | Should -Be "2019-12-17T06:14:06 +06:00" $result."date-o-should-parse-as-string" | Should -BeOfType [String] $result."date-f-should-parse-as-string" | Should -Be "Monday, September 22, 2008 2:01 PM" @@ -453,7 +455,7 @@ Describe "Json Tests" -Tags "Feature" { $result."date-y-should-parse-as-string" | Should -BeOfType [String] } } - + It "ConvertFrom-Json properly parses complex objects" { $json = @" { @@ -541,13 +543,13 @@ Describe "Json Tests" -Tags "Feature" { $result."registered" | Should -BeOfType [String] $result."_id"| Should -BeExactly "60dd3ea9253016932039a0a2" $result."_id" | Should -BeOfType [String] - + $result.Tags | Should -BeOfType [string] - - $result.Tags.count | Should -Be 7 + + $result.Tags.count | Should -Be 7 $result.Tags[0] | Should -BeExactly "laboris" $result.Tags | Should -Be @("laboris", "voluptate", "amet", "ad", "velit", "ipsum", "do") - + $result.Friends | Should -BeOfType [pscustomobject] $result.Friends[0].id | Should -Be 0 $result.Friends[0].name | Should -BeExactly "Renee Holden" @@ -556,7 +558,7 @@ Describe "Json Tests" -Tags "Feature" { $result.Friends[2].id | Should -Be 2 $result.Friends[2].name | Should -BeExactly "Emilia Holder" } - + It "ConvertFrom-Json chooses the appropriate number type" { ConvertFrom-Json -InputObject "5" | should -Be 5 ConvertFrom-Json -InputObject 5 | should -Be 5 @@ -570,33 +572,33 @@ Describe "Json Tests" -Tags "Feature" { ConvertFrom-Json -InputObject 5.0 | should -Be 5.0 ConvertFrom-Json -InputObject "5.0" | should -BeOfType [double] ConvertFrom-Json -InputObject 5.0 | should -BeOfType [double] - + # The decimal is lost but only when this is quoted ConvertFrom-Json -InputObject "500000000000.0000000000000001" | should -Be "500000000000" - + # Counter intuitively all four of these tests pass because precision is lost on both sides of the test, likely due to powershell number handling ConvertFrom-Json -InputObject 500000000000.0000000000000001 | should -Be 500000000000 ConvertFrom-Json -InputObject 500000000000.0000000000000001 | should -Be 500000000000.0000000000000001 ConvertFrom-Json -InputObject 500000000000 | should -Be 500000000000.0000000000000001 ConvertFrom-Json -InputObject 500000000000 | should -Be 500000000000 - + ConvertFrom-Json -InputObject "500000000000.0000000000000001" | should -BeOfType [double] ConvertFrom-Json -InputObject 500000000000.0000000000000001 | should -BeOfType [double] - + # these tests also pass because precision is lost during conversion/powershell handling ConvertFrom-Json -InputObject "50000000000000000000000000000000000.0000000000000001" | should -Be "5E+34" ConvertFrom-Json -InputObject 50000000000000000000000000000000000.0000000000000001 | should -Be "5E+34" - + ConvertFrom-Json -InputObject "50000000000000000000000000000000000.0000000000000001" | should -BeOfType [double] ConvertFrom-Json -InputObject 50000000000000000000000000000000000.0000000000000001 | should -BeOfType [double] - - + + ConvertFrom-Json -InputObject "50000000000000000000000000000000000" | should -Be 50000000000000000000000000000000000 ConvertFrom-Json -InputObject 50000000000000000000000000000000000 | should -Be 50000000000000000000000000000000000 ConvertFrom-Json -InputObject "50000000000000000000000000000000000" | should -BeOfType [BigInt] ConvertFrom-Json -InputObject 50000000000000000000000000000000000 | should -BeOfType [BigInt] } - + It "ConvertFrom-Json with special characters" { $json = '{"SampleValue":"\"\\\b\f\n\r\t\u4321\uD7FF"}' diff --git a/test/tools/TestMetadata.json b/test/tools/TestMetadata.json index cd94ce83a79..bd716ccec7b 100644 --- a/test/tools/TestMetadata.json +++ b/test/tools/TestMetadata.json @@ -3,6 +3,7 @@ "ExpTest.FeatureOne": [ "test/powershell/engine/ExperimentalFeature/ExperimentalFeature.Basic.Tests.ps1" ], "PSCultureInvariantReplaceOperator": [ "test/powershell/Language/Operators/ReplaceOperator.Tests.ps1" ], "Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace": [ "test/powershell/Modules/Microsoft.PowerShell.Utility/RunspaceBreakpointManagement.Tests.ps1" ], - "PSNativeWindowsTildeExpansion": [ "test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1" ] + "PSNativeWindowsTildeExpansion": [ "test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1" ], + "PSSerializeJSONLongEnumAsNumber": [ "test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.PSSerializeJSONLongEnumAsNumber.Tests.ps1" ] } } From 652c6b3b6d6021a37c193c4807b8b960c5fe036a Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Sep 2024 14:56:38 -0700 Subject: [PATCH 023/275] Remove the MD5 branch in the strong name signing token calculation (#24288) (#24321) --- src/TypeCatalogGen/TypeCatalogGen.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/TypeCatalogGen/TypeCatalogGen.cs b/src/TypeCatalogGen/TypeCatalogGen.cs index 05a47814568..3d4c0f21ed9 100644 --- a/src/TypeCatalogGen/TypeCatalogGen.cs +++ b/src/TypeCatalogGen/TypeCatalogGen.cs @@ -235,9 +235,6 @@ private static string GetAssemblyStrongName(MetadataReader metadataReader) case AssemblyHashAlgorithm.Sha1: hashImpl = SHA1.Create(); break; - case AssemblyHashAlgorithm.MD5: - hashImpl = MD5.Create(); - break; case AssemblyHashAlgorithm.Sha256: hashImpl = SHA256.Create(); break; From 91c96f3186525e455faffbc1327a1958545cd424 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 23 Sep 2024 10:55:16 -0700 Subject: [PATCH 024/275] Add telemetry to track the use of features (#24247) (#24331) --- .../CoreCLR/CorePsAssemblyLoadContext.cs | 8 ++- .../engine/Modules/ModuleUtils.cs | 2 - .../FeedbackSubsystem/IFeedbackProvider.cs | 16 +++-- .../engine/Subsystem/SubsystemInfo.cs | 2 + .../utils/Telemetry.cs | 71 +++++++++++++++++-- 5 files changed, 83 insertions(+), 16 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsAssemblyLoadContext.cs b/src/System.Management.Automation/CoreCLR/CorePsAssemblyLoadContext.cs index 6be8d3c595e..5a15df53ca8 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsAssemblyLoadContext.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsAssemblyLoadContext.cs @@ -9,6 +9,7 @@ using System.Runtime.InteropServices; using System.Reflection; using System.Runtime.Loader; +using Microsoft.PowerShell.Telemetry; namespace System.Management.Automation { @@ -607,16 +608,19 @@ public static unsafe class PowerShellUnsafeAssemblyLoad [UnmanagedCallersOnly] public static int LoadAssemblyFromNativeMemory(IntPtr data, int size) { + int result = 0; try { using var stream = new UnmanagedMemoryStream((byte*)data, size); AssemblyLoadContext.Default.LoadFromStream(stream); - return 0; } catch { - return -1; + result = -1; } + + ApplicationInsightsTelemetry.SendUseTelemetry("PowerShellUnsafeAssemblyLoad", result == 0 ? "1" : "0"); + return result; } } } diff --git a/src/System.Management.Automation/engine/Modules/ModuleUtils.cs b/src/System.Management.Automation/engine/Modules/ModuleUtils.cs index f58f51dfd37..41bf4ac3521 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleUtils.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleUtils.cs @@ -44,8 +44,6 @@ static ModuleUtils() | FileAttributes.Offline | (FileAttributes)FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS | (FileAttributes)FILE_ATTRIBUTE_RECALL_ON_OPEN; - - return; } /// diff --git a/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs b/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs index aba105c8faa..328eb4eee87 100644 --- a/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs +++ b/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs @@ -9,6 +9,7 @@ using System.Management.Automation.Language; using System.Management.Automation.Runspaces; using System.Threading; +using Microsoft.PowerShell.Telemetry; namespace System.Management.Automation.Subsystem.Feedback { @@ -287,13 +288,14 @@ internal GeneralCommandErrorFeedback() .AddParameter("ExpandProperty", "Name") .Invoke(); - if (results.Count > 0) - { - return new FeedbackItem( - SuggestionStrings.Suggestion_CommandNotFound, - new List(results), - FeedbackDisplayLayout.Landscape); - } + if (results.Count > 0) + { + ApplicationInsightsTelemetry.SendUseTelemetry("FuzzyMatching", "CommandNotFound"); + return new FeedbackItem( + SuggestionStrings.Suggestion_CommandNotFound, + new List(results), + FeedbackDisplayLayout.Landscape); + } return null; } diff --git a/src/System.Management.Automation/engine/Subsystem/SubsystemInfo.cs b/src/System.Management.Automation/engine/Subsystem/SubsystemInfo.cs index c290e807ce4..8756fd69c9b 100644 --- a/src/System.Management.Automation/engine/Subsystem/SubsystemInfo.cs +++ b/src/System.Management.Automation/engine/Subsystem/SubsystemInfo.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Management.Automation.Internal; +using Microsoft.PowerShell.Telemetry; namespace System.Management.Automation.Subsystem { @@ -96,6 +97,7 @@ private protected SubsystemInfo(SubsystemKind kind, Type subsystemType) internal void RegisterImplementation(ISubsystem impl) { AddImplementation(impl); + ApplicationInsightsTelemetry.SendUseTelemetry(ApplicationInsightsTelemetry.s_subsystemRegistration, impl.Name); } internal ISubsystem UnregisterImplementation(Guid id) diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index ff655bbe60e..9e40e60a4d6 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -83,6 +83,13 @@ internal enum TelemetryType /// Remote session creation. /// RemoteSessionOpen, + + /// + /// Send telemetry for a stable feature when used. + /// By making a distinction between this and experimental feature use, it will make + /// queries much easier. + /// + FeatureUse, } /// @@ -110,6 +117,9 @@ public void Initialize(ITelemetry telemetry) /// public static class ApplicationInsightsTelemetry { + // The string for SubsystermRegistration + internal const string s_subsystemRegistration = "Subsystem.Registration"; + // If this env var is true, yes, or 1, telemetry will NOT be sent. private const string _telemetryOptoutEnvVar = "POWERSHELL_TELEMETRY_OPTOUT"; @@ -152,6 +162,8 @@ public static class ApplicationInsightsTelemetry private static readonly HashSet s_knownModules; private static readonly HashSet s_knownModuleTags; + private static readonly HashSet s_knownSubsystemNames; + /// Gets a value indicating whether telemetry can be sent. public static bool CanSendTelemetry { get; private set; } = false; @@ -620,6 +632,13 @@ static ApplicationInsightsTelemetry() }; s_uniqueUserIdentifier = GetUniqueIdentifier().ToString(); + s_knownSubsystemNames = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "Completion", + "general", + "Windows Package Manager - WinGet", + "Az Predictor" + }; } } @@ -715,7 +734,7 @@ internal static void SendModuleTelemetryMetric(TelemetryType telemetryType, PSMo s_telemetryClient. GetMetric(new MetricIdentifier(string.Empty, telemetryType.ToString(), "uuid", "SessionId", "ModuleName", "Version", "Tag")). - TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, allowedModuleName, allowedModuleVersion, allowedModuleTagString); + TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, allowedModuleName, allowedModuleVersion, allowedModuleTagString); } catch { @@ -754,7 +773,8 @@ internal static void SendModuleTelemetryMetric(TelemetryType telemetryType, stri /// /// The type of telemetry that we'll be sending. /// The specific details about the telemetry. - internal static void SendTelemetryMetric(TelemetryType metricId, string data) + /// The count of instances for the telemetry payload. + internal static void SendTelemetryMetric(TelemetryType metricId, string data, double value = 1.0) { if (!CanSendTelemetry) { @@ -776,12 +796,13 @@ internal static void SendTelemetryMetric(TelemetryType metricId, string data) case TelemetryType.ExperimentalEngineFeatureActivation: case TelemetryType.ExperimentalEngineFeatureDeactivation: case TelemetryType.ExperimentalFeatureUse: - s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, data); + case TelemetryType.FeatureUse: + s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: value, s_uniqueUserIdentifier, s_sessionId, data); break; case TelemetryType.ExperimentalModuleFeatureActivation: case TelemetryType.ExperimentalModuleFeatureDeactivation: string experimentalFeatureName = GetExperimentalFeatureName(data); - s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, experimentalFeatureName); + s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: value, s_uniqueUserIdentifier, s_sessionId, experimentalFeatureName); break; } } @@ -792,6 +813,35 @@ internal static void SendTelemetryMetric(TelemetryType metricId, string data) } } + /// + /// Send additional information about an feature as it is used. + /// + /// The name of the feature. + /// The details about the feature use. + /// The value to report when sending the payload. + internal static void SendUseTelemetry(string featureName, string detail, double value = 1.0) + { + if (!CanSendTelemetry) + { + return; + } + + // keep payload small + if (featureName is null || detail is null || featureName.Length > 33 || detail.Length > 33) + { + return; + } + + if (string.Compare(featureName, s_subsystemRegistration, true) == 0) + { + ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, GetSubsystemName(detail)), value); + } + else + { + ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, detail), value); + } + } + /// /// Send additional information about an experimental feature as it is used. /// @@ -822,7 +872,18 @@ private static string GetExperimentalFeatureName(string featureNameToValidate) return Anonymous; } - // Get the module name. If we can report it, we'll return the name, otherwise, we'll return "anonymous" + // Get the module name. If we can report it, we'll return the name, otherwise, we'll return the string "anonymous" + private static string GetSubsystemName(string subsystemNameToValidate) + { + if (s_knownSubsystemNames.Contains(subsystemNameToValidate)) + { + return subsystemNameToValidate; + } + + return Anonymous; + } + + // Get the module name. If we can report it, we'll return the name, otherwise, we'll return anonymous. private static string GetModuleName(string moduleNameToValidate) { if (s_knownModules.Contains(moduleNameToValidate)) From 5733a9c10444c911d89aa3201a4f92e9e04d438b Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 24 Sep 2024 09:19:11 -0700 Subject: [PATCH 025/275] Update `Microsoft.PowerShell.PSResourceGet` to `1.1.0-preview2` (#24300) (#24337) --- src/Modules/PSGalleryModules.csproj | 2 +- ...crosoft.PowerShell.PSResourceGet.Tests.ps1 | 109 ++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index e677b124710..1c8e5e64356 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + diff --git a/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 index d58a8535903..b06f0aa427a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 @@ -7,10 +7,20 @@ $ProgressPreference = "SilentlyContinue" $RepositoryName = 'PSGallery' $ACRRepositoryName = "ACRRepo" $ACRRepoUri = "https://psresourcegettest.azurecr.io/" +$LocalRepoName = 'LocalRepo' +$TempDir = 'TempDir' +$LocalRepoUri = Microsoft.PowerShell.Management\Join-Path -Path $TempDir -ChildPath 'TempLocalRepoUri' $TestModule = 'newTestModule' $TestScript = 'TestTestScript' $ACRTestModule = 'newTestMod' +$PublishedNupkgs = Microsoft.PowerShell.Management\Join-Path -Path $TempDir -ChildPath 'PublishedNupkgs' +$TestModuleNupkgName = "$TestModule.0.0.1.nupkg" +$TestModuleNupkgPath = Microsoft.PowerShell.Management\Join-Path -Path $PublishedNupkgs -ChildPath $TestModuleNupkgName +$TestScriptPath = "$TestScript.ps1" +$TestScriptNupkgName = "$TestScript.0.0.1.nupkg" +$TestScriptNupkgPath = Microsoft.PowerShell.Management\Join-Path -Path $PublishedNupkgs -ChildPath $TestScriptNupkgName + $Initialized = $false #region Install locations for modules and scripts @@ -72,6 +82,11 @@ if (!(Test-Path $script:MyDocumentsScriptsPath)) { function Initialize { + if(!(Test-Path $TempDir)) + { + New-Item -Path $TempDir -ItemType Directory + } + $repo = Get-PSResourceRepository $RepositoryName -ErrorAction SilentlyContinue if($repo) { @@ -97,6 +112,15 @@ function Initialize } } +function Register-LocalRepo +{ + if (!(Test-Path $LocalRepoUri)) { + New-Item -Path $LocalRepoUri -ItemType Directory + } + + Register-PSResourceRepository -Name $LocalRepoName -Uri $LocalRepoUri -Trusted -Force +} + #endregion function Remove-InstalledModules @@ -104,6 +128,28 @@ function Remove-InstalledModules Get-InstalledPSResource -Name $TestModule -Version '*' -ErrorAction SilentlyContinue | Microsoft.PowerShell.PSResourceGet\Uninstall-PSResource } +function New-TestPackages +{ + if (!(Test-Path $PublishedNupkgs)) { + New-Item $PublishedNupkgs -ItemType Directory + } + + if (!(Test-Path $TestModule)) { + New-Item $TestModule -ItemType Directory + } + + $moduleManifestPath = Join-Path $TestModule -ChildPath "$TestModule.psd1" + if (!(Test-Path $moduleManifestPath)) + { + New-ModuleManifest $moduleManifestPath -Description "Test module for PowerShell CI" -Author "PSGetAuthor" + } + + if (!(Test-Path $TestScriptPath)) + { + New-ScriptFileInfo -Path $TestScriptPath -Description "Test script for PowerShell CI" -Author "PSGetAuthor" + } +} + Describe "PSResourceGet - Module tests" -tags "Feature" { BeforeAll { @@ -111,6 +157,9 @@ Describe "PSResourceGet - Module tests" -tags "Feature" { Initialize $script:Initialized = $true } + + Register-LocalRepo + New-TestPackages } BeforeEach { @@ -138,6 +187,39 @@ Describe "PSResourceGet - Module tests" -tags "Feature" { } } + It "Should publish a module" { + Publish-PSResource -Path $TestModule -Repository $LocalRepoName + + $foundModuleInfo = Find-PSResource $TestModule -Repository $LocalRepoName + $foundModuleInfo | Should -Not -BeNullOrEmpty + $foundModuleInfo.Count | Should -Be 1 + $foundModuleInfo.Name | Should -Be $TestModule + } + + It "Should compress a module into a .nupkg" { + Compress-PSResource -Path $TestModule -DestinationPath $PublishedNupkgs + + $modulePublished = Get-ChildItem $TestModuleNupkgPath + $modulePublished | Should -Not -BeNullOrEmpty + $modulePublished.Name | Should -Be $TestModuleNupkgName + } + + It "Should publish compressed .nupkg" { + Compress-PSResource -Path $TestModule -DestinationPath $PublishedNupkgs + + Publish-PSResource -NupkgPath $TestModuleNupkgPath -Repository $LocalRepoName + + $foundModuleInfo = Find-PSResource $TestModule -Repository $LocalRepoName + $foundModuleInfo | Should -Not -BeNullOrEmpty + $foundModuleInfo.Count | Should -Be 1 + $foundModuleInfo.Name | Should -Be $TestModule + } + + AfterEach { + Get-ChildItem $PublishedNupkgs | Remove-Item -Recurse -Force + Get-ChildItem $LocalRepoUri | Remove-Item -Recurse -Force + } + AfterAll { Remove-InstalledModules } @@ -181,6 +263,9 @@ Describe "PSResourceGet - Script tests" -tags "Feature" { Initialize $script:Initialized = $true } + + Register-LocalRepo + New-TestPackages } BeforeEach { @@ -205,6 +290,20 @@ Describe "PSResourceGet - Script tests" -tags "Feature" { } } + It "Should publish a script" { + Publish-PSResource -Path $TestScriptPath -Repository $LocalRepoName + + $foundScriptInfo = Find-PSResource $TestScript -Repository $LocalRepoName + $foundScriptInfo | Should -Not -BeNullOrEmpty + $foundScriptInfo.Count | Should -Be 1 + $foundScriptInfo.Name | Should -Be $TestScript + } + + AfterEach { + Get-ChildItem $PublishedNupkgs | Remove-Item -Recurse -Force + Get-ChildItem $LocalRepoUri | Remove-Item -Recurse -Force + } + AfterAll { Remove-InstalledScripts } @@ -294,5 +393,15 @@ Describe "PSResourceGet - ACR tests" -tags "Feature" { } Remove-InstalledModules + FinalCleanUp + } +} + + +function FinalCleanUp +{ + if(Test-Path $TempDir) + { + Remove-Item -Path $TempDir -Recurse -Force } } From 20ad8f3fd7e10b161f2f8878d9d7d3d0e824e8f9 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 25 Sep 2024 11:02:35 -0700 Subject: [PATCH 026/275] Add `-Force` parameter to `Resolve-Path` and `Convert-Path` cmdlets to support wildcard hidden files (#20981) (#24344) --- .../commands/management/ConvertPathCommand.cs | 10 +++ .../commands/management/ResolvePathCommand.cs | 10 +++ .../Convert-Path.Tests.ps1 | 69 +++++++++++++++++++ .../Resolve-Path.Tests.ps1 | 63 ++++++++++++++++- 4 files changed, 151 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ConvertPathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ConvertPathCommand.cs index c32d0f2aa67..33796b23378 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ConvertPathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ConvertPathCommand.cs @@ -55,6 +55,16 @@ public string[] LiteralPath } } + /// + /// Gets or sets the force property. + /// + [Parameter] + public override SwitchParameter Force + { + get => base.Force; + set => base.Force = value; + } + #endregion Parameters #region parameter data diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs index b624c6e08cf..3d1b66933d2 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs @@ -93,6 +93,16 @@ public string RelativeBasePath } } + /// + /// Gets or sets the force property. + /// + [Parameter] + public override SwitchParameter Force + { + get => base.Force; + set => base.Force = value; + } + #endregion Parameters #region parameter data diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Convert-Path.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Convert-Path.Tests.ps1 index 1cc88b36bb7..7de1d97dd20 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Convert-Path.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Convert-Path.Tests.ps1 @@ -1,6 +1,27 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. Describe "Convert-Path tests" -Tag CI { + BeforeAll { + $hiddenFilePrefix = ($IsLinux -or $IsMacOS) ? '.' : '' + + $hiddenFilePath1 = Join-Path -Path $TestDrive -ChildPath "$($hiddenFilePrefix)test1.txt" + $hiddenFilePath2 = Join-Path -Path $TestDrive -ChildPath "$($hiddenFilePrefix)test2.txt" + + $hiddenFile1 = New-Item -Path $hiddenFilePath1 -ItemType File + $hiddenFile2 = New-Item -Path $hiddenFilePath2 -ItemType File + + $relativeHiddenFilePath1 = ".$([System.IO.Path]::DirectorySeparatorChar)$($hiddenFilePrefix)test1.txt" + $relativeHiddenFilePath2 = ".$([System.IO.Path]::DirectorySeparatorChar)$($hiddenFilePrefix)test2.txt" + + if ($IsWindows) { + $hiddenFile1.Attributes = "Hidden" + $hiddenFile2.Attributes = "Hidden" + } + + $hiddenFileWildcardPath = Join-Path -Path $TestDrive -ChildPath "$($hiddenFilePrefix)test*.txt" + $relativeHiddenFileWildcardPath = ".$([System.IO.Path]::DirectorySeparatorChar)$($hiddenFilePrefix)test*.txt" + } + It "Convert-Path should handle provider qualified paths" { Convert-Path -Path "FileSystem::${TestDrive}" | Should -BeExactly "${TestDrive}" } @@ -41,4 +62,52 @@ Describe "Convert-Path tests" -Tag CI { It "Convert-Path should return something which exists" { Convert-Path -Path $TestDrive | Should -Exist } + + It "Convert-Path -Path '' -Force: should return ''" -TestCases @( + @{ + Path = $relativeHiddenFilePath1 + BasePath = $TestDrive + Force = $false + ExpectedResult = $hiddenFilePath1 + } + @{ + Path = $relativeHiddenFilePath2 + BasePath = $TestDrive + Force = $false + ExpectedResult = $hiddenFilePath2 + } + @{ + Path = $relativeHiddenFileWildcardPath + BasePath = $TestDrive + Force = $false + ExpectedResult = $null + } + @{ + Path = $relativeHiddenFilePath1 + BasePath = $TestDrive + Force = $true + ExpectedResult = $hiddenFilePath1 + } + @{ + Path = $relativeHiddenFilePath2 + BasePath = $TestDrive + Force = $true + ExpectedResult = $hiddenFilePath2 + } + @{ + Path = $relativeHiddenFileWildcardPath + BasePath = $TestDrive + Force = $true + ExpectedResult = @($hiddenFilePath1, $hiddenFilePath2) + } + ) { + param($Path, $BasePath, $Force, $ExpectedResult) + try { + Push-Location -Path $BasePath + Convert-Path -Path $Path -Force:$Force | Should -BeExactly $ExpectedResult + } + finally { + Pop-Location + } + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Resolve-Path.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Resolve-Path.Tests.ps1 index efd2441e0a7..9e38d1f8c20 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Resolve-Path.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Resolve-Path.Tests.ps1 @@ -16,6 +16,25 @@ Describe "Resolve-Path returns proper path" -Tag "CI" { @{ wd = $fakeRoot; target = $testRoot; expected = $testRoot } @{ wd = $testRoot; target = Join-Path $fakeRoot "file.txt"; expected = Join-Path "." "fakeroot" "file.txt" } ) + + $hiddenFilePrefix = ($IsLinux -or $IsMacOS) ? '.' : '' + + $hiddenFilePath1 = Join-Path -Path $TestDrive -ChildPath "$($hiddenFilePrefix)test1.txt" + $hiddenFilePath2 = Join-Path -Path $TestDrive -ChildPath "$($hiddenFilePrefix)test2.txt" + + $hiddenFile1 = New-Item -Path $hiddenFilePath1 -ItemType File + $hiddenFile2 = New-Item -Path $hiddenFilePath2 -ItemType File + + $relativeHiddenFilePath1 = ".$([System.IO.Path]::DirectorySeparatorChar)$($hiddenFilePrefix)test1.txt" + $relativeHiddenFilePath2 = ".$([System.IO.Path]::DirectorySeparatorChar)$($hiddenFilePrefix)test2.txt" + + if ($IsWindows) { + $hiddenFile1.Attributes = "Hidden" + $hiddenFile2.Attributes = "Hidden" + } + + $hiddenFileWildcardPath = Join-Path -Path $TestDrive -ChildPath "$($hiddenFilePrefix)test*.txt" + $relativeHiddenFileWildcardPath = ".$([System.IO.Path]::DirectorySeparatorChar)$($hiddenFilePrefix)test*.txt" } AfterAll { Remove-PSDrive -Name $driveName -Force @@ -86,7 +105,7 @@ Describe "Resolve-Path returns proper path" -Tag "CI" { } ) -Test { param($Path, $BasePath, $Expected, $CD) - + if ($null -eq $Expected) { {Resolve-Path -Path $Path -RelativeBasePath $BasePath -ErrorAction Stop} | Should -Throw -ErrorId "PathNotFound,Microsoft.PowerShell.Commands.ResolvePathCommand" @@ -114,4 +133,46 @@ Describe "Resolve-Path returns proper path" -Tag "CI" { } } } + + It "Resolve-Path -Path '' -RelativeBasePath '' -Force: should return ''" -TestCases @( + @{ + Path = $relativeHiddenFilePath1 + BasePath = $TestDrive + Force = $false + ExpectedResult = $hiddenFilePath1 + } + @{ + Path = $relativeHiddenFilePath2 + BasePath = $TestDrive + Force = $false + ExpectedResult = $hiddenFilePath2 + } + @{ + Path = $relativeHiddenFileWildcardPath + BasePath = $TestDrive + Force = $false + ExpectedResult = $null + } + @{ + Path = $relativeHiddenFilePath1 + BasePath = $TestDrive + Force = $true + ExpectedResult = $hiddenFilePath1 + } + @{ + Path = $relativeHiddenFilePath2 + BasePath = $TestDrive + Force = $true + ExpectedResult = $hiddenFilePath2 + } + @{ + Path = $relativeHiddenFileWildcardPath + BasePath = $TestDrive + Force = $true + ExpectedResult = @($hiddenFilePath1, $hiddenFilePath2) + } + ) { + param($Path, $BasePath, $Force, $ExpectedResult) + (Resolve-Path -Path $Path -RelativeBasePath $BasePath -Force:$Force).Path | Should -BeExactly $ExpectedResult + } } From ecf40d6f5f3f1180f42e2d6a64fdae13f97dd32a Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 25 Sep 2024 11:12:11 -0700 Subject: [PATCH 027/275] Copy to static site instead of making blob public (#24269) (#24343) --- .../templates/release-MakeBlobPublic.yml | 119 +++++++++++------- .../templates/release-upload-buildinfo.yml | 21 ++-- tools/install-powershell.ps1 | 4 +- 3 files changed, 84 insertions(+), 60 deletions(-) diff --git a/.pipelines/templates/release-MakeBlobPublic.yml b/.pipelines/templates/release-MakeBlobPublic.yml index 1e3789b207a..ba4fb14ec8a 100644 --- a/.pipelines/templates/release-MakeBlobPublic.yml +++ b/.pipelines/templates/release-MakeBlobPublic.yml @@ -1,31 +1,22 @@ jobs: - template: /.pipelines/templates/approvalJob.yml@self parameters: - displayName: Approve Blob Public - jobName: ApproveBlobPublic + displayName: Approve Copy release packages to PSInfra storage + jobName: CopyReleaseBlobApproval instructions: | - Are you sure you want to make the blob public? + Approval for Copy release packages to PSInfra storage -- job: blobPublic - displayName: Make Azure Blob Public - dependsOn: ApproveBlobPublic - condition: succeeded() +- job: PSInfraReleaseBlobPublic + displayName: Copy release to PSInfra storage + dependsOn: CopyReleaseBlobApproval pool: type: windows + variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE - value: 1 + - group: 'PSInfraStorage' - group: 'Azure Blob variable group' - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: ob_sdl_codeSignValidation_enabled - value: false - - name: ob_sdl_binskim_enabled - value: false - name: ob_sdl_tsa_configFile value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - name: ob_sdl_credscan_suppressionsFile @@ -34,47 +25,81 @@ jobs: value: false steps: - - checkout: self - clean: true - env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + - checkout: self + clean: true + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - - template: /.pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: yes + UseJson: no - pwsh: | Get-ChildItem Env: displayName: 'Capture Environment Variables' - - pwsh: | - $azureRmModule = Get-InstalledModule AzureRM -ErrorAction SilentlyContinue -Verbose - if ($azureRmModule) { - Write-Host 'AzureRM module exists. Removing it' - Uninstall-AzureRm - Write-Host 'AzureRM module removed' - } - - Install-Module -Name Az.Storage -Force -AllowClobber -Scope CurrentUser -Verbose - displayName: Remove AzRM modules - - - task: AzureCLI@2 - displayName: 'Set blob permissions' - inputs: - azureSubscription: az-blob-cicd-infra - scriptType: 'pscore' - scriptLocation: 'inlineScript' - inlineScript: | - az storage container set-permission --account-name $(StorageAccount) --name $(azureVersion) --public-access blob - az storage container set-permission --account-name $(StorageAccount) --name $(azureVersion)-gc --public-access blob + - pwsh: | + $azureRmModule = Get-InstalledModule AzureRM -ErrorAction SilentlyContinue -Verbose + if ($azureRmModule) { + Write-Host 'AzureRM module exists. Removing it' + Uninstall-AzureRm + Write-Host 'AzureRM module removed' + } + + Install-Module -Name Az.Storage -Force -AllowClobber -Scope CurrentUser -Verbose + displayName: Remove AzRM modules + + - task: AzurePowerShell@5 + displayName: Copy blobs to PSInfra storage + inputs: + azureSubscription: az-blob-cicd-infra + scriptType: inlineScript + azurePowerShellVersion: LatestVersion + pwsh: true + inline: | + $sourceStorageAccountName = '$(StorageAccount)' + $destinationStorageAccountName = '$(PSInfraStorageAccount)' + $destinationContainerName = '$web' + $destinationPrefix = 'install/$(ReleaseTagVar)' + + $sourceContext = New-AzStorageContext -StorageAccountName $sourceStorageAccountName + Write-Verbose -Verbose "Source context: $($sourceContext.BlobEndPoint)" + + $destinationContext = New-AzStorageContext -StorageAccountName $destinationStorageAccountName + Write-Verbose -Verbose "Destination context: $($destinationContext.BlobEndPoint)" + + foreach ($sourceContainerName in '$(AzureVersion)', '$(AzureVersion)-gc') { + $blobs = Get-AzStorageBlob -Context $sourceContext -Container $sourceContainerName + + Write-Verbose -Verbose "Blobs found in $sourceContainerName" + $blobs.Name | Write-Verbose -Verbose + + Write-Verbose -Verbose "Copying blobs from $sourceContainerName to $destinationContainerName/$destinationPrefix" + + foreach ($blob in $blobs) { + $sourceBlobName = $blob.Name + Write-Verbose -Verbose "sourceBlobName = $sourceBlobName" + + $destinationBlobName = "$destinationPrefix/$sourceBlobName" + Write-Verbose -Verbose "destinationBlobName = $destinationBlobName" + $existingBlob = Get-AzStorageBlob -Blob $destinationBlobName -Container $destinationContainerName -Context $destinationContext -ErrorAction Ignore + if ($existingBlob) { + Write-Verbose -Verbose "Blob $destinationBlobName already exists in '$destinationStorageAccountName/$destinationContainerName', removing before copy." + $existingBlob | Remove-AzStorageBlob -ErrorAction Stop -Verbose + } + + Copy-AzStorageBlob -SourceContext $sourceContext -DestinationContext $destinationContext -SrcContainer $sourceContainerName -SrcBlob $sourceBlobName -DestContainer $destinationContainerName -DestBlob $destinationBlobName -Force -Verbose -Confirm:$false + } + } + - template: /.pipelines/templates/approvalJob.yml@self parameters: displayName: Approve Copy Global tool packages to PSInfra storage jobName: CopyBlobApproval - dependsOnJob: blobPublic + dependsOnJob: PSInfraReleaseBlobPublic instructions: | Approval for Copy global tool packages to PSInfra storage diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index 3738328004b..f2b06cd2010 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -45,14 +45,14 @@ jobs: displayName: Download build info artifact - pwsh: | - Import-Module '$(Build.SourcesDirectory)/tools/ci.psm1' + Import-Module '$(Build.SourcesDirectory)/PowerShell/tools/ci.psm1' $jsonFile = Get-Item "$ENV:PIPELINE_WORKSPACE/PSPackagesOfficial/BuildInfoJson/*.json" $fileName = Split-Path $jsonFile -Leaf $dateTime = [datetime]::UtcNow $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) - $metadata = Get-Content ./tools/metadata.json | ConvertFrom-Json + $metadata = Get-Content -LiteralPath '$(Build.SourcesDirectory)/PowerShell/tools/metadata.json' -ErrorAction Stop | ConvertFrom-Json $stableRelease = $metadata.StableRelease.Latest $ltsRelease = $metadata.LTSRelease.Latest @@ -118,29 +118,30 @@ jobs: azurePowerShellVersion: LatestVersion pwsh: true inline: | - $containerName = "buildinfo" - $storageAccount = '$(StorageAccount)' + $containerName = '$web' + $storageAccount = '$(PSInfraStorageAccount)' + $prefix = "buildinfo" $storageContext = New-AzStorageContext -StorageAccountName $storageAccount -UseConnectedAccount if ($env:CopyMainBuildInfo -eq 'YES') { $jsonFile = "$env:BuildInfoJsonFile" $blobName = Get-Item $jsonFile | Split-Path -Leaf - Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$blobName" - Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob $blobName -Context $storageContext -Force + Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" + Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } if ($env:CopyLTSBuildInfo -eq 'YES') { $jsonFile = "$env:LtsBuildInfoJsonFile" $blobName = Get-Item $jsonFile | Split-Path -Leaf - Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$blobName" - Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob $blobName -Context $storageContext -Force + Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" + Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } if ($env:CopyVersionBuildInfo -eq 'YES') { $jsonFile = "$env:VersionBuildInfoJsonFile" $blobName = Get-Item $jsonFile | Split-Path -Leaf - Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$blobName" - Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob $blobName -Context $storageContext -Force + Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" + Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } condition: and(succeeded(), eq(variables['CopyMainBuildInfo'], 'YES')) diff --git a/tools/install-powershell.ps1 b/tools/install-powershell.ps1 index b6c8f595ccb..2f40e9223c1 100644 --- a/tools/install-powershell.ps1 +++ b/tools/install-powershell.ps1 @@ -268,7 +268,6 @@ try { if ($Daily) { $metadata = Invoke-RestMethod 'https://aka.ms/pwsh-buildinfo-daily' $release = $metadata.ReleaseTag -replace '^v' - $blobName = $metadata.BlobName # Get version from currently installed PowerShell Daily if available. $pwshPath = if ($IsWinEnv) {Join-Path $Destination "pwsh.exe"} else {Join-Path $Destination "pwsh"} @@ -297,8 +296,7 @@ try { throw "The OS architecture is '$architecture'. However, we currently only support daily package for x64." } - - $downloadURL = "https://pscoretestdata.blob.core.windows.net/${blobName}/${packageName}" + $downloadURL = "https://powershellinfraartifacts-gkhedzdeaghdezhr.z01.azurefd.net/install/$($metadata.ReleaseTag)/$packageName" Write-Verbose "About to download package from '$downloadURL'" -Verbose $packagePath = Join-Path -Path $tempDir -ChildPath $packageName From 508825bb407083e8e256569ecf756ea303d4294c Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 25 Sep 2024 11:43:17 -0700 Subject: [PATCH 028/275] Fix cleanup in PSResourceGet test (#24339) (#24345) --- ...Microsoft.PowerShell.PSResourceGet.Tests.ps1 | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 index b06f0aa427a..01f9a90127a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 @@ -331,6 +331,14 @@ Describe "PSResourceGet - Script tests (Admin)" -Tags @('Feature', 'RequireAdmin } } +function FinalCleanUp +{ + if(Test-Path $TempDir) + { + Remove-Item -Path $TempDir -Recurse -Force + } +} + Describe "PSResourceGet - ACR tests" -tags "Feature" { BeforeAll { @@ -396,12 +404,3 @@ Describe "PSResourceGet - ACR tests" -tags "Feature" { FinalCleanUp } } - - -function FinalCleanUp -{ - if(Test-Path $TempDir) - { - Remove-Item -Path $TempDir -Recurse -Force - } -} From 113e15ef345f93c0ab8bbe3f46ac76892d8b2332 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Wed, 2 Oct 2024 12:59:44 -0500 Subject: [PATCH 029/275] Fix found during 7.5-preview.5 release (#24368) * Merged PR 32689: Fix typo in release-MakeBlobPublic.yml Fix typo in release-MakeBlobPublic.yml * Merged PR 32693: Add back local NuGet source for test packages Add back local NuGet source for test packages * Merged PR 32696: Fixed Test Scenario for Compress-PSResource The test was failing because a relative path was provided to parameter -DestinationPath. Should update Compress-PSResource to accept relative paths for -DestinationPath. ---- #### AI description (iteration 1) #### PR Classification Bug fix for a failing test scenario. #### PR Summary This pull request fixes the test scenario for the `Compress-PSResource` function. - `Microsoft.PowerShell.PSResourceGet.Tests.ps1`: Updated the path resolution for `$PublishedNupkgs` using `Resolve-Path` and added a missing line break in the test for compressing a module. * Merged PR 32709: Changelog for v7.5.0-preview.5 Added 7.5.0-preview.5 change log ---- #### AI description (iteration 1) #### PR Classification Changelog update for the new preview release. #### PR Summary This pull request updates the changelog for the v7.5.0-preview.5 release, documenting breaking changes, engine updates, new features, and other improvements. - `ConvertTo-Json`: Treat large Enum values as numbers. - `Import-Module`: Fix processor architecture validation. - `Resolve-Path` and `Convert-Path`: Add `-Force` parameter to support wildcard hidden files. - `PSResourceGet` test: Fix cleanup. - Various build and packaging improvements, including updates to dependencies and test scenarios. * fixed readme lint error --------- Co-authored-by: Aditya Patwardhan Co-authored-by: Justin Chung Co-authored-by: Justin Chung --- .../templates/release-MakeBlobPublic.yml | 6 +- .pipelines/templates/release-validate-sdk.yml | 10 +-- CHANGELOG/preview.md | 68 ++++++++++++++++++- ...crosoft.PowerShell.PSResourceGet.Tests.ps1 | 6 +- 4 files changed, 77 insertions(+), 13 deletions(-) diff --git a/.pipelines/templates/release-MakeBlobPublic.yml b/.pipelines/templates/release-MakeBlobPublic.yml index ba4fb14ec8a..52b3476d1e3 100644 --- a/.pipelines/templates/release-MakeBlobPublic.yml +++ b/.pipelines/templates/release-MakeBlobPublic.yml @@ -36,9 +36,9 @@ jobs: CreateJson: yes UseJson: no - - pwsh: | - Get-ChildItem Env: - displayName: 'Capture Environment Variables' + - pwsh: | + Get-ChildItem Env: + displayName: 'Capture Environment Variables' - pwsh: | $azureRmModule = Get-InstalledModule AzureRM -ErrorAction SilentlyContinue -Verbose diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index f626051b543..db3f550b965 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -89,11 +89,11 @@ jobs: Start-PSBootstrap $localLocation = "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" - # $xmlElement = @" - # - # - # - # "@ + $xmlElement = @" + + + + "@ $releaseVersion = '$(Version)' diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index 73d39ba122a..847ca7a2919 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,69 @@ # Preview Changelog +## [7.5.0-preview.5] - 2024-10-01 + +### Breaking Changes + +- Treat large `Enum` values as numbers in `ConvertTo-Json` (#20999) (#24304) + +### Engine Updates and Fixes + +- Fix how processor architecture is validated in `Import-Module` (#24265) (#24317) + +### Experimental Features + +### General Cmdlet Updates and Fixes + +- Add `-Force` parameter to `Resolve-Path` and `Convert-Path` cmdlets to support wildcard hidden files (#20981) (#24344) +- Add telemetry to track the use of features (#24247) (#24331) +- Treat large `Enum` values as numbers in `ConvertTo-Json` (#20999) (#24304) +- Make features `PSCommandNotFoundSuggestion`, `PSCommandWithArgs`, and `PSModuleAutoLoadSkipOfflineFiles` stable (#24246) (#24310) +- Handle global tool when prepending `$PSHome` to `PATH` (#24228) (#24307) + +### Tests + +- Fix cleanup in `PSResourceGet` test (#24339) (#24345) + +### Build and Packaging Improvements + +
+ + + +

Bump .NET SDK to 9.0.100-rc.1.24452.12

+ +
+ +
    +
  • Fixed Test Scenario for Compress-PSResource (Internal 32696)
  • +
  • Add back local NuGet source for test packages (Internal 32693)
  • +
  • Fix typo in release-MakeBlobPublic.yml (Internal 32689)
  • +
  • Copy to static site instead of making blob public (#24269) (#24343)
  • +
  • Update Microsoft.PowerShell.PSResourceGet to 1.1.0-preview2 (#24300) (#24337)
  • +
  • Remove the MD5 branch in the strong name signing token calculation (#24288) (#24321)
  • +
  • Update experimental-feature json files (#24271) (#24319)
  • +
  • Add updated libicu dependency for Debian packages (#24301) (#24324)
  • +
  • Add mapping to AzureLinux repo (#24290) (#24322)
  • +
  • Update and add new NuGet package sources for different environments. (#24264) (#24316)
  • +
  • Bump .NET 9 to 9.0.100-rc.1.24452.12 (#24273) (#24320)
  • +
  • Make some release tests run in a hosted pools (#24270) (#24318)
  • +
  • Do not build the exe for Global tool shim project (#24263) (#24315)
  • +
  • Delete assets/AppImageThirdPartyNotices.txt (#24256) (#24313)
  • +
  • Create new pipeline for compliance (#24252) (#24312)
  • +
  • Add specific path for issues in tsaconfig (#24244) (#24309)
  • +
  • Use Managed Identity for APIScan authentication (#24243) (#24308)
  • +
  • Add Windows signing for pwsh.exe (#24219) (#24306)
  • +
  • Check Create and Submit in vPack build by default (#24181) (#24305)
  • +
+ +
+ +### Documentation and Help Content + +- Delete demos directory (#24258) (#24314) + +[7.5.0-preview.5]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-preview.4...v7.5.0-preview.5 + ## [7.5.0-preview.4] - 2024-08-28 ### Engine Updates and Fixes @@ -474,7 +538,7 @@ ### Documentation and Help Content -- Include information about upgrading in README (#20993) +- Include information about upgrading in readme (#20993) - Expand "iff" to "if-and-only-if" in XML doc content (#20852) - Update LTS links in README.md to point to the v7.4 packages (#20839) (Thanks @kilasuit!) - Update `README.md` to improve readability (#20553) (Thanks @AnkitaSikdar005!) @@ -482,7 +546,7 @@ - Update `ADOPTERS.md` (#20555) (Thanks @AnkitaSikdar005!) - Fix a typo in `ADOPTERS.md` (#20504, #20520) (Thanks @shruti-sen2004!) - Correct grammatical errors in `README.md` (#20509) (Thanks @alienishi!) -- Add 7.3 changelog URL to Readme (#20473) (Thanks @Saibamen!) +- Add 7.3 changelog URL to readme (#20473) (Thanks @Saibamen!) - Clarify some comments and documentation (#20462) (Thanks @darkstar!) [7.5.0-preview.1]: https://github.com/PowerShell/PowerShell/compare/v7.4.1...v7.5.0-preview.1 diff --git a/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 index 01f9a90127a..46e4f60cbc2 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 @@ -197,15 +197,15 @@ Describe "PSResourceGet - Module tests" -tags "Feature" { } It "Should compress a module into a .nupkg" { - Compress-PSResource -Path $TestModule -DestinationPath $PublishedNupkgs - + Compress-PSResource -Path $TestModule -DestinationPath (Resolve-Path -Path $PublishedNupkgs) + $modulePublished = Get-ChildItem $TestModuleNupkgPath $modulePublished | Should -Not -BeNullOrEmpty $modulePublished.Name | Should -Be $TestModuleNupkgName } It "Should publish compressed .nupkg" { - Compress-PSResource -Path $TestModule -DestinationPath $PublishedNupkgs + Compress-PSResource -Path $TestModule -DestinationPath (Resolve-Path -Path $PublishedNupkgs) Publish-PSResource -NupkgPath $TestModuleNupkgPath -Repository $LocalRepoName From 34c679ec05b18f39f212a4d8852875d929e1aea3 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 3 Oct 2024 13:09:57 -0700 Subject: [PATCH 030/275] Add `BaseUrl` to `buildinfo` json file (#24376) (#24377) Co-authored-by: Patrick Meinecke --- tools/releaseBuild/setReleaseTag.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/releaseBuild/setReleaseTag.ps1 b/tools/releaseBuild/setReleaseTag.ps1 index 3f501051c19..c5f2f016554 100644 --- a/tools/releaseBuild/setReleaseTag.ps1 +++ b/tools/releaseBuild/setReleaseTag.ps1 @@ -41,6 +41,7 @@ function New-BuildInfoJson { ReleaseTag = $ReleaseTag ReleaseDate = $dateTime BlobName = $blobName + BaseUrl = 'https://powershellinfraartifacts-gkhedzdeaghdezhr.z01.azurefd.net/install' } | ConvertTo-Json | Out-File -Encoding ascii -Force -FilePath $filename $resolvedPath = (Resolve-Path -Path $filename).ProviderPath From 04efcdc3f09f439794d00ba7feaf121d54239619 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Thu, 3 Oct 2024 17:21:14 -0500 Subject: [PATCH 031/275] Bring preview.5 release fixes to release/v7.5 (#24379) * added ks2 to release pipeline * Merged PR 32752: Copy global tools to static site Rather than an intermediate folder that must be manually copied into the static site. ---- #### AI description (iteration 1) #### PR Classification Code modification to enhance functionality. #### PR Summary This pull request updates the release pipeline to copy global tools to a static site. - Changes in `/.pipelines/templates/release-MakeBlobPublic.yml` to set `prefix` and `destinationPrefix` for blob copying. - Adjusted destination container name to use `$web` and updated blob naming conventions. * Merged PR 32759: Switch to single quotes for container name in global tool copy #### AI description (iteration 1) #### PR Classification Code cleanup #### PR Summary This pull request updates the container name string to use single quotes for consistency. - Changes in `/.pipelines/templates/release-MakeBlobPublic.yml` to switch `$destinationContainerName` from double quotes to single quotes. * Added condition for make blob public * moved conditional from global tools to copy * conditional as a paramter instead of var * removed dependency * blob folder name to release Tag --------- Co-authored-by: Justin Chung Co-authored-by: Patrick Meinecke --- .pipelines/PowerShell-Release-Official.yml | 12 +++++++ .../templates/release-MakeBlobPublic.yml | 33 +++++++++++-------- .pipelines/templates/release-publish-pmc.yml | 2 +- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index eb21b407ba7..2538d1b5370 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -21,6 +21,10 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip PMC Publish type: boolean default: false + - name: SkipPSInfraInstallers + displayName: Skip Copying Archives and Installers to PSInfrastructure Public Location + type: boolean + default: false variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -75,6 +79,12 @@ resources: extends: template: v2/OneBranch.Official.CrossPlat.yml@templates parameters: + # still using KS2 because we are not yet using a Box Product Deployment + featureFlags: + LinuxHostVersion: + Network: KS2 + WindowsHostVersion: + Network: KS2 cloudvault: enabled: false globalSdl: @@ -257,6 +267,8 @@ extends: dependsOn: UpdateChangeLog jobs: - template: /.pipelines/templates/release-MakeBlobPublic.yml@self + parameters: + SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} - stage: PublishGitHubRelease displayName: Publish GitHub Release diff --git a/.pipelines/templates/release-MakeBlobPublic.yml b/.pipelines/templates/release-MakeBlobPublic.yml index 52b3476d1e3..f9afbebb909 100644 --- a/.pipelines/templates/release-MakeBlobPublic.yml +++ b/.pipelines/templates/release-MakeBlobPublic.yml @@ -1,3 +1,9 @@ +parameters: + - name: SkipPSInfraInstallers + displayName: Skip Copying Archives and Installers to PSInfrastructure Public Location + type: boolean + default: false + jobs: - template: /.pipelines/templates/approvalJob.yml@self parameters: @@ -9,6 +15,7 @@ jobs: - job: PSInfraReleaseBlobPublic displayName: Copy release to PSInfra storage dependsOn: CopyReleaseBlobApproval + condition: and(succeeded(), ne('${{ parameters.SkipPSInfraInstallers }}', true)) pool: type: windows @@ -99,7 +106,6 @@ jobs: parameters: displayName: Approve Copy Global tool packages to PSInfra storage jobName: CopyBlobApproval - dependsOnJob: PSInfraReleaseBlobPublic instructions: | Approval for Copy global tool packages to PSInfra storage @@ -110,14 +116,14 @@ jobs: type: windows variables: - - group: 'PSInfraStorage' - - group: 'Azure Blob variable group' - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - group: 'PSInfraStorage' + - group: 'Azure Blob variable group' + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json steps: - checkout: self @@ -156,9 +162,11 @@ jobs: inline: | $sourceStorageAccountName = '$(StorageAccount)' $sourceContainerName = '$(AzureVersion)-nuget' + $prefix = 'globaltool' $destinationStorageAccountName = '$(PSInfraStorageAccount)' - $destinationContainerName = "tool" + $destinationContainerName = '$web' + $destinationPrefix = 'tool/$(Version)' $sourceContext = New-AzStorageContext -StorageAccountName $sourceStorageAccountName Write-Verbose -Verbose "Source context: $($sourceContext.BlobEndPoint)" @@ -166,19 +174,18 @@ jobs: $destinationContext = New-AzStorageContext -StorageAccountName $destinationStorageAccountName Write-Verbose -Verbose "Destination context: $($destinationContext.BlobEndPoint)" - $prefix = 'globaltool' $blobs = Get-AzStorageBlob -Context $sourceContext -Container $sourceContainerName -Prefix $prefix Write-Verbose -Verbose "Blobs found in $sourceContainerName" $blobs.Name | Write-Verbose -Verbose - Write-Verbose -Verbose "Copying blobs from $sourceContainerName to $destinationContainerName" + Write-Verbose -Verbose "Copying blobs from $sourceContainerName to $destinationContainerName/$destinationPrefix" foreach ($blob in $blobs) { $sourceBlobName = $blob.Name Write-Verbose -Verbose "sourceBlobName = $sourceBlobName" - $destinationBlobName = $sourceBlobName -replace "$prefix", '$(Version)' + $destinationBlobName = $sourceBlobName -replace "$prefix", $destinationPrefix Write-Verbose -Verbose "destinationBlobName = $destinationBlobName" Copy-AzStorageBlob -SourceContext $sourceContext -DestinationContext $destinationContext -SrcContainer $sourceContainerName -SrcBlob $sourceBlobName -DestContainer $destinationContainerName -DestBlob $destinationBlobName -Force -Verbose -Confirm:$false diff --git a/.pipelines/templates/release-publish-pmc.yml b/.pipelines/templates/release-publish-pmc.yml index 93032f35b3b..27311611e61 100644 --- a/.pipelines/templates/release-publish-pmc.yml +++ b/.pipelines/templates/release-publish-pmc.yml @@ -77,7 +77,7 @@ jobs: $params = @{ ReleaseTag = "$(ReleaseTag)" AadClientId = "$(PmcCliClientID)" - BlobFolderName = "$(AzureVersion)" + BlobFolderName = "$(ReleaseTag)" LTS = $metadata.LTSRelease.Latest ForProduction = $true SkipPublish = $${{ parameters.skipPublish }} From 30b9b9ddbfaada7dbc94e28bd508c6a129c630ba Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 10 Oct 2024 12:28:43 -0700 Subject: [PATCH 032/275] Revert "Add windows signing for pwsh.exe (#24219) (#24306)" (#24408) This reverts commit f0461bc00f673ac20c2531d3006813ba692e7ba1. --- .pipelines/templates/obp-file-signing.yml | 25 ----------------------- 1 file changed, 25 deletions(-) diff --git a/.pipelines/templates/obp-file-signing.yml b/.pipelines/templates/obp-file-signing.yml index 7ed973ddf5a..ba761633b29 100644 --- a/.pipelines/templates/obp-file-signing.yml +++ b/.pipelines/templates/obp-file-signing.yml @@ -84,31 +84,6 @@ steps: files_to_sign: '**\*.psd1;**\*.psm1;**\*.ps1xml;**\*.ps1;**\*.dll;**\*.exe;**\pwsh' search_root: $(Pipeline.Workspace)/toBeSigned -- task: onebranch.pipeline.signing@1 - displayName: Sign pwsh.exe with Windows cert - inputs: - command: 'sign' - cp_code: '203' - files_to_sign: '**\pwsh.exe' - search_root: $(Pipeline.Workspace)/toBeSigned - -- pwsh: | - if (Test-Path $(Pipeline.Workspace)/toBeSigned/pwsh.exe) { - Write-Verbose -Verbose "pwsh.exe is found, verifying signature" - $signature = Get-AuthenticodeSignature -FilePath $(Pipeline.Workspace)/toBeSigned/pwsh.exe - if ($signature.SignerCertificate.Issuer -notmatch '^CN=Microsoft Windows Production.*') { - Write-Error -ErrorAction Stop "pwsh.exe is not signed by Microsoft" - } - else { - Write-Verbose -Verbose "pwsh.exe is signed by Microsoft" - } - } - else { - Write-Verbose -Verbose "pwsh.exe is not found, skipping" - } - - displayName: 'Verify windows signature' - - pwsh : | Get-ChildItem -Path env: displayName: Capture environment From d50eeea479811b752be87ebacae0dd7c9e3dcd0d Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 30 Oct 2024 20:57:41 -0700 Subject: [PATCH 033/275] Fix seed max value for Container Linux CI (#24510) (#24511) --- tools/ci.psm1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 73c6cb41e83..6628d54e043 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -863,11 +863,17 @@ function Invoke-InitializeContainerStage { # For PRs set the seed to the PR number so that the image is always the same $seed = $env:SYSTEM_PULLREQUEST_PULLREQUESTID + if(!$seed) { # for non-PRs use the integer identifier of the build as the seed. $seed = $fallbackSeed } + # cut down to 32 bits and keep the most varying parts, which are lower bits + if ($seed -ge [Int32]::MaxValue) { + $seed = [int]($seed -band [int]::MaxValue) + } + Write-Verbose "Seed: $seed" -Verbose # Get the latest image matrix JSON for preview From ff03706831da454567f4077fbb1a2c80eee21cac Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 30 Oct 2024 23:10:21 -0700 Subject: [PATCH 034/275] Update package references (#24414) (#24513) --- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 4 ++-- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +++++----- .../Microsoft.WSMan.Management.csproj | 2 +- .../PSVersionInfoGenerator.csproj | 2 +- .../System.Management.Automation.csproj | 20 +++++++++---------- test/tools/TestService/TestService.csproj | 4 ++-- 9 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 9f36b8134d1..34502ced25d 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 695ed6f21e4..4f20755c6e6 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 113d62231f0..dd2bf636955 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -33,8 +33,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 1296b1e28ba..003999e97b3 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 34c462edbd4..5a1001ddc2c 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -17,13 +17,13 @@ - + - - - + + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 9a8f4973d1a..77aa3cef77c 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - +
diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index fe82962adca..228126c3267 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -15,6 +15,6 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index e4b0c5d7e48..cefbbfa31f0 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -19,9 +19,7 @@ - + @@ -34,16 +32,16 @@ - - - - + + + + - + - - - + + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index f6ca75e1dae..56b17f3d7bc 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,8 +15,8 @@ - - + + From 81e916c1c0894dd6d7351829e8a13e7da83dfa6c Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 30 Oct 2024 23:17:18 -0700 Subject: [PATCH 035/275] Update vpack pipeline (#24281) (#24514) --- .pipelines/PowerShell-vPack-Official.yml | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index bb780a6f203..91735669d99 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -82,19 +82,14 @@ extends: enabled: true scanFolder: $(Build.SourcesDirectory) suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json - asyncSdl: - enabled: true - forStages: ['main'] - credscan: - enabled: true - scanFolder: $(Build.SourcesDirectory) - suppressionsFile: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - binskim: - enabled: false - # APIScan requires a non-Ready-To-Run build - apiscan: - enabled: false - tsaOptionsFile: .config/tsaoptions.json + binskim: + enabled: false + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + asyncSDL: + enabled: false + tsaOptionsFile: .config/tsaoptions.json stages: - stage: main jobs: From c22f576a49f7dc1771f131cfb8d9973852371a62 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 30 Oct 2024 23:17:44 -0700 Subject: [PATCH 036/275] Add CodeQL scanning to APIScan build (#24303) (#24515) --- .pipelines/apiscan-gen-notice.yml | 32 +++++++++- .pipelines/templates/compliance/apiscan.yml | 68 ++++++++++++--------- 2 files changed, 69 insertions(+), 31 deletions(-) diff --git a/.pipelines/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml index 02ab4ba3796..f469a49eef5 100644 --- a/.pipelines/apiscan-gen-notice.yml +++ b/.pipelines/apiscan-gen-notice.yml @@ -1,8 +1,14 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. - +name: apiscan-genNotice-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) trigger: none +parameters: + - name: FORCE_CODEQL + displayName: Debugging - Enable CodeQL and set cadence to 1 hour + type: boolean + default: false + variables: - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' @@ -17,6 +23,24 @@ variables: value: onebranch.azurecr.io/linux/ubuntu-2004:latest - name: WindowsContainerImage value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest + - ${{ if eq(parameters['FORCE_CODEQL'],'true') }}: + # Cadence is hours before CodeQL will allow a re-upload of the database + - name: CodeQL.Cadence + value: 0 + - name: CODEQL_ENABLED + ${{ if or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(parameters['FORCE_CODEQL'],'true')) }}: + value: true + ${{ else }}: + value: false + - name: Codeql.TSAEnabled + value: $(CODEQL_ENABLED) + # AnalyzeInPipeline: false = upload results + # AnalyzeInPipeline: true = do not upload results + - name: Codeql.AnalyzeInPipeline + ${{ if or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(parameters['FORCE_CODEQL'],'true')) }}: + value: false + ${{ else }}: + value: true resources: repositories: @@ -32,8 +56,10 @@ extends: WindowsHostVersion: Version: 2022 globalSdl: - compiled: - enabled: true + codeql: + compiled: + enabled: $(CODEQL_ENABLED) + tsaEnabled: $(CODEQL_ENABLED) # This enables TSA bug filing only for CodeQL 3000 armory: enabled: false sbom: diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml index a96471aecd9..b30d72f6a56 100644 --- a/.pipelines/templates/compliance/apiscan.yml +++ b/.pipelines/templates/compliance/apiscan.yml @@ -4,34 +4,36 @@ jobs: - job: APIScan variables: - - name: runCodesignValidationInjection - value : false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: ReleaseTagVar - value: fromBranch - # Defines the variables APIScanClient, APIScanTenant and APIScanSecret - - group: PS-PS-APIScan - # PAT permissions NOTE: Declare a SymbolServerPAT variable in this group with a 'microsoft' organizanization scoped PAT with 'Symbols' Read permission. - # A PAT in the wrong org will give a single Error 203. No PAT will give a single Error 401, and individual pdbs may be missing even if permissions are correct. - - group: symbols - - name: branchCounterKey - value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] - - name: branchCounter - value: $[counter(variables['branchCounterKey'], 1)] - - group: DotNetPrivateBuildAccess - - group: Azure Blob variable group - - group: ReleasePipelineSecrets - - group: mscodehub-feed-read-general - - group: mscodehub-feed-read-akv - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: repoRoot - value: '$(Build.SourcesDirectory)\PowerShell' - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: runCodesignValidationInjection + value : false + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: ReleaseTagVar + value: fromBranch + # Defines the variables APIScanClient, APIScanTenant and APIScanSecret + - group: PS-PS-APIScan + # PAT permissions NOTE: Declare a SymbolServerPAT variable in this group with a 'microsoft' organizanization scoped PAT with 'Symbols' Read permission. + # A PAT in the wrong org will give a single Error 203. No PAT will give a single Error 401, and individual pdbs may be missing even if permissions are correct. + - group: symbols + - name: branchCounterKey + value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] + - name: branchCounter + value: $[counter(variables['branchCounterKey'], 1)] + - group: DotNetPrivateBuildAccess + - group: Azure Blob variable group + - group: ReleasePipelineSecrets + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: repoRoot + value: '$(Build.SourcesDirectory)\PowerShell' + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: Codeql.SourceRoot + value: $(repoRoot) pool: type: windows @@ -119,6 +121,12 @@ jobs: workingDirectory: '$(repoRoot)' condition: succeededOrFailed() + - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. + displayName: 🔏 CodeQL 3000 Init + condition: eq(variables['CODEQL_ENABLED'], 'true') + inputs: + Language: csharp + - pwsh: | Import-Module .\build.psm1 -force Find-DotNet @@ -136,6 +144,10 @@ jobs: workingDirectory: '$(repoRoot)' displayName: 'Build PowerShell Source' + - task: CodeQL3000Finalize@0 # Add CodeQL Finalize task right after your 'Build' step. + displayName: 🔏 CodeQL 3000 Finalize + condition: eq(variables['CODEQL_ENABLED'], 'true') + - pwsh: | Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose workingDirectory: '$(repoRoot)' From 3c2d60eafd2d7bc34c26ad8754fc8b9e563e8a31 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 30 Oct 2024 23:18:01 -0700 Subject: [PATCH 037/275] Delete the msix blob if it's already there (#24353) (#24516) --- .pipelines/templates/release-create-msix.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/release-create-msix.yml b/.pipelines/templates/release-create-msix.yml index 89f2e7b5a2c..448a46c1194 100644 --- a/.pipelines/templates/release-create-msix.yml +++ b/.pipelines/templates/release-create-msix.yml @@ -104,8 +104,14 @@ jobs: if ($env:BundleDir) { $bundleFile = Get-Item "$env:BundleDir\*.msixbundle" $blobName = $bundleFile | Split-Path -Leaf + $existing = Get-AzStorageBlob -Container $containerName -Blob $blobName -Context $storageContext -ErrorAction Ignore + if ($existing) { + Write-Verbose -Verbose "MSIX bundle already exists at '$storageAccount/$containerName/$blobName', removing first." + $existingBlob | Remove-AzStorageBlob -ErrorAction Stop -Verbose + } + Write-Verbose -Verbose "Uploading $bundleFile to $containerName/$blobName" - Set-AzStorageBlobContent -File $bundleFile -Container $containerName -Blob $blobName -Context $storageContext + Set-AzStorageBlobContent -File $bundleFile -Container $containerName -Blob $blobName -Context $storageContext -Force } else{ throw "BundleDir not found" From 8dfb52184663731ed3d1ab0f423231dbed3b7e41 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 30 Oct 2024 23:18:40 -0700 Subject: [PATCH 038/275] Download package from package build for generating vpack (#24481) (#24521) --- .pipelines/PowerShell-vPack-Official.yml | 31 +++++++++++++----------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 91735669d99..33eddc88d0e 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -59,6 +59,15 @@ resources: name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main + pipelines: + - pipeline: PSPackagesOfficial + source: 'PowerShell-Packages-Official' + trigger: + branches: + include: + - master + - releases/* + extends: template: v2/Microsoft.Official.yml@templates parameters: @@ -129,21 +138,15 @@ extends: installationPath: $(Agent.ToolsDirectory)/dotnet - pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/build.psm1' - Install-AzCopy - displayName: Install AzCopy - retryCountOnTaskFailure: 2 + $packageArtifactName = 'drop_windows_package_package_${{ parameters.architecture }}' + $vstsCommandString = "vso[task.setvariable variable=PackageArtifactName]$packageArtifactName" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: 'Set package artifact name' - - pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/build.psm1' - $azcopy = Find-AzCopy - Write-Verbose -Verbose "Found AzCopy: $azcopy" - Write-Host "running: $azcopy cp https://$(StorageAccount).blob.core.windows.net/$(AzureVersion)/PowerShell-$(Version)-win-${{ parameters.architecture }}.zip $(System.ArtifactsDirectory)" - & $azcopy cp https://$(StorageAccount).blob.core.windows.net/$(AzureVersion)/PowerShell-$(Version)-win-${{ parameters.architecture }}.zip $(System.ArtifactsDirectory) - displayName: 'Download Azure Artifacts' - retryCountOnTaskFailure: 2 - env: - AZCOPY_AUTO_LOGIN_TYPE: MSI + - download: PSPackagesOfficial + artifact: $(PackageArtifactName) + displayName: Download package - pwsh: 'Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty Name' displayName: 'Capture Artifact Listing' From 7649d338f7599dee20b4b466990167bf16ef8e44 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 31 Oct 2024 09:14:24 -0700 Subject: [PATCH 039/275] Update PSReadLine to 2.3.6 (#24380) (#24517) --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index 1c8e5e64356..e105facf8e4 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -15,7 +15,7 @@ - + From afd21a32c1d083b9beeb2c8a803bbd3fe794671d Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 31 Oct 2024 09:15:11 -0700 Subject: [PATCH 040/275] Checkin generated manpage (#24423) (#24519) --- .vsts-ci/mac.yml | 17 +++++++++++++++++ assets/manpage/pwsh.1 | 10 ++++++++++ assets/{ => manpage}/pwsh.1.ronn | 0 build.psm1 | 3 +-- tools/packaging/packaging.psm1 | 27 ++++++++------------------- 5 files changed, 36 insertions(+), 21 deletions(-) create mode 100644 assets/manpage/pwsh.1 rename assets/{ => manpage}/pwsh.1.ronn (100%) diff --git a/.vsts-ci/mac.yml b/.vsts-ci/mac.yml index 9e297cf4ae6..bfb0b3afd21 100644 --- a/.vsts-ci/mac.yml +++ b/.vsts-ci/mac.yml @@ -96,3 +96,20 @@ stages: parameters: pool: macOS-latest +- stage: PackageMac + dependsOn: ['BuildMac'] + displayName: Package macOS (bootstrap only) + jobs: + - job: macos_packaging + pool: + vmImage: macOS-latest + + displayName: macOS packaging (bootstrap only) + steps: + - checkout: self + clean: true + - pwsh: | + import-module ./build.psm1 + start-psbootstrap -package + displayName: Bootstrap packaging + condition: succeededOrFailed() diff --git a/assets/manpage/pwsh.1 b/assets/manpage/pwsh.1 new file mode 100644 index 00000000000..14c191241a9 --- /dev/null +++ b/assets/manpage/pwsh.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "PWSH" "1" "October 2023" "" "" +. +.SH "NAME" +\fBpwsh\fR \- PowerShell command\-line shell and \.NET REPL +. +.SH "SYNOPSIS" +\fBpwsh\fR [\fB\-Login\fR] [ [\fB\-File\fR] \fIfilePath\fR [args] ] [\fB\-Command\fR { \- | \fIscript\-block\fR [\fB\-args\fR \fIarg\-array\fR] | \fIstring\fR [\fICommandParameters\fR] } ] [\fB\-ConfigurationFile\fR \fIfilePath\fR] [\fB\-ConfigurationName\fR \fIstring\fR] [\fB\-CustomPipeName\fR \fIstring\fR] [\fB\-EncodedArguments\fR \fIBase64EncodedArguments\fR] [\fB\-EncodedCommand\fR \fIBase64EncodedCommand\fR] [\fB\-ExecutionPolicy\fR \fIExecutionPolicy\fR] [\fB\-Help\fR] [\fB\-InputFormat\fR {Text | XML}] [\fB\-Interactive\fR] [\fB\-MTA\fR] [\fB\-NoExit\fR] [\fB\-NoLogo\fR] [\fB\-NonInteractive\fR] [\fB\-NoProfile\fR] [\fB\-NoProfileLoadTime\fR] [\fB\-OutputFormat\fR {Text | XML}] [\fB\-SettingsFile\fR \fIfilePath\fR] [\fB\-SSHServerMode\fR] [\fB\-STA\fR] [\fB\-Version\fR] [\fB\-WindowStyle\fR diff --git a/assets/pwsh.1.ronn b/assets/manpage/pwsh.1.ronn similarity index 100% rename from assets/pwsh.1.ronn rename to assets/manpage/pwsh.1.ronn diff --git a/build.psm1 b/build.psm1 index 2d038367713..7855e46ac1a 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2333,12 +2333,11 @@ function Start-PSBootstrap { } } - # Install [fpm](https://github.com/jordansissel/fpm) and [ronn](https://github.com/rtomayko/ronn) + # Install [fpm](https://github.com/jordansissel/fpm) if ($Package) { Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.16.3" Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" - Install-GlobalGem -Sudo $sudo -GemName "ronn" -GemVersion "0.7.3" Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5" } } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 1c3686591f0..95caafede8d 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1636,7 +1636,7 @@ function Get-PackageDependencies function Test-Dependencies { - foreach ($Dependency in "fpm", "ronn") { + foreach ($Dependency in "fpm") { if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Package")) { # These tools are not added to the path automatically on OpenSUSE 13.2 # try adding them to the path and re-tesing first @@ -1714,26 +1714,15 @@ function New-ManGzip ) Write-Log "Creating man gz..." - # run ronn to convert man page to roff - $RonnFile = "$RepoRoot/assets/pwsh.1.ronn" - if ($IsPreview.IsPresent -or $IsLTS.IsPresent) - { - $prodName = if ($IsLTS) { 'pwsh-lts' } else { 'pwsh-preview' } - $newRonnFile = $RonnFile -replace 'pwsh', $prodName - Copy-Item -Path $RonnFile -Destination $newRonnFile -Force - $RonnFile = $newRonnFile - } - - $RoffFile = $RonnFile -replace "\.ronn$" + # run roff to convert man page to roff + $RoffFile = "$RepoRoot/assets/manpage/pwsh.1" - # Run ronn on assets file - Write-Log "Creating man gz - running ronn..." - Start-NativeExecution { ronn --roff $RonnFile } - - if ($IsPreview.IsPresent) - { - Remove-Item $RonnFile + if ($IsPreview.IsPresent -or $IsLTS.IsPresent) { + $prodName = if ($IsLTS) { 'pwsh-lts' } else { 'pwsh-preview' } + $newRoffFile = $RoffFile -replace 'pwsh', $prodName + Copy-Item -Path $RoffFile -Destination $newRoffFile -Force -Verbose + $RoffFile = $newRoffFile } # gzip in assets directory From 82cefa6f198c4208e9c4c9f6caab1a8180af092b Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 31 Oct 2024 09:15:40 -0700 Subject: [PATCH 041/275] Keep the roff file when gzipping it. (#24450) (#24520) --- .gitignore | 3 +++ tools/packaging/packaging.psm1 | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 13d3a89b888..cb12a297984 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,6 @@ nuget.config # Ignore MSBuild Binary Logs msbuild.binlog + +# Ignore gzip files in the manpage folder +assets/manpage/*.gz diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 95caafede8d..6e88df19dec 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1728,7 +1728,7 @@ function New-ManGzip # gzip in assets directory $GzipFile = "$RoffFile.gz" Write-Log "Creating man gz - running gzip..." - Start-NativeExecution { gzip -f $RoffFile } -VerboseOutputOnError + Start-NativeExecution { gzip -kf $RoffFile } -VerboseOutputOnError $ManFile = Join-Path "/usr/local/share/man/man1" (Split-Path -Leaf $GzipFile) From 23a8da2748106d24550570b0ec62a97cb22231a9 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 31 Oct 2024 09:15:59 -0700 Subject: [PATCH 042/275] Bump .NET to 9.0.100-rc.2.24474.11 (#24509) (#24522) --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 0519736ab95..2dd360f846e 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.100-rc.1.24452.12" + "version": "9.0.100-rc.2.24474.11" } } From f6c8dfc8f5b1ac452c7e6eaacde9b68e4683b49d Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 31 Oct 2024 09:21:21 -0700 Subject: [PATCH 043/275] Add PMC mapping for debian 12 (bookworm) (#24413) (#24518) Co-authored-by: Anam Navied --- tools/packages.microsoft.com/mapping.json | 35 ++++++++++++++--------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/tools/packages.microsoft.com/mapping.json b/tools/packages.microsoft.com/mapping.json index b3753722a59..682c96d9110 100644 --- a/tools/packages.microsoft.com/mapping.json +++ b/tools/packages.microsoft.com/mapping.json @@ -127,19 +127,26 @@ ], "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" }, - { - "url": "microsoft-ubuntu-xenial-prod", - "distribution": [ - "xenial" - ], - "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" - }, - { - "url": "microsoft-debian-bullseye-prod", - "distribution": [ - "bullseye" - ], - "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" - } + { + "url": "microsoft-ubuntu-xenial-prod", + "distribution": [ + "xenial" + ], + "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" + }, + { + "url": "microsoft-debian-bullseye-prod", + "distribution": [ + "bullseye" + ], + "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" + }, + { + "url": "microsoft-debian-bookworm-prod", + "distribution": [ + "bookworm" + ], + "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" + } ] } From 9432b4500f5e0a9a2751d182ea8d33c3390adfaa Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 31 Oct 2024 10:01:09 -0700 Subject: [PATCH 044/275] Update PSResourceGet to v1.1.0-RC2 (#24512) (#24525) --- src/Modules/PSGalleryModules.csproj | 2 +- tools/packaging/boms/windows.json | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index e105facf8e4..9df1121f38b 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index c467adbbfa9..c9fd280930f 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -787,14 +787,6 @@ "Pattern": "Microsoft.WSMan.Runtime.xml", "FileType": "NonProduct" }, - { - "Pattern": "Modules/*.json", - "FileType": "NonProduct" - }, - { - "Pattern": "Modules/*.sha256", - "FileType": "NonProduct" - }, { "Pattern": "Modules/Microsoft.PowerShell.Archive/*.cat", "FileType": "NonProduct" @@ -900,7 +892,11 @@ "FileType": "NonProduct" }, { - "Pattern": "Modules\\PSReadLine\\_manifest\\spdx_2.2\\manifest.cat", + "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\PSResourceRepository.adml", + "FileType": "NonProduct" + }, + { + "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\PSResourceRepository.admx", "FileType": "NonProduct" }, { @@ -3455,6 +3451,10 @@ "Pattern": "Modules/PSDiagnostics/PSDiagnostics.psm1", "FileType": "Product" }, + { + "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\InstallPSResourceGetPolicyDefinitions.ps1", + "FileType": "Product" + }, { "Pattern": "pwsh.dll", "FileType": "Product" From 4020aac7a69a7e3706c920eff2102f8c74e48f24 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 31 Oct 2024 13:38:26 -0700 Subject: [PATCH 045/275] Revert "Update package references (#24414)" (#24532) (#24533) This reverts commit 01ae63263661351c812c8ab5fee3a6cceaa559c0. --- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 4 ++-- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +++++----- .../Microsoft.WSMan.Management.csproj | 2 +- .../PSVersionInfoGenerator.csproj | 2 +- .../System.Management.Automation.csproj | 20 ++++++++++--------- test/tools/TestService/TestService.csproj | 4 ++-- 9 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 34502ced25d..9f36b8134d1 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 4f20755c6e6..695ed6f21e4 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index dd2bf636955..113d62231f0 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -33,8 +33,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 003999e97b3..1296b1e28ba 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 5a1001ddc2c..34c462edbd4 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -17,13 +17,13 @@ - + - - - + + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 77aa3cef77c..9a8f4973d1a 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index 228126c3267..fe82962adca 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -15,6 +15,6 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index cefbbfa31f0..e4b0c5d7e48 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -19,7 +19,9 @@ - + @@ -32,16 +34,16 @@ - - - - + + + + - + - - - + + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 56b17f3d7bc..f6ca75e1dae 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,8 +15,8 @@ - - + + From 8b94694726594b60cb015bdbed7eaad7dc70ee30 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 31 Oct 2024 14:05:37 -0700 Subject: [PATCH 046/275] Add a way to use only NuGet feed sources (#24528) (#24530) --- build.psm1 | 15 +++++++++------ nuget.config | 2 +- src/Modules/nuget.config | 2 +- test/tools/Modules/nuget.config | 2 +- tools/findMissingNotices.ps1 | 6 ++++-- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/build.psm1 b/build.psm1 index 7855e46ac1a..e21194c9af9 100644 --- a/build.psm1 +++ b/build.psm1 @@ -740,7 +740,7 @@ function Switch-PSNugetConfig { param( [Parameter(Mandatory = $true, ParameterSetName = 'user')] [Parameter(Mandatory = $true, ParameterSetName = 'nouser')] - [ValidateSet('Public', 'Private')] + [ValidateSet('Public', 'Private', 'NuGetOnly')] [string] $Source, [Parameter(Mandatory = $true, ParameterSetName = 'user')] @@ -760,16 +760,19 @@ function Switch-PSNugetConfig { } } + $dotnetSdk = [NugetPackageSource] @{Url = 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet9/nuget/v2'; Name = 'dotnet' } + $gallery = [NugetPackageSource] @{Url = 'https://www.powershellgallery.com/api/v2/'; Name = 'psgallery' } + $nugetorg = [NugetPackageSource] @{Url = 'https://api.nuget.org/v3/index.json'; Name = 'nuget.org' } if ( $Source -eq 'Public') { - $dotnetSdk = [NugetPackageSource] @{Url = 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet9/nuget/v2'; Name = 'dotnet' } - $gallery = [NugetPackageSource] @{Url = 'https://www.powershellgallery.com/api/v2/'; Name = 'psgallery' } - $nugetorg = [NugetPackageSource] @{Url = 'https://api.nuget.org/v3/index.json'; Name = 'nuget.org' } - New-NugetConfigFile -NugetPackageSource $nugetorg, $dotnetSdk -Destination "$PSScriptRoot/" @extraParams New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/src/Modules/" @extraParams New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/test/tools/Modules/" @extraParams + } elseif ( $Source -eq 'NuGetOnly') { + New-NugetConfigFile -NugetPackageSource $nugetorg -Destination "$PSScriptRoot/" @extraParams + New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/src/Modules/" @extraParams + New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/test/tools/Modules/" @extraParams } elseif ( $Source -eq 'Private') { - $powerShellPackages = [NugetPackageSource] @{Url = 'https://pkgs.dev.azure.com/powershell/PowerShell/_packaging/PowerShell-7-5-preview-test-2/nuget/v3/index.json'; Name = 'powershell' } + $powerShellPackages = [NugetPackageSource] @{Url = 'https://pkgs.dev.azure.com/powershell/PowerShell/_packaging/PowerShell/nuget/v3/index.json'; Name = 'powershell' } New-NugetConfigFile -NugetPackageSource $powerShellPackages -Destination "$PSScriptRoot/" @extraParams New-NugetConfigFile -NugetPackageSource $powerShellPackages -Destination "$PSScriptRoot/src/Modules/" @extraParams diff --git a/nuget.config b/nuget.config index db65daa061e..388a65572dd 100644 --- a/nuget.config +++ b/nuget.config @@ -2,7 +2,7 @@ - + diff --git a/src/Modules/nuget.config b/src/Modules/nuget.config index db65daa061e..388a65572dd 100644 --- a/src/Modules/nuget.config +++ b/src/Modules/nuget.config @@ -2,7 +2,7 @@ - + diff --git a/test/tools/Modules/nuget.config b/test/tools/Modules/nuget.config index 3ca2bee3c18..388a65572dd 100644 --- a/test/tools/Modules/nuget.config +++ b/test/tools/Modules/nuget.config @@ -2,7 +2,7 @@ - + diff --git a/tools/findMissingNotices.ps1 b/tools/findMissingNotices.ps1 index 2915853ec38..490edebb81b 100644 --- a/tools/findMissingNotices.ps1 +++ b/tools/findMissingNotices.ps1 @@ -26,7 +26,9 @@ $existingRegistrationsJson.Registrations | ForEach-Object { $registration = [Registration]$_ if ($registration.Component) { $name = $registration.Component.Name() - $existingRegistrationTable.Add($name, $registration) + if (!$existingRegistrationTable.ContainsKey($name)) { + $existingRegistrationTable.Add($name, $registration) + } } } @@ -103,7 +105,7 @@ function ConvertTo-SemVer { So, I'm making the logic work for that scenario by thorwing away any part that doesn't match non-pre-release semver portion #> - $null = $Version -match '^(\d+\.\d+\.\d+)).*' + $null = $Version -match '^(\d+\.\d+\.\d+).*' $desiredVersion = $matches[1] } From 0fe4b9fffc75fbb924b02f37a41548f1d0e5ab0b Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:09:49 -0700 Subject: [PATCH 047/275] Update branch for release (#24535) --- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 18 ++- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 23 +++- .../Microsoft.WSMan.Management.csproj | 2 +- .../PSVersionInfoGenerator.csproj | 7 +- .../System.Management.Automation.csproj | 24 ++-- .../BenchmarkDotNet.Extensions.csproj | 11 +- .../dotnet-tools/Reporting/Reporting.csproj | 3 +- .../ResultsComparer/ResultsComparer.csproj | 10 +- .../engine/Module/IsolatedModule.Tests.ps1 | 3 + ...soft.PowerShell.NamedPipeConnection.csproj | 15 ++- .../TestAlc/init/Test.Isolated.Init.csproj | 4 +- .../nested/Test.Isolated.Nested.csproj | 11 +- .../TestAlc/root/Test.Isolated.Root.csproj | 4 +- test/tools/TestService/TestService.csproj | 35 +++++- test/tools/WebListener/WebListener.csproj | 5 +- test/xUnit/xUnit.tests.csproj | 20 +++- tools/cgmanifest.json | 108 ++++++------------ 20 files changed, 186 insertions(+), 123 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 9f36b8134d1..34502ced25d 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 695ed6f21e4..4f20755c6e6 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 113d62231f0..9b61bb2b53d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -7,8 +7,16 @@ + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + - + @@ -32,10 +40,10 @@ - - - - + + + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 1296b1e28ba..003999e97b3 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 34c462edbd4..03898ace0d3 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -17,13 +17,25 @@ - + + + + + + + + - - - + + + + + + + + - + + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 9a8f4973d1a..77aa3cef77c 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index fe82962adca..9de256a3ba1 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -14,7 +14,10 @@ - - + + + + + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index e4b0c5d7e48..6fce6d93111 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -19,9 +19,7 @@ - + @@ -34,21 +32,25 @@ - - - - + + + + + + - + - - - + + + + + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 2a398dad179..47dc5733932 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -6,8 +6,15 @@ - - + + + + + + + + + diff --git a/test/perf/dotnet-tools/Reporting/Reporting.csproj b/test/perf/dotnet-tools/Reporting/Reporting.csproj index 70447cf5d73..693cc1b6481 100644 --- a/test/perf/dotnet-tools/Reporting/Reporting.csproj +++ b/test/perf/dotnet-tools/Reporting/Reporting.csproj @@ -6,7 +6,8 @@ - + + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index a8b48dde151..02f7255bcdb 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -6,10 +6,16 @@ 11.0 + + + + + - - + + + diff --git a/test/powershell/engine/Module/IsolatedModule.Tests.ps1 b/test/powershell/engine/Module/IsolatedModule.Tests.ps1 index 5d1289271de..00dae01838c 100644 --- a/test/powershell/engine/Module/IsolatedModule.Tests.ps1 +++ b/test/powershell/engine/Module/IsolatedModule.Tests.ps1 @@ -3,6 +3,9 @@ Describe "Isolated module scenario - load the whole module in custom ALC" -Tag 'CI' { It "Loading 'IsolatedModule' should work as expected" { + + Set-ItResult -Pending -Because "The test is failing as we cannot depend on Newtonsoft.Json v10.0.0 as it has security vulnerabilities." + ## The 'IsolatedModule' module can be found at '\test\tools\Modules'. ## The module assemblies are created and deployed by '\test\tools\TestAlc'. ## The module defines its own custom ALC and has its module structure organized in a special way that allows the module to be loaded in that custom ALC. diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index aa50d6ec179..d6cc1071790 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -14,7 +14,20 @@ + - + + + + + + + + + + + + + diff --git a/test/tools/TestAlc/init/Test.Isolated.Init.csproj b/test/tools/TestAlc/init/Test.Isolated.Init.csproj index c1a291fa550..c8d37ac959a 100644 --- a/test/tools/TestAlc/init/Test.Isolated.Init.csproj +++ b/test/tools/TestAlc/init/Test.Isolated.Init.csproj @@ -1,6 +1,6 @@ - + @@ -15,7 +15,7 @@ - + diff --git a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj index 85ea03a9c4f..483ae9267fb 100644 --- a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj +++ b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj @@ -1,6 +1,6 @@ - + @@ -16,8 +16,13 @@ - - + + + + + + + diff --git a/test/tools/TestAlc/root/Test.Isolated.Root.csproj b/test/tools/TestAlc/root/Test.Isolated.Root.csproj index ab333e0668a..2a757064167 100644 --- a/test/tools/TestAlc/root/Test.Isolated.Root.csproj +++ b/test/tools/TestAlc/root/Test.Isolated.Root.csproj @@ -1,6 +1,6 @@ - + @@ -15,7 +15,7 @@ - + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index f6ca75e1dae..10bf8593408 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -1,6 +1,6 @@ - + Very tiny windows service to do service testing @@ -15,9 +15,38 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 791be2fd228..d3e8a1f3244 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,7 +7,8 @@ - - + + + diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index b09abbf7483..2b04741dba8 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -23,11 +23,23 @@ - + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + - - - + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index a1b0338c41f..64926e8c0d2 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -35,7 +35,7 @@ "Type": "nuget", "Nuget": { "Name": "Json.More.Net", - "Version": "2.0.1.2" + "Version": "2.0.2" } }, "DevelopmentDependency": false @@ -45,7 +45,7 @@ "Type": "nuget", "Nuget": { "Name": "JsonPointer.Net", - "Version": "5.0.0" + "Version": "5.0.2" } }, "DevelopmentDependency": false @@ -55,7 +55,7 @@ "Type": "nuget", "Nuget": { "Name": "JsonSchema.Net", - "Version": "7.0.1" + "Version": "7.2.3" } }, "DevelopmentDependency": false @@ -65,7 +65,7 @@ "Type": "nuget", "Nuget": { "Name": "Markdig.Signed", - "Version": "0.37.0" + "Version": "0.38.0" } }, "DevelopmentDependency": false @@ -90,22 +90,12 @@ }, "DevelopmentDependency": false }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "Microsoft.CodeAnalysis.Analyzers", - "Version": "3.3.4" - } - }, - "DevelopmentDependency": true - }, { "Component": { "Type": "nuget", "Nuget": { "Name": "Microsoft.CodeAnalysis.Common", - "Version": "4.9.2" + "Version": "4.11.0" } }, "DevelopmentDependency": false @@ -115,7 +105,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.CodeAnalysis.CSharp", - "Version": "4.9.2" + "Version": "4.11.0" } }, "DevelopmentDependency": false @@ -125,7 +115,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "8.0.4" + "Version": "8.0.10" } }, "DevelopmentDependency": false @@ -205,7 +195,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry", - "Version": "4.7.0" + "Version": "5.0.0" } }, "DevelopmentDependency": false @@ -225,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "8.0.8" + "Version": "8.0.10" } }, "DevelopmentDependency": false @@ -245,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.0-preview.3.24172.9" + "Version": "9.0.0-rc.2.24473.5" } }, "DevelopmentDependency": false @@ -255,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0-preview.3.24172.9" + "Version": "9.0.0-rc.2.24473.5" } }, "DevelopmentDependency": false @@ -265,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0-preview.3.24172.9" + "Version": "9.0.0-rc.2.24473.5" } }, "DevelopmentDependency": false @@ -275,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.0-preview.3.24172.9" + "Version": "9.0.0-rc.2.24473.5" } }, "DevelopmentDependency": false @@ -305,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0-preview.3.24172.9" + "Version": "9.0.0-rc.2.24473.5" } }, "DevelopmentDependency": false @@ -315,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0-preview.3.24172.9" + "Version": "9.0.0-rc.2.24473.5" } }, "DevelopmentDependency": false @@ -325,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.0-preview.3.24172.9" + "Version": "9.0.0-rc.2.24473.5" } }, "DevelopmentDependency": false @@ -335,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0-preview.3.24172.9" + "Version": "9.0.0-rc.2.24473.5" } }, "DevelopmentDependency": false @@ -345,7 +335,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0-preview.3.24172.9" + "Version": "9.0.0-rc.2.24473.5" } }, "DevelopmentDependency": false @@ -365,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0-preview.3.24172.9" + "Version": "9.0.0-rc.2.24473.5" } }, "DevelopmentDependency": false @@ -375,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0-preview.3.24172.9" + "Version": "9.0.0-rc.2.24473.5" } }, "DevelopmentDependency": false @@ -515,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "8.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -525,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "8.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -535,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "8.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -565,17 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "8.0.0" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.Diagnostics.PerformanceCounter", - "Version": "8.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -585,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "8.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -595,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "8.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -625,17 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "8.0.8" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.Formats.Asn1", - "Version": "8.0.1" + "Version": "8.0.10" } }, "DevelopmentDependency": false @@ -645,7 +615,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "8.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -725,7 +695,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Metadata", - "Version": "8.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -735,17 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "8.0.0" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.Runtime.CompilerServices.Unsafe", - "Version": "6.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -765,7 +725,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "8.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -785,7 +745,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "8.0.1" + "Version": "8.0.2" } }, "DevelopmentDependency": false @@ -875,7 +835,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "8.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -925,7 +885,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Web.Services.Description", - "Version": "4.10.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false From 396e3089a99fb41745df6d2e24d568d55d09bc40 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 1 Nov 2024 13:05:52 -0700 Subject: [PATCH 048/275] Update ThirdPartyNotices for release (#24536) --- ThirdPartyNotices.txt | 306 +++++++++++++----------------------------- 1 file changed, 90 insertions(+), 216 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 27dd8ead268..24c332f7074 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -17,7 +17,7 @@ required to debug changes to any libraries licensed under the GNU Lesser General --------------------------------------------------------- -Markdig.Signed 0.37.0 - BSD-2-Clause +Markdig.Signed 0.38.0 - BSD-2-Clause @@ -55,14 +55,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Json.More.Net 2.0.1.2 - MIT +Json.More.Net 2.0.2 - MIT -Copyright (c) 2024 Greg Dennis +Copyright (c) .NET Foundation and Contributors MIT License -Copyright (c) 2024 Greg Dennis +Copyright (c) .NET Foundation and Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -87,14 +87,14 @@ SOFTWARE. --------------------------------------------------------- -JsonPointer.Net 5.0.0 - MIT +JsonPointer.Net 5.0.2 - MIT -Copyright (c) 2024 Greg Dennis +Copyright (c) .NET Foundation and Contributors MIT License -Copyright (c) 2024 Greg Dennis +Copyright (c) .NET Foundation and Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -119,7 +119,7 @@ SOFTWARE. --------------------------------------------------------- -JsonSchema.Net 7.0.1 - MIT +JsonSchema.Net 7.2.3 - MIT @@ -242,7 +242,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.CodeAnalysis.Common 4.9.2 - MIT +Microsoft.CodeAnalysis.Common 4.11.0 - MIT (c) Microsoft Corporation @@ -262,7 +262,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.CodeAnalysis.CSharp 4.9.2 - MIT +Microsoft.CodeAnalysis.CSharp 4.11.0 - MIT (c) Microsoft Corporation @@ -284,7 +284,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 8.0.4 - MIT +Microsoft.Extensions.ObjectPool 8.0.10 - MIT Copyright 2019 The gRPC @@ -374,29 +374,48 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Win32.Registry 4.7.0 - MIT +Microsoft.Win32.Registry 5.0.0 - MIT -(c) Microsoft Corporation. -Copyright (c) .NET Foundation. +(c) Microsoft Corporation +Copyright (c) Andrew Arnott +Copyright 2018 Daniel Lemire +Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. -(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 2020 Dan Shechter +(c) 1997-2005 Sean Eron Anderson +Copyright (c) 1998 Microsoft. To +Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2017 Unicode, Inc. +Copyright (c) 2012-2014, Yann Collet +Copyright (c) 1991-2020 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright 2012 the V8 project authors +Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2015 The Chromium Authors +Copyright (c) 2018 Alexander Chermyanin +Copyright (c) The Internet Society 1997 Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. Copyright (c) 2004-2006 Intel Corporation +Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors Copyright (c) .NET Foundation and Contributors Copyright (c) 2011 Novell, Inc (http://www.novell.com) Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors +Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com +Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -599,7 +618,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Windows.Compatibility 8.0.8 - MIT +Microsoft.Windows.Compatibility 8.0.10 - MIT (c) Microsoft Corporation @@ -652,7 +671,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.android-arm.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT +runtime.android-arm.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT Copyright (c) Six Labors @@ -676,6 +695,7 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula @@ -694,6 +714,7 @@ Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -701,7 +722,6 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com @@ -741,7 +761,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-arm64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT +runtime.android-arm64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT Copyright (c) Six Labors @@ -765,6 +785,7 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula @@ -783,6 +804,7 @@ Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -790,7 +812,6 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com @@ -830,7 +851,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT +runtime.android-x64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT Copyright (c) Six Labors @@ -854,6 +875,7 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula @@ -872,6 +894,7 @@ Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -879,7 +902,6 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com @@ -919,7 +941,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x86.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT +runtime.android-x86.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT Copyright (c) Six Labors @@ -943,6 +965,7 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula @@ -961,6 +984,7 @@ Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -968,7 +992,6 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com @@ -1180,7 +1203,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT +runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT Copyright (c) Six Labors @@ -1204,6 +1227,7 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula @@ -1222,6 +1246,7 @@ Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -1229,7 +1254,6 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com @@ -1269,7 +1293,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT +runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT Copyright (c) Six Labors @@ -1293,6 +1317,7 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula @@ -1311,6 +1336,7 @@ Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -1318,7 +1344,6 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com @@ -1358,7 +1383,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT +runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT Copyright (c) Six Labors @@ -1382,6 +1407,7 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula @@ -1400,6 +1426,7 @@ Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -1407,7 +1434,6 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com @@ -1447,7 +1473,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT +runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT Copyright (c) Six Labors @@ -1471,6 +1497,7 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula @@ -1489,6 +1516,7 @@ Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -1496,7 +1524,6 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com @@ -1536,7 +1563,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT +runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT Copyright (c) Six Labors @@ -1560,6 +1587,7 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula @@ -1578,6 +1606,7 @@ Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -1585,7 +1614,6 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com @@ -1711,7 +1739,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT +runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT Copyright (c) Six Labors @@ -1735,6 +1763,7 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula @@ -1753,6 +1782,7 @@ Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -1760,7 +1790,6 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com @@ -1800,7 +1829,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.0-preview.3.24172.9 - MIT +runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT Copyright (c) Six Labors @@ -1824,6 +1853,7 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula @@ -1842,6 +1872,7 @@ Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -1849,7 +1880,6 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com @@ -2544,7 +2574,7 @@ SOFTWARE. --------------------------------------------------------- -System.Configuration.ConfigurationManager 8.0.0 - MIT +System.Configuration.ConfigurationManager 8.0.1 - MIT Copyright (c) Six Labors @@ -2630,7 +2660,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.Odbc 8.0.0 - MIT +System.Data.Odbc 8.0.1 - MIT Copyright (c) Six Labors @@ -2716,7 +2746,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.OleDb 8.0.0 - MIT +System.Data.OleDb 8.0.1 - MIT Copyright (c) Six Labors @@ -2941,7 +2971,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.EventLog 8.0.0 - MIT +System.Diagnostics.EventLog 8.0.1 - MIT Copyright (c) Six Labors @@ -3027,7 +3057,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.PerformanceCounter 8.0.0 - MIT +System.Diagnostics.PerformanceCounter 8.0.1 - MIT Copyright (c) Six Labors @@ -3199,7 +3229,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.AccountManagement 8.0.0 - MIT +System.DirectoryServices.AccountManagement 8.0.1 - MIT Copyright (c) Six Labors @@ -3371,7 +3401,7 @@ SOFTWARE. --------------------------------------------------------- -System.Drawing.Common 8.0.8 - MIT +System.Drawing.Common 8.0.10 - MIT (c) Microsoft Corporation @@ -3406,93 +3436,7 @@ SOFTWARE. --------------------------------------------------------- -System.Formats.Asn1 8.0.1 - MIT - - -Copyright (c) Six Labors -(c) Microsoft Corporation -Copyright (c) Andrew Arnott -Copyright 2019 LLVM Project -Copyright 2018 Daniel Lemire -Copyright (c) .NET Foundation -Copyright (c) 2011, Google Inc. -Copyright (c) 2020 Dan Shechter -(c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To -Copyright (c) 2022, Wojciech Mula -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) 2022, Geoff Langdale -Copyright (c) 2005-2020 Rich Felker -Copyright (c) 2012-2021 Yann Collet -Copyright (c) Microsoft Corporation -Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -Copyright 2012 the V8 project authors -Copyright (c) 1999 Lucent Technologies -Copyright (c) 2008-2016, Wojciech Mula -Copyright (c) 2011-2020 Microsoft Corp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors -Copyright (c) 2005-2007, Nick Galbreath -Copyright (c) 2015 The Chromium Authors -Copyright (c) 2018 Alexander Chermyanin -Copyright (c) The Internet Society 1997 -Portions (c) International Organization -Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2011-2015 Intel Corporation -Copyright (c) 2013-2017, Milosz Krajewski -Copyright (c) 2016-2017, Matthieu Darbois -Copyright (c) The Internet Society (2003) -Copyright (c) .NET Foundation Contributors -Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2012 - present, Victor Zverovich -Copyright (c) 2006 Jb Evain (jbevain@gmail.com) -Copyright (c) 2008-2020 Advanced Micro Devices, Inc. -Copyright (c) 2019 Microsoft Corporation, Daan Leijen -Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler -Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors -Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com -Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip -Copyright (c) 1980, 1986, 1993 The Regents of the University of California -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass - -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), 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 "AS IS", 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. - - ---------------------------------------------------------- - ---------------------------------------------------------- - -System.IO.Packaging 8.0.0 - MIT +System.IO.Packaging 8.0.1 - MIT Copyright (c) Six Labors @@ -4060,7 +4004,7 @@ SOFTWARE. --------------------------------------------------------- -System.Reflection.Metadata 8.0.0 - MIT +System.Reflection.Metadata 8.0.1 - MIT Copyright (c) Six Labors @@ -4147,7 +4091,7 @@ SOFTWARE. --------------------------------------------------------- -System.Runtime.Caching 8.0.0 - MIT +System.Runtime.Caching 8.0.1 - MIT Copyright (c) Six Labors @@ -4229,80 +4173,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------- - ---------------------------------------------------------- - -System.Runtime.CompilerServices.Unsafe 6.0.0 - MIT - - -(c) Microsoft Corporation -Copyright (c) Andrew Arnott -Copyright 2018 Daniel Lemire -Copyright (c) .NET Foundation -Copyright (c) 2011, Google Inc. -Copyright (c) 2020 Dan Shechter -(c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) 2005-2020 Rich Felker -Copyright (c) Microsoft Corporation -Copyright (c) 2007 James Newton-King -Copyright (c) 2012-2014, Yann Collet -Copyright (c) 1991-2020 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -Copyright 2012 the V8 project authors -Copyright (c) 2011-2020 Microsoft Corp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2005-2007, Nick Galbreath -Copyright (c) 2015 The Chromium Authors -Copyright (c) 2018 Alexander Chermyanin -Copyright (c) The Internet Society 1997 -Portions (c) International Organization -Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2013-2017, Milosz Krajewski -Copyright (c) 2016-2017, Matthieu Darbois -Copyright (c) The Internet Society (2003) -Copyright (c) .NET Foundation Contributors -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2019 Microsoft Corporation, Daan Leijen -Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler -Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors -Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com -Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To - -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), 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 "AS IS", 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. - - --------------------------------------------------------- --------------------------------------------------------- @@ -4382,7 +4252,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Pkcs 8.0.0 - MIT +System.Security.Cryptography.Pkcs 8.0.1 - MIT Copyright (c) Six Labors @@ -4554,7 +4424,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Xml 8.0.1 - MIT +System.Security.Cryptography.Xml 8.0.2 - MIT Copyright (c) Six Labors @@ -5061,7 +4931,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceProcess.ServiceController 8.0.0 - MIT +System.ServiceProcess.ServiceController 8.0.1 - MIT Copyright (c) Six Labors @@ -5438,9 +5308,12 @@ SOFTWARE. --------------------------------------------------------- -System.Web.Services.Description 4.10.0 - MIT +System.Web.Services.Description 8.0.0 - MIT +(c) Microsoft Corporation +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) The MIT License (MIT) @@ -5747,3 +5620,4 @@ 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. + From a84ab3a1cb76f32df0d118f48326d99724cbdc65 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:16:23 -0800 Subject: [PATCH 049/275] [release/v7.5] Update branch for release - Transitive - true - minor (#24576) --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 3 +- ...soft.PowerShell.Commands.Management.csproj | 3 +- ...crosoft.PowerShell.Commands.Utility.csproj | 6 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 49 ++++++--- .../Microsoft.WSMan.Management.csproj | 3 +- .../System.Management.Automation.csproj | 24 ++--- .../BenchmarkDotNet.Extensions.csproj | 4 +- .../ResultsComparer/ResultsComparer.csproj | 4 +- ...soft.PowerShell.NamedPipeConnection.csproj | 20 ++-- .../nested/Test.Isolated.Nested.csproj | 2 + test/tools/TestService/TestService.csproj | 60 ++++++----- test/tools/WebListener/WebListener.csproj | 7 +- tools/cgmanifest.json | 102 +++++++++--------- 16 files changed, 162 insertions(+), 131 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 50884cd0a3c..472b5958a8c 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "9.0.0-preview.6.24327.7", + "sdkImageVersion": "9.0.100", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 2dd360f846e..65324522984 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.100-rc.2.24474.11" + "version": "9.0.100" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 34502ced25d..e575d8ef567 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,8 +7,9 @@ + - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 4f20755c6e6..748df04b328 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,8 @@ - + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 9b61bb2b53d..e60c27d28a6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -13,7 +13,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + @@ -41,8 +41,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 003999e97b3..5c28e4fe256 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 03898ace0d3..bc5206ea9fa 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -17,25 +17,39 @@ - - - - - + + + + + + + + + + - - - + + + + + + - - - - - - - - + + + + + + + + + + + + + + - + + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 77aa3cef77c..5a379621c85 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,10 +7,11 @@ + - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 6fce6d93111..12177ffd61c 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,25 +32,25 @@ - - - - - - + + + + + + - + - - - - + + + + - + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 47dc5733932..4c1975ac342 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -11,10 +11,12 @@ + - + + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 02f7255bcdb..61a9818dc23 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -11,11 +11,13 @@ + - + + diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index d6cc1071790..0acf5c81d43 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -20,14 +20,18 @@ - - - - - + + + + + + + - - - + + + + + diff --git a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj index 483ae9267fb..200b284b31a 100644 --- a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj +++ b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj @@ -17,6 +17,8 @@ + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 10bf8593408..e96e4defa48 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,38 +15,40 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index d3e8a1f3244..fc11e328e7e 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,8 +7,9 @@ - - - + + + + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index 64926e8c0d2..4abc0cd4000 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -115,7 +115,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "8.0.10" + "Version": "8.0.11" } }, "DevelopmentDependency": false @@ -185,7 +185,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -205,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -215,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "8.0.10" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -235,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.0-rc.2.24473.5" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -245,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0-rc.2.24473.5" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -255,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0-rc.2.24473.5" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -265,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.0-rc.2.24473.5" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -275,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -285,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -295,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0-rc.2.24473.5" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -305,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0-rc.2.24473.5" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -315,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.0-rc.2.24473.5" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -325,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0-rc.2.24473.5" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -335,7 +335,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0-rc.2.24473.5" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -345,7 +345,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -355,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0-rc.2.24473.5" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -365,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0-rc.2.24473.5" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -385,7 +385,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -395,7 +395,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -405,7 +405,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -465,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -485,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -495,7 +495,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -505,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "8.0.1" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -515,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "8.0.1" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -525,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "8.0.1" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -545,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.DiagnosticSource", - "Version": "8.0.1" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -555,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "8.0.1" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -565,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "8.0.1" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -575,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "8.0.1" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -585,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -595,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -605,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "8.0.10" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -615,7 +615,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "8.0.1" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -625,7 +625,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -635,7 +635,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -645,7 +645,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "8.0.2" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -675,7 +675,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -705,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "8.0.1" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -725,7 +725,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "8.0.1" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -735,7 +735,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -745,7 +745,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "8.0.2" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -755,7 +755,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -825,7 +825,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -835,7 +835,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "8.0.1" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -845,7 +845,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -855,7 +855,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encoding.CodePages", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -865,7 +865,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encodings.Web", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -875,7 +875,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false @@ -895,7 +895,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "8.0.0" + "Version": "9.0.0" } }, "DevelopmentDependency": false From c0142dde17137e436e302b3c4e93e2d6dc50c5c4 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 13 Nov 2024 11:23:21 -0800 Subject: [PATCH 050/275] Update ThirdPartyNotices file (#24582) --- ThirdPartyNotices.txt | 792 +++++++++++++++++++++++++----------------- 1 file changed, 468 insertions(+), 324 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 24c332f7074..a11a42b0aab 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -284,16 +284,16 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 8.0.10 - MIT +Microsoft.Extensions.ObjectPool 8.0.11 - MIT -Copyright 2019 The gRPC Copyright Jorn Zaefferer (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright (c) 2015, Google Inc. Copyright (c) 2019 David Fowler Copyright (c) HTML5 Boilerplate +Copyright 2019 The gRPC Authors Copyright (c) 2016 Richard Morris Copyright (c) 1998 John D. Polstra Copyright (c) 2017 Yoshifumi Kawai @@ -446,19 +446,22 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Win32.Registry.AccessControl 8.0.0 - MIT +Microsoft.Win32.Registry.AccessControl 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -468,23 +471,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -492,12 +496,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -532,19 +536,22 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Win32.SystemEvents 8.0.0 - MIT +Microsoft.Win32.SystemEvents 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -554,23 +561,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -578,12 +586,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -618,7 +626,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Windows.Compatibility 8.0.10 - MIT +Microsoft.Windows.Compatibility 9.0.0 - MIT (c) Microsoft Corporation @@ -671,20 +679,21 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.android-arm.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT +runtime.android-arm.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai @@ -702,12 +711,10 @@ Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski @@ -726,7 +733,8 @@ Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -761,20 +769,21 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-arm64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT +runtime.android-arm64.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai @@ -792,12 +801,10 @@ Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski @@ -816,7 +823,8 @@ Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -851,20 +859,21 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT +runtime.android-x64.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai @@ -882,12 +891,10 @@ Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski @@ -906,7 +913,8 @@ Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -941,20 +949,21 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x86.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT +runtime.android-x86.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai @@ -972,12 +981,10 @@ Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski @@ -996,7 +1003,8 @@ Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -1031,19 +1039,22 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm.runtime.native.System.IO.Ports 8.0.0 - MIT +runtime.linux-arm.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -1053,23 +1064,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -1077,12 +1089,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -1117,19 +1129,22 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm64.runtime.native.System.IO.Ports 8.0.0 - MIT +runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -1139,23 +1154,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -1163,12 +1179,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -1203,20 +1219,21 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT +runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai @@ -1234,12 +1251,10 @@ Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski @@ -1258,7 +1273,8 @@ Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -1293,20 +1309,21 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT +runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai @@ -1324,12 +1341,10 @@ Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski @@ -1348,7 +1363,8 @@ Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -1383,20 +1399,21 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT +runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai @@ -1414,12 +1431,10 @@ Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski @@ -1438,7 +1453,8 @@ Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -1473,20 +1489,21 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT +runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai @@ -1504,12 +1521,10 @@ Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski @@ -1528,7 +1543,8 @@ Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -1563,20 +1579,21 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT +runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai @@ -1594,12 +1611,10 @@ Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski @@ -1618,7 +1633,8 @@ Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -1653,19 +1669,22 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-x64.runtime.native.System.IO.Ports 8.0.0 - MIT +runtime.linux-x64.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -1675,23 +1694,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -1699,12 +1719,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -1739,20 +1759,21 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT +runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai @@ -1770,12 +1791,10 @@ Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski @@ -1794,7 +1813,8 @@ Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -1829,20 +1849,21 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.0-rc.2.24473.5 - MIT +runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai @@ -1860,12 +1881,10 @@ Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski @@ -1884,7 +1903,8 @@ Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -1972,19 +1992,22 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.IO.Ports 8.0.0 - MIT +runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -1994,23 +2017,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -2018,12 +2042,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -2058,19 +2082,22 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-arm64.runtime.native.System.IO.Ports 8.0.0 - MIT +runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -2080,23 +2107,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -2104,12 +2132,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -2144,19 +2172,22 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-x64.runtime.native.System.IO.Ports 8.0.0 - MIT +runtime.osx-x64.runtime.native.System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -2166,23 +2197,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -2190,12 +2222,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -2230,19 +2262,22 @@ SOFTWARE. --------------------------------------------------------- -System.CodeDom 8.0.0 - MIT +System.CodeDom 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -2252,23 +2287,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -2276,12 +2312,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -2402,19 +2438,22 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition 8.0.0 - MIT +System.ComponentModel.Composition 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -2424,23 +2463,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -2448,12 +2488,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -2488,19 +2528,22 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition.Registration 8.0.0 - MIT +System.ComponentModel.Composition.Registration 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -2510,23 +2553,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -2534,12 +2578,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -2574,19 +2618,22 @@ SOFTWARE. --------------------------------------------------------- -System.Configuration.ConfigurationManager 8.0.1 - MIT +System.Configuration.ConfigurationManager 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -2596,23 +2643,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -2620,12 +2668,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -2660,19 +2708,22 @@ SOFTWARE. --------------------------------------------------------- -System.Data.Odbc 8.0.1 - MIT +System.Data.Odbc 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -2682,23 +2733,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -2706,12 +2758,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -2746,19 +2798,22 @@ SOFTWARE. --------------------------------------------------------- -System.Data.OleDb 8.0.1 - MIT +System.Data.OleDb 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -2768,23 +2823,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -2792,12 +2848,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -2885,62 +2941,9 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.DiagnosticSource 8.0.1 - MIT +System.Diagnostics.DiagnosticSource 9.0.0 - MIT -Copyright (c) Six Labors -(c) Microsoft Corporation -Copyright (c) Andrew Arnott -Copyright 2019 LLVM Project -Copyright 2018 Daniel Lemire -Copyright (c) .NET Foundation -Copyright (c) 2011, Google Inc. -Copyright (c) 2020 Dan Shechter -(c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To -Copyright (c) 2022, Wojciech Mula -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) 2022, Geoff Langdale -Copyright (c) 2005-2020 Rich Felker -Copyright (c) 2012-2021 Yann Collet -Copyright (c) Microsoft Corporation -Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -Copyright 2012 the V8 project authors -Copyright (c) 1999 Lucent Technologies -Copyright (c) 2008-2016, Wojciech Mula -Copyright (c) 2011-2020 Microsoft Corp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors -Copyright (c) 2005-2007, Nick Galbreath -Copyright (c) 2015 The Chromium Authors -Copyright (c) 2018 Alexander Chermyanin -Copyright (c) The Internet Society 1997 -Portions (c) International Organization -Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2011-2015 Intel Corporation -Copyright (c) 2013-2017, Milosz Krajewski -Copyright (c) 2016-2017, Matthieu Darbois -Copyright (c) The Internet Society (2003) -Copyright (c) .NET Foundation Contributors -Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2012 - present, Victor Zverovich -Copyright (c) 2006 Jb Evain (jbevain@gmail.com) -Copyright (c) 2008-2020 Advanced Micro Devices, Inc. -Copyright (c) 2019 Microsoft Corporation, Daan Leijen -Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler -Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors -Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com -Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip -Copyright (c) 1980, 1986, 1993 The Regents of the University of California -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass The MIT License (MIT) @@ -2971,19 +2974,22 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.EventLog 8.0.1 - MIT +System.Diagnostics.EventLog 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -2993,23 +2999,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -3017,12 +3024,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -3057,19 +3064,22 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.PerformanceCounter 8.0.1 - MIT +System.Diagnostics.PerformanceCounter 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -3079,23 +3089,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -3103,12 +3114,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -3143,19 +3154,22 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices 8.0.0 - MIT +System.DirectoryServices 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -3165,23 +3179,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -3189,12 +3204,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -3229,19 +3244,22 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.AccountManagement 8.0.1 - MIT +System.DirectoryServices.AccountManagement 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -3251,23 +3269,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -3275,12 +3294,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -3315,19 +3334,22 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.Protocols 8.0.0 - MIT +System.DirectoryServices.Protocols 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -3337,23 +3359,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -3361,12 +3384,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -3401,7 +3424,7 @@ SOFTWARE. --------------------------------------------------------- -System.Drawing.Common 8.0.10 - MIT +System.Drawing.Common 9.0.0 - MIT (c) Microsoft Corporation @@ -3436,19 +3459,22 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Packaging 8.0.1 - MIT +System.IO.Packaging 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -3458,23 +3484,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -3482,12 +3509,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -3522,19 +3549,22 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Ports 8.0.0 - MIT +System.IO.Ports 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -3544,23 +3574,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -3568,12 +3599,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -3608,19 +3639,22 @@ SOFTWARE. --------------------------------------------------------- -System.Management 8.0.0 - MIT +System.Management 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -3630,23 +3664,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -3654,12 +3689,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -3694,19 +3729,22 @@ SOFTWARE. --------------------------------------------------------- -System.Net.Http.WinHttpHandler 8.0.2 - MIT +System.Net.Http.WinHttpHandler 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -3716,23 +3754,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -3740,12 +3779,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -3865,19 +3904,22 @@ SOFTWARE. --------------------------------------------------------- -System.Reflection.Context 8.0.0 - MIT +System.Reflection.Context 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -3887,23 +3929,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -3911,12 +3954,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -4091,19 +4134,22 @@ SOFTWARE. --------------------------------------------------------- -System.Runtime.Caching 8.0.1 - MIT +System.Runtime.Caching 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -4113,23 +4159,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -4137,12 +4184,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -4252,19 +4299,22 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Pkcs 8.0.1 - MIT +System.Security.Cryptography.Pkcs 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -4274,23 +4324,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -4298,12 +4349,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -4338,19 +4389,22 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.ProtectedData 8.0.0 - MIT +System.Security.Cryptography.ProtectedData 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -4360,23 +4414,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -4384,12 +4439,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -4424,19 +4479,22 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Xml 8.0.2 - MIT +System.Security.Cryptography.Xml 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -4446,23 +4504,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -4470,12 +4529,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -4510,19 +4569,22 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Permissions 8.0.0 - MIT +System.Security.Permissions 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -4532,23 +4594,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -4556,12 +4619,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -4845,19 +4908,22 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Syndication 8.0.0 - MIT +System.ServiceModel.Syndication 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -4867,23 +4933,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -4891,12 +4958,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -4931,19 +4998,22 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceProcess.ServiceController 8.0.1 - MIT +System.ServiceProcess.ServiceController 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -4953,23 +5023,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -4977,12 +5048,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -5017,19 +5088,22 @@ SOFTWARE. --------------------------------------------------------- -System.Speech 8.0.0 - MIT +System.Speech 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -5039,23 +5113,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -5063,12 +5138,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -5103,9 +5178,66 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encoding.CodePages 8.0.0 - MIT +System.Text.Encoding.CodePages 9.0.0 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors +(c) Microsoft Corporation +Copyright (c) 2022 FormatJS +Copyright (c) Andrew Arnott +Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft +Copyright 2018 Daniel Lemire +Copyright (c) .NET Foundation +Copyright (c) 2011, Google Inc. +Copyright (c) 2020 Dan Shechter +(c) 1997-2005 Sean Eron Anderson +Copyright (c) 2015 Andrew Gallant +Copyright (c) 2022, Wojciech Mula +Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) 2022, Geoff Langdale +Copyright (c) 2005-2020 Rich Felker +Copyright (c) 2012-2021 Yann Collet +Copyright (c) Microsoft Corporation +Copyright (c) 2007 James Newton-King +Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic +Copyright 2012 the V8 project authors +Copyright (c) 1999 Lucent Technologies +Copyright (c) 2008-2016, Wojciech Mula +Copyright (c) 2011-2020 Microsoft Corp +Copyright (c) 2015-2017, Wojciech Mula +Copyright (c) 2015-2018, Wojciech Mula +Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2015 The Chromium Authors +Copyright (c) 2018 Alexander Chermyanin +Copyright (c) The Internet Society 1997 +Copyright (c) 2004-2006 Intel Corporation +Copyright (c) 2011-2015 Intel Corporation +Copyright (c) 2013-2017, Milosz Krajewski +Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) The Internet Society (2003) +Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler +Copyright (c) 2020 Mara Bos +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2012 - present, Victor Zverovich +Copyright (c) 2006 Jb Evain (jbevain@gmail.com) +Copyright (c) 2008-2020 Advanced Micro Devices, Inc. +Copyright (c) 2019 Microsoft Corporation, Daan Leijen +Copyright (c) 2011 Novell, Inc (http://www.novell.com) +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors +Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com +Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip +Copyright (c) 1980, 1986, 1993 The Regents of the University of California +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass The MIT License (MIT) @@ -5136,19 +5268,22 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encodings.Web 8.0.0 - MIT +System.Text.Encodings.Web 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -5158,23 +5293,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -5182,12 +5318,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -5222,19 +5358,22 @@ SOFTWARE. --------------------------------------------------------- -System.Threading.AccessControl 8.0.0 - MIT +System.Threading.AccessControl 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -5244,23 +5383,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -5268,12 +5408,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -5344,19 +5484,22 @@ SOFTWARE. --------------------------------------------------------- -System.Windows.Extensions 8.0.0 - MIT +System.Windows.Extensions 9.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -5366,23 +5509,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -5390,12 +5534,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California From be6dfe3480e41af4776286d6777dee450675b605 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 13 Nov 2024 18:24:46 -0800 Subject: [PATCH 051/275] Update change log for v7.5.0-rc.1 (#24584) --- CHANGELOG/preview.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index 847ca7a2919..3ffbdcae65b 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,40 @@ # Preview Changelog +## [7.5.0-rc.1] - 2024-11-14 + +### Build and Packaging Improvements + +
+ + + +

Bump to .NET 9.0.100

+ +
+ +
    +
  • Update ThirdPartyNotices file (#24582) (#24536)
  • +
  • Bump to .NET 9.0.100 (#24576) (#24535)
  • +
  • Add a way to use only NuGet feed sources (#24528) (#24530)
  • +
  • Update PSResourceGet to v1.1.0-RC2 (#24512) (#24525)
  • +
  • Add PMC mapping for debian 12 (bookworm) (#24413) (#24518)
  • +
  • Bump .NET to 9.0.100-rc.2.24474.11 (#24509) (#24522)
  • +
  • Keep the roff file when gzipping it. (#24450) (#24520)
  • +
  • Checkin generated manpage (#24423) (#24519)
  • +
  • Update PSReadLine to 2.3.6 (#24380) (#24517)
  • +
  • Download package from package build for generating vpack (#24481) (#24521)
  • +
  • Delete the msix blob if it's already there (#24353) (#24516)
  • +
  • Add CodeQL scanning to APIScan build (#24303) (#24515)
  • +
  • Update vpack pipeline (#24281) (#24514)
  • +
  • Fix seed max value for Container Linux CI (#24510) (#24511)
  • +
  • Bring preview.5 release fixes to release/v7.5 (#24379) (#24368)
  • +
  • Add BaseUrl to buildinfo json file (#24376) (#24377)
  • +
+ +
+ +[7.5.0-rc.1]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-preview.5...v7.5.0-rc.1 + ## [7.5.0-preview.5] - 2024-10-01 ### Breaking Changes From 2800f895f59272e97583fddec9285cd773142f5b Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 14 Nov 2024 14:14:58 -0800 Subject: [PATCH 052/275] Update machine pool for copy blob and upload buildinfo stage (#24587) (#24588) --- .pipelines/PowerShell-Release-Official.yml | 6 +++--- .pipelines/templates/release-MakeBlobPublic.yml | 9 +++++++++ .pipelines/templates/release-upload-buildinfo.yml | 9 +++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 2538d1b5370..195491ef161 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -79,12 +79,12 @@ resources: extends: template: v2/OneBranch.Official.CrossPlat.yml@templates parameters: - # still using KS2 because we are not yet using a Box Product Deployment + # using Monitor as copy blob is being blocked by the network featureFlags: LinuxHostVersion: - Network: KS2 + Network: Monitor WindowsHostVersion: - Network: KS2 + Network: Monitor cloudvault: enabled: false globalSdl: diff --git a/.pipelines/templates/release-MakeBlobPublic.yml b/.pipelines/templates/release-MakeBlobPublic.yml index f9afbebb909..84a02c9e0f0 100644 --- a/.pipelines/templates/release-MakeBlobPublic.yml +++ b/.pipelines/templates/release-MakeBlobPublic.yml @@ -17,7 +17,12 @@ jobs: dependsOn: CopyReleaseBlobApproval condition: and(succeeded(), ne('${{ parameters.SkipPSInfraInstallers }}', true)) pool: + name: PowerShell1ES type: windows + isCustom: true + demands: + - ImageOverride -equals PSMMS2019-Secure + variables: - group: 'PSInfraStorage' @@ -113,7 +118,11 @@ jobs: displayName: Copy global tools to PSInfra storage dependsOn: CopyBlobApproval pool: + name: PowerShell1ES type: windows + isCustom: true + demands: + - ImageOverride -equals PSMMS2019-Secure variables: - group: 'PSInfraStorage' diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index f2b06cd2010..ea7b90db8e3 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -8,7 +8,11 @@ jobs: displayName: Publish BuildInfo condition: succeeded() pool: + name: PowerShell1ES type: windows + isCustom: true + demands: + - ImageOverride -equals PSMMS2019-Secure variables: - name: runCodesignValidationInjection value: false @@ -45,14 +49,15 @@ jobs: displayName: Download build info artifact - pwsh: | - Import-Module '$(Build.SourcesDirectory)/PowerShell/tools/ci.psm1' + $toolsDirectory = '$(Build.SourcesDirectory)/tools' + Import-Module "$toolsDirectory/ci.psm1" $jsonFile = Get-Item "$ENV:PIPELINE_WORKSPACE/PSPackagesOfficial/BuildInfoJson/*.json" $fileName = Split-Path $jsonFile -Leaf $dateTime = [datetime]::UtcNow $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) - $metadata = Get-Content -LiteralPath '$(Build.SourcesDirectory)/PowerShell/tools/metadata.json' -ErrorAction Stop | ConvertFrom-Json + $metadata = Get-Content -LiteralPath "$toolsDirectory/metadata.json" -ErrorAction Stop | ConvertFrom-Json $stableRelease = $metadata.StableRelease.Latest $ltsRelease = $metadata.LTSRelease.Latest From 9aa6e06ce65a9c55601f6b4109d9812bd78de7e1 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 15 Nov 2024 15:26:12 -0800 Subject: [PATCH 053/275] Added Deploy Box Product Pathway to GitHub Release and NuGet Release Pipelines (#24583) (#24595) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> --- .pipelines/PowerShell-Release-Official.yml | 99 +++++--- .../templates/release-checkout-pwsh-repo.yml | 13 + .../templates/release-download-packages.yml | 122 ++++++++++ .pipelines/templates/release-githubtasks.yml | 222 +++++++----------- .pipelines/templates/release-install-pwsh.yml | 34 +++ .../templates/release-publish-nuget.yml | 42 ++-- .pipelines/templates/uploadToAzure.yml | 20 ++ .../templates/variable/release-shared.yml | 32 +++ 8 files changed, 394 insertions(+), 190 deletions(-) create mode 100644 .pipelines/templates/release-checkout-pwsh-repo.yml create mode 100644 .pipelines/templates/release-download-packages.yml create mode 100644 .pipelines/templates/release-install-pwsh.yml create mode 100644 .pipelines/templates/variable/release-shared.yml diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 195491ef161..f025c42f460 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -50,7 +50,7 @@ variables: - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - name: LinuxContainerImage value: mcr.microsoft.com/onebranch/cbl-mariner/build:2.0 - name: ReleaseTagVar @@ -79,12 +79,12 @@ resources: extends: template: v2/OneBranch.Official.CrossPlat.yml@templates parameters: - # using Monitor as copy blob is being blocked by the network + release: + category: NonAzure featureFlags: - LinuxHostVersion: - Network: Monitor WindowsHostVersion: - Network: Monitor + Version: 2022 + Network: Netlock cloudvault: enabled: false globalSdl: @@ -110,13 +110,23 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: + - stage: DownloadPackages + displayName: 'Download Packages' + dependsOn: [] + jobs: + - template: /.pipelines/templates/release-download-packages.yml@self + - stage: msixbundle displayName: 'Create MSIX Bundle' + dependsOn: [] + variables: + ob_release_environment: Test jobs: - template: /.pipelines/templates/release-create-msix.yml@self - stage: validateSdk displayName: 'Validate SDK' + dependsOn: [] jobs: - template: /.pipelines/templates/release-validate-sdk.yml@self parameters: @@ -141,6 +151,7 @@ extends: - stage: gbltool displayName: 'Validate Global tools' + dependsOn: [] jobs: - template: /.pipelines/templates/release-validate-globaltools.yml@self parameters: @@ -158,6 +169,7 @@ extends: - stage: fxdpackages displayName: 'Validate FXD Packages' + dependsOn: [] jobs: - template: /.pipelines/templates/release-validate-fxdpackages.yml@self parameters: @@ -194,6 +206,7 @@ extends: - stage: validatePackages displayName: 'Validate Packages' + dependsOn: [] jobs: - template: /.pipelines/templates/release-validate-packagenames.yml@self @@ -262,23 +275,50 @@ extends: Update and merge the changelog for the release. This step is required for creating GitHub draft release. + - stage: PublishGitHubRelease + displayName: Publish GitHub Release + dependsOn: + - DownloadPackages + - UpdateChangeLog + variables: + ob_release_environment: Production + jobs: + - template: /.pipelines/templates/release-githubtasks.yml@self + + - stage: PushGitTagAndMakeDraftPublic + displayName: Push Git Tag and Make Draft Public + dependsOn: PublishGitHubRelease + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Push Git Tag + jobName: PushGitTag + instructions: | + Push the git tag to upstream + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Make Draft Public + dependsOnJob: PushGitTag + jobName: DraftPublic + instructions: | + Make the GitHub Release Draft Public + - stage: BlobPublic displayName: Make Blob Public - dependsOn: UpdateChangeLog + dependsOn: + - UpdateChangeLog + - PushGitTagAndMakeDraftPublic jobs: - template: /.pipelines/templates/release-MakeBlobPublic.yml@self parameters: - SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} - - - stage: PublishGitHubRelease - displayName: Publish GitHub Release - dependsOn: BlobPublic - jobs: - - template: /.pipelines/templates/release-githubtasks.yml@self - + SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} + - stage: PublishNuGet displayName: Publish NuGet - dependsOn: PublishGitHubRelease + dependsOn: PushGitTagAndMakeDraftPublic + variables: + ob_release_environment: Production jobs: - template: /.pipelines/templates/release-publish-nuget.yml@self parameters: @@ -286,14 +326,14 @@ extends: - stage: PublishPMC displayName: Publish PMC - dependsOn: PublishGitHubRelease + dependsOn: PushGitTagAndMakeDraftPublic jobs: - template: /.pipelines/templates/release-publish-pmc.yml@self parameters: skipPublish: ${{ parameters.SkipPMCPublish }} - stage: ReleaseDocker - dependsOn: PublishGitHubRelease + dependsOn: PushGitTagAndMakeDraftPublic displayName: 'Docker Release' jobs: - template: /.pipelines/templates/approvalJob.yml@self @@ -312,7 +352,7 @@ extends: Kickoff docker release - stage: UpdateDotnetDocker - dependsOn: PublishGitHubRelease + dependsOn: PushGitTagAndMakeDraftPublic displayName: Update DotNet SDK Docker images jobs: - template: /.pipelines/templates/approvalJob.yml@self @@ -327,7 +367,7 @@ extends: 4. create PR targeting nightly branch - stage: UpdateWinGet - dependsOn: PublishGitHubRelease + dependsOn: PushGitTagAndMakeDraftPublic displayName: Add manifest entry to winget jobs: - template: /.pipelines/templates/approvalJob.yml@self @@ -338,7 +378,7 @@ extends: This is typically done by the community 1-2 days after the release. - stage: PublishMsix - dependsOn: PublishGitHubRelease + dependsOn: PushGitTagAndMakeDraftPublic displayName: Publish MSIX to store jobs: - template: /.pipelines/templates/approvalJob.yml@self @@ -349,7 +389,7 @@ extends: Ask Steve to release MSIX bundle package to Store - stage: PublishVPack - dependsOn: PublishGitHubRelease + dependsOn: PushGitTagAndMakeDraftPublic displayName: Release vPack jobs: - template: /.pipelines/templates/approvalJob.yml@self @@ -367,20 +407,22 @@ extends: # - template: templates/release-UpdateDepsJson.yml - stage: UploadBuildInfoJson - dependsOn: PublishGitHubRelease + dependsOn: PushGitTagAndMakeDraftPublic displayName: Upload BuildInfo.json jobs: - template: /.pipelines/templates/release-upload-buildinfo.yml@self - stage: ReleaseSymbols - dependsOn: PublishGitHubRelease + dependsOn: PushGitTagAndMakeDraftPublic displayName: Release Symbols jobs: - template: /.pipelines/templates/release-symbols.yml@self - stage: ChangesToMaster displayName: Ensure changes are in GH master - dependsOn: ['PublishNuGet', 'PublishPMC'] + dependsOn: + - PublishNuGet + - PublishPMC jobs: - template: /.pipelines/templates/approvalJob.yml@self parameters: @@ -391,7 +433,7 @@ extends: - stage: ReleaseSnap displayName: Release Snap - dependsOn: 'ChangesToMaster' + dependsOn: ChangesToMaster jobs: - template: /.pipelines/templates/approvalJob.yml@self parameters: @@ -402,7 +444,7 @@ extends: - stage: ReleaseToMU displayName: Release to MU - dependsOn: ['PublishNuGet', 'PublishPMC', 'ChangesToMaster'] + dependsOn: PushGitTagAndMakeDraftPublic # This only needs the blob to be available jobs: - template: /.pipelines/templates/approvalJob.yml@self parameters: @@ -412,7 +454,10 @@ extends: - stage: ReleaseClose displayName: Finish Release - dependsOn: ['ReleaseToMU', 'ReleaseSymbols', 'ReleaseSnap'] + dependsOn: + - ReleaseToMU + - ReleaseSymbols + - ReleaseSnap jobs: - template: /.pipelines/templates/approvalJob.yml@self parameters: diff --git a/.pipelines/templates/release-checkout-pwsh-repo.yml b/.pipelines/templates/release-checkout-pwsh-repo.yml new file mode 100644 index 00000000000..9a7486887a6 --- /dev/null +++ b/.pipelines/templates/release-checkout-pwsh-repo.yml @@ -0,0 +1,13 @@ +steps: + - pwsh: | + Write-Verbose -Verbose "Deploy Box Product Pathway Does Not Support the `"checkout`" task" + if ($ENV:BUILD_REASON -eq 'PullRequest') { + throw 'We dont support PRs' + } + + Write-Verbose -Verbose $ENV:BUILD_SOURCEBRANCH + $branchName = $ENV:BUILD_SOURCEBRANCH -replace '^refs/heads/' + Write-Verbose -Verbose "Branch Name: $branchName" + git clone --depth 1 --branch $branchName https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/PowerShell '$(Pipeline.Workspace)/PowerShell' + cd $(Pipeline.Workspace)/PowerShell + displayName: Checkout Powershell Repository diff --git a/.pipelines/templates/release-download-packages.yml b/.pipelines/templates/release-download-packages.yml new file mode 100644 index 00000000000..27a3098d1e1 --- /dev/null +++ b/.pipelines/templates/release-download-packages.yml @@ -0,0 +1,122 @@ +jobs: +- job: upload_packages + displayName: Upload packages + condition: succeeded() + pool: + type: windows + variables: + - template: ./variable/release-shared.yml@self + parameters: + REPOROOT: $(Build.SourcesDirectory) + SBOM: true + + steps: + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture environment variables + + - download: PSPackagesOfficial + artifact: drop_linux_package_deb + displayName: Download linux deb packages + + - download: PSPackagesOfficial + artifact: drop_linux_package_fxdependent + displayName: Download linux fx packages + + - download: PSPackagesOfficial + artifact: drop_linux_package_mariner_arm64 + displayName: Download linux mariner packages + + - download: PSPackagesOfficial + artifact: drop_linux_package_mariner_x64 + displayName: Download linux mariner x64 packages + + - download: PSPackagesOfficial + artifact: drop_linux_package_minSize + displayName: Download linux min packages + + - download: PSPackagesOfficial + artifact: drop_linux_package_rpm + displayName: Download linux rpm packages + + - download: PSPackagesOfficial + artifact: drop_linux_package_tar + displayName: Download linux tar packages + + - download: PSPackagesOfficial + artifact: drop_linux_package_tar_alpine + displayName: Download linux tar alpine packages + + - download: PSPackagesOfficial + artifact: drop_linux_package_tar_alpine_fxd + displayName: Download linux tar alpine fxd packages + + - download: PSPackagesOfficial + artifact: drop_linux_package_tar_arm + displayName: Download linux tar arm packages + + - download: PSPackagesOfficial + artifact: drop_linux_package_tar_arm64 + displayName: Download linux tar arm 64 packages + + - download: PSPackagesOfficial + artifact: drop_nupkg_build_nupkg + displayName: Download nupkg packages + + - download: PSPackagesOfficial + artifact: drop_windows_package_package_win_arm64 + displayName: Download windows arm64 packages + + - download: PSPackagesOfficial + artifact: drop_windows_package_package_win_fxdependent + displayName: Download windows fxdependent packages + + - download: PSPackagesOfficial + artifact: drop_windows_package_package_win_fxdependentWinDesktop + displayName: Download windows fxdependentWinDesktop packages + + - download: PSPackagesOfficial + artifact: drop_windows_package_package_win_minsize + displayName: Download windows minsize packages + + - download: PSPackagesOfficial + artifact: drop_windows_package_package_win_x64 + displayName: Download windows x64 packages + + - download: PSPackagesOfficial + artifact: drop_windows_package_package_win_x86 + displayName: Download windows x86 packages + + - download: PSPackagesOfficial + artifact: macos-pkgs + displayName: Download macos tar packages + + - download: PSPackagesOfficial + artifact: drop_mac_package_sign_package_macos_arm64 + displayName: Download macos arm packages + + - download: PSPackagesOfficial + artifact: drop_mac_package_sign_package_macos_x64 + displayName: Download macos x64 packages + + - pwsh: | + Get-ChildItem '$(Pipeline.Workspace)/PSPackagesOfficial' -Recurse | Select-Object -ExpandProperty FullName + displayName: 'Capture downloads' + + - pwsh: | + $PackagesPath = '$(Pipeline.Workspace)/PSPackagesOfficial' + Write-Verbose -Verbose "Copying Github Release files in $PackagesPath to use in Release Pipeline" + + Write-Verbose -Verbose "Creating output directory for GitHub Release files: $(ob_outputDirectory)/GitHubPackages" + New-Item -Path $(ob_outputDirectory)/GitHubPackages -ItemType Directory -Force + Get-ChildItem -Path "$PackagesPath/*" -Recurse | + Where-Object { $_.Extension -notin '.msix', '.nupkg' } | + Where-Object { $_.Extension -in '.gz', '.pkg', '.msi', '.zip', '.deb', '.rpm', '.zip' } | + Copy-Item -Destination $(ob_outputDirectory)/GitHubPackages -Recurse -Verbose + + Write-Verbose -Verbose "Creating output directory for NuGet packages: $(ob_outputDirectory)/NuGetPackages" + New-Item -Path $(ob_outputDirectory)/NuGetPackages -ItemType Directory -Force + Get-ChildItem -Path "$PackagesPath/*" -Recurse | + Where-Object { $_.Extension -eq '.nupkg' } | + Copy-Item -Destination $(ob_outputDirectory)/NuGetPackages -Recurse -Verbose + displayName: Copy downloads to Artifacts diff --git a/.pipelines/templates/release-githubtasks.yml b/.pipelines/templates/release-githubtasks.yml index c1e5d1a06a7..bfc500585b0 100644 --- a/.pipelines/templates/release-githubtasks.yml +++ b/.pipelines/templates/release-githubtasks.yml @@ -3,162 +3,114 @@ jobs: displayName: Create GitHub Release Draft condition: succeeded() pool: - type: windows + type: release + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: drop_DownloadPackages_upload_packages variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE - value: 1 - - group: 'mscodehub-code-read-akv' - - group: 'Azure Blob variable group' - - group: 'GitHubTokens' - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: ob_sdl_codeSignValidation_enabled - value: false - - name: ob_sdl_binskim_enabled - value: false - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - template: ./variable/release-shared.yml@self steps: - - checkout: self - clean: true - env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - - - template: release-SetReleaseTagAndContainerName.yml - - - pwsh: | - Get-ChildItem Env: + - task: PowerShell@2 + inputs: + targetType: inline + script: | + Get-ChildItem Env: | Out-String -Stream | write-Verbose -Verbose displayName: 'Capture Environment Variables' - - pwsh: | - # Uninstall Azure RM modules - $azRmModules = Get-Module -Name AzureRM* -ListAvailable - if ($azRmModules) { - $azRmModules | Remove-Module -Force - } - - # Install Az.Storage module if not already installed - if (-not (Get-Module -Name Az.Storage -ListAvailable)) { - Install-Module -Name Az.Storage -Force -AllowClobber -Scope CurrentUser -Verbose - } - displayName: Install Az.Storage module - - - task: AzurePowerShell@5 - displayName: Download packages from Azure Storage - inputs: - azureSubscription: az-blob-cicd-infra - scriptType: inlineScript - azurePowerShellVersion: LatestVersion - pwsh: true - inline: | - $storageAccount = "$(StorageAccount)" - $containerName = "$(AzureVersion)" - $destinationPath = "$(System.ArtifactsDirectory)" - - # Get storage account context - $storageContext = New-AzStorageContext -StorageAccountName $storageAccount - - $blobList = Get-AzStorageBlob -Container $containerName -Context $storageContext - foreach ($blob in $blobList) { - $blobName = $blob.Name - $destinationFile = Join-Path -Path $destinationPath -ChildPath $blobName - Get-AzStorageBlobContent -Container $containerName -Blob $blobName -Destination $destinationFile -Context $storageContext -Force - Write-Output "Downloaded $blobName to $destinationFile" - } + - template: release-install-pwsh.yml - $packagesPath = Get-ChildItem -Path $destinationPath\*.deb -Recurse -File | Select-Object -First 1 -ExpandProperty DirectoryName - Write-Host "sending -- vso[task.setvariable variable=PackagesRoot]$packagesPath" - Write-Host "##vso[task.setvariable variable=PackagesRoot]$packagesPath" + - template: release-checkout-pwsh-repo.yml - - pwsh: | - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty FullName - displayName: Capture downloaded artifacts + - template: release-SetReleaseTagAndContainerName.yml - - pwsh: | - git clone https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/Internal-PowerShellTeam-Tools '$(Pipeline.Workspace)/tools' + - task: PowerShell@2 + inputs: + targetType: inline + pwsh: true + script: | + git clone --depth 1 https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/Internal-PowerShellTeam-Tools '$(Pipeline.Workspace)/tools' displayName: Clone Internal-Tools repository - - pwsh: | - $Path = "$(System.ArtifactsDirectory)" - $OutputPath = Join-Path $Path 'hashes.sha256' - $srcPaths = @($Path) - $packages = Get-ChildItem -Path $srcPaths -Include * -Recurse -File - $checksums = $packages | - ForEach-Object { - Write-Verbose -Verbose "Generating checksum file for $($_.FullName)" - $packageName = $_.Name - $hash = (Get-FileHash -Path $_.FullName -Algorithm SHA256).Hash.ToLower() - # the '*' before the packagename signifies it is a binary - "$hash *$packageName" - } - $checksums | Out-File -FilePath $OutputPath -Force - $fileContent = Get-Content -Path $OutputPath -Raw | Out-String - Write-Verbose -Verbose -Message $fileContent + - task: PowerShell@2 + inputs: + targetType: inline + pwsh: true + script: | + $Path = "$(Pipeline.Workspace)/GitHubPackages" + $OutputPath = Join-Path $Path 'hashes.sha256' + $packages = Get-ChildItem -Path $Path -Include * -Recurse -File + $checksums = $packages | + ForEach-Object { + Write-Verbose -Verbose "Generating checksum file for $($_.FullName)" + $packageName = $_.Name + $hash = (Get-FileHash -Path $_.FullName -Algorithm SHA256).Hash.ToLower() + # the '*' before the packagename signifies it is a binary + "$hash *$packageName" + } + $checksums | Out-File -FilePath $OutputPath -Force + $fileContent = Get-Content -Path $OutputPath -Raw | Out-String + Write-Verbose -Verbose -Message $fileContent displayName: Add sha256 hashes - - pwsh: | - $releaseVersion = '$(ReleaseTag)' -replace '^v','' - $vstsCommandString = "vso[task.setvariable variable=ReleaseVersion]$releaseVersion" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" + - task: PowerShell@2 + inputs: + targetType: inline + pwsh: true + script: | + $releaseVersion = '$(ReleaseTag)' -replace '^v','' + $vstsCommandString = "vso[task.setvariable variable=ReleaseVersion]$releaseVersion" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" displayName: 'Set release version' - - pwsh: | - Import-module '$(Pipeline.Workspace)/tools/Scripts/GitHubRelease.psm1' - $releaseVersion = '$(ReleaseTag)' -replace '^v','' - $semanticVersion = [System.Management.Automation.SemanticVersion]$releaseVersion + - task: PowerShell@2 + inputs: + targetType: inline + pwsh: true + script: | + Get-ChildItem $(Pipeline.Workspace) -recurse | Select-Object -ExpandProperty FullName + displayName: List all files in the workspace + + - task: PowerShell@2 + inputs: + targetType: inline + pwsh: true + script: | + Import-module '$(Pipeline.Workspace)/tools/Scripts/GitHubRelease.psm1' + $releaseVersion = '$(ReleaseTag)' -replace '^v','' + $semanticVersion = [System.Management.Automation.SemanticVersion]$releaseVersion - $isPreview = $semanticVersion.PreReleaseLabel -ne $null + $isPreview = $semanticVersion.PreReleaseLabel -ne $null - $fileName = if ($isPreview) { - "preview.md" - } - else { - $semanticVersion.Major.ToString() + "." + $semanticVersion.Minor.ToString() + ".md" - } + $fileName = if ($isPreview) { + "preview.md" + } + else { + $semanticVersion.Major.ToString() + "." + $semanticVersion.Minor.ToString() + ".md" + } - $filePath = "$env:BUILD_SOURCESDIRECTORY/PowerShell/CHANGELOG/$fileName" - Write-Verbose -Verbose "Selected Log file: $filePath" + $filePath = "$(Pipeline.Workspace)/PowerShell/CHANGELOG/$fileName" + Write-Verbose -Verbose "Selected Log file: $filePath" - if (-not (Test-Path $filePath)) { - throw "$filePath not found" - } + if (-not (Test-Path $filePath)) { + throw "$filePath not found" + } - $changelog = Get-Content -Path $filePath + $changelog = Get-Content -Path $filePath - $startPattern = "^## \[" + ([regex]::Escape($releaseVersion)) + "\]" - $endPattern = "^## \[{0}\.{1}\.{2}*" -f $semanticVersion.Major, $semanticVersion.Minor, $semanticVersion.Patch + $startPattern = "^## \[" + ([regex]::Escape($releaseVersion)) + "\]" + $endPattern = "^## \[{0}\.{1}\.{2}*" -f $semanticVersion.Major, $semanticVersion.Minor, $semanticVersion.Patch - $clContent = $changelog | ForEach-Object { - if ($_ -match $startPattern) { $outputLine = $true } - elseif ($_ -match $endPattern) { $outputLine = $false } - if ($outputLine) { $_} - } | Out-String + $clContent = $changelog | ForEach-Object { + if ($_ -match $startPattern) { $outputLine = $true } + elseif ($_ -match $endPattern) { $outputLine = $false } + if ($outputLine) { $_} + } | Out-String - Write-Verbose -Verbose "Selected content: `n$clContent" + Write-Verbose -Verbose "Selected content: `n$clContent" - Publish-ReleaseDraft -Tag '$(ReleaseTag)' -Name '$(ReleaseTag) Release of PowerShell' -Description $clContent -User PowerShell -Repository PowerShell -PackageFolder $(PackagesRoot) -Token $(GitHubReleasePat) + Publish-ReleaseDraft -Tag '$(ReleaseTag)' -Name '$(ReleaseTag) Release of PowerShell' -Description $clContent -User PowerShell -Repository PowerShell -PackageFolder "$(Pipeline.Workspace)/GitHubPackages" -Token $(GitHubReleasePat) displayName: Publish Release Draft - -- template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Push Git Tag - jobName: PushGitTag - dependsOnJob: GithubReleaseDraft - instructions: | - Push the git tag to upstream - -- template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Make Draft Public - jobName: DraftPublic - dependsOnJob: PushGitTag - instructions: | - Make the GitHub Release Draft Public diff --git a/.pipelines/templates/release-install-pwsh.yml b/.pipelines/templates/release-install-pwsh.yml new file mode 100644 index 00000000000..9d7080a7e78 --- /dev/null +++ b/.pipelines/templates/release-install-pwsh.yml @@ -0,0 +1,34 @@ +steps: + - task: PowerShell@2 + inputs: + targetType: inline + script: | + $localInstallerPath = Get-ChildItem -Path "$(Pipeline.Workspace)/GitHubPackages" -Filter '*win-x64.msi' | Select-Object -First 1 -ExpandProperty FullName + if (Test-Path -Path $localInstallerPath) { + Write-Verbose -Verbose "Installer found at $localInstallerPath" + } else { + throw "Installer not found" + } + Write-Verbose -Verbose "Installing PowerShell via msiexec" + Start-Process -FilePath msiexec -ArgumentList "/package $localInstallerPath /quiet REGISTER_MANIFEST=1" -Wait -NoNewWindow + $pwshPath = Get-ChildItem -Directory -Path 'C:\Program Files\PowerShell\7*' | Select-Object -First 1 -ExpandProperty FullName + if (Test-Path -Path $pwshPath) { + Write-Verbose -Verbose "PowerShell installed at $pwshPath" + Write-Verbose -Verbose "Adding pwsh to env:PATH" + Write-Host "##vso[task.prependpath]$pwshPath" + } else { + throw "PowerShell not installed" + } + displayName: Install pwsh 7 + + - task: PowerShell@2 + inputs: + targetType: inline + pwsh: true + script: | + Write-Verbose -Verbose "Pwsh 7 Installed" + Write-Verbose -Verbose "env:Path: " + $env:PATH -split ';' | ForEach-Object { + Write-Verbose -Verbose $_ + } + displayName: Check pwsh 7 installation diff --git a/.pipelines/templates/release-publish-nuget.yml b/.pipelines/templates/release-publish-nuget.yml index e9bebf5d93e..b29f29c3dd5 100644 --- a/.pipelines/templates/release-publish-nuget.yml +++ b/.pipelines/templates/release-publish-nuget.yml @@ -8,31 +8,20 @@ jobs: displayName: Publish to NuGet condition: succeeded() pool: - type: windows + type: release + os: windows + templateContext: + inputs: + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_upload_upload_packages variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE - value: 1 - - group: 'mscodehub-code-read-akv' - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: ob_sdl_codeSignValidation_enabled - value: false - - name: ob_sdl_binskim_enabled - value: false - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - template: ./variable/release-shared.yml@self steps: - - checkout: self - clean: true - env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + - template: release-install-pwsh.yml + + - template: release-checkout-pwsh-repo.yml - template: release-SetReleaseTagAndContainerName.yml @@ -40,23 +29,20 @@ jobs: Get-ChildItem Env: displayName: 'Capture Environment Variables' - - download: PSPackagesOfficial - artifact: drop_nupkg_build_nupkg - displayName: Download nuget packages - - pwsh: | #Exclude all global tool packages. Their names start with 'PowerShell.' $null = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/release" - Copy-Item "$ENV:PIPELINE_WORKSPACE/PSPackagesOfficial/drop_nupkg_build_nupkg/*.nupkg" -Destination "$(Pipeline.Workspace)/release" -Exclude "PowerShell.*.nupkg" -Force -Verbose + Copy-Item "$(Pipeline.Workspace)/NuGetPackages/*.nupkg" -Destination "$(Pipeline.Workspace)/release" -Exclude "PowerShell.*.nupkg" -Force -Verbose $releaseVersion = '$(VERSION)' - $globalToolPath = "$ENV:PIPELINE_WORKSPACE/PSPackagesOfficial/drop_nupkg_build_nupkg/PowerShell.$releaseVersion.nupkg" + $globalToolPath = "$(Pipeline.Workspace)/NuGetPackages/PowerShell.$releaseVersion.nupkg" if ($releaseVersion -notlike '*-*') { # Copy the global tool package for stable releases Copy-Item $globalToolPath -Destination "$(Pipeline.Workspace)/release" } + Write-Verbose -Verbose "The .nupkgs below will be pushed:" Get-ChildItem "$(Pipeline.Workspace)/release" -recurse displayName: Download and capture nupkgs condition: and(ne('${{ parameters.skipPublish }}', 'false'), succeeded()) diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index 2bb48767ae4..50a4a676fee 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -5,6 +5,8 @@ jobs: pool: type: windows variables: + - name: ob_sdl_sbom_enabled + value: false - name: runCodesignValidationInjection value: false - name: NugetSecurityAnalysisWarningLevel @@ -233,6 +235,24 @@ jobs: Get-ChildItem '$(Build.ArtifactStagingDirectory)/downloads' | Select-Object -ExpandProperty FullName displayName: 'Capture downloads' + # - pwsh: | + # Write-Verbose -Verbose "Copying Github Release files in $(Build.ArtifactStagingDirectory)/downloads to use in Release Pipeline" + # + # Write-Verbose -Verbose "Creating output directory for GitHub Release files: $(ob_outputDirectory)/GitHubPackages" + # New-Item -Path $(ob_outputDirectory)/GitHubPackages -ItemType Directory -Force + # Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)/downloads/*" -Recurse | + # Where-Object { $_.Extension -notin '.msix', '.nupkg' } | + # ForEach-Object { Write-Verbose -Verbose $_.FullName ; $_ } | + # Copy-Item -Destination $(ob_outputDirectory)/GitHubPackages -Recurse + # + # Write-Verbose -Verbose "Creating output directory for NuGet packages: $(ob_outputDirectory)/NuGetPackages" + # New-Item -Path $(ob_outputDirectory)/NuGetPackages -ItemType Directory -Force + # Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)/downloads/*" -Recurse | + # Where-Object { $_.Extension -eq '.nupkg' } | + # ForEach-Object { Write-Verbose -Verbose $_.FullName ; $_ } | + # Copy-Item -Destination $(ob_outputDirectory)/NuGetPackages -Recurse + # displayName: Copy downloads to Artifacts + - pwsh: | # Create output directory for packages which have been uploaded to blob storage New-Item -Path $(Build.ArtifactStagingDirectory)/uploaded -ItemType Directory -Force diff --git a/.pipelines/templates/variable/release-shared.yml b/.pipelines/templates/variable/release-shared.yml new file mode 100644 index 00000000000..92ab56199d4 --- /dev/null +++ b/.pipelines/templates/variable/release-shared.yml @@ -0,0 +1,32 @@ +parameters: + - name: REPOROOT + type: string + default: $(Build.SourcesDirectory)\PowerShell + - name: SBOM + type: boolean + default: false + +variables: + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_sbom_enabled + value: ${{ parameters.SBOM }} + - name: runCodesignValidationInjection + value: false + - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + value: 1 + - group: 'mscodehub-code-read-akv' + - group: 'Azure Blob variable group' + - group: 'GitHubTokens' + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_codeSignValidation_enabled + value: false + - name: ob_sdl_binskim_enabled + value: false + - name: ob_sdl_tsa_configFile + value: ${{ parameters.REPOROOT }}\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: ${{ parameters.REPOROOT }}\.config\suppress.json + - name: ob_sdl_codeql_compiled_enabled + value: false From 0e5c5aa8f629b386ef413c685a3eb1c96db9105d Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 15 Nov 2024 15:46:51 -0800 Subject: [PATCH 054/275] Update nuget publish to use Deploy Box (#24596) (#24597) --- .pipelines/templates/release-publish-nuget.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/release-publish-nuget.yml b/.pipelines/templates/release-publish-nuget.yml index b29f29c3dd5..db0978e0b0b 100644 --- a/.pipelines/templates/release-publish-nuget.yml +++ b/.pipelines/templates/release-publish-nuget.yml @@ -13,8 +13,8 @@ jobs: templateContext: inputs: - input: pipelineArtifact - pipeline: PSPackagesOfficial - artifactName: drop_upload_upload_packages + artifactName: drop_DownloadPackages_upload_packages + variables: - template: ./variable/release-shared.yml@self From c2353537f81c94072d326141cf048b4035b2c0fa Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Tue, 14 Jan 2025 13:34:25 -0800 Subject: [PATCH 055/275] Update machine pool for copy blob and upload buildinfo stage (#24587) (#24776) Co-authored-by: Aditya Patwardhan --- .pipelines/PowerShell-Release-Official.yml | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index f025c42f460..03defa5d128 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -79,7 +79,7 @@ resources: extends: template: v2/OneBranch.Official.CrossPlat.yml@templates parameters: - release: + release: category: NonAzure featureFlags: WindowsHostVersion: @@ -277,14 +277,14 @@ extends: - stage: PublishGitHubRelease displayName: Publish GitHub Release - dependsOn: + dependsOn: - DownloadPackages - UpdateChangeLog variables: ob_release_environment: Production jobs: - template: /.pipelines/templates/release-githubtasks.yml@self - + - stage: PushGitTagAndMakeDraftPublic displayName: Push Git Tag and Make Draft Public dependsOn: PublishGitHubRelease @@ -294,8 +294,8 @@ extends: displayName: Push Git Tag jobName: PushGitTag instructions: | - Push the git tag to upstream - + Push the git tag to upstream + - template: /.pipelines/templates/approvalJob.yml@self parameters: displayName: Make Draft Public @@ -303,17 +303,17 @@ extends: jobName: DraftPublic instructions: | Make the GitHub Release Draft Public - + - stage: BlobPublic displayName: Make Blob Public - dependsOn: + dependsOn: - UpdateChangeLog - PushGitTagAndMakeDraftPublic jobs: - template: /.pipelines/templates/release-MakeBlobPublic.yml@self parameters: - SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} - + SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} + - stage: PublishNuGet displayName: Publish NuGet dependsOn: PushGitTagAndMakeDraftPublic @@ -420,8 +420,8 @@ extends: - stage: ChangesToMaster displayName: Ensure changes are in GH master - dependsOn: - - PublishNuGet + dependsOn: + - PublishNuGet - PublishPMC jobs: - template: /.pipelines/templates/approvalJob.yml@self @@ -454,7 +454,7 @@ extends: - stage: ReleaseClose displayName: Finish Release - dependsOn: + dependsOn: - ReleaseToMU - ReleaseSymbols - ReleaseSnap From 7979599d32df0b6370190ad74d095b64627da5bc Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 15 Jan 2025 09:52:49 -0800 Subject: [PATCH 056/275] Update `HelpInfoUri` for 7.5 (#24610) (#24777) Co-authored-by: Sean Wheeler --- .../Microsoft.PowerShell.Host.psd1 | 2 +- .../Microsoft.PowerShell.Management.psd1 | 2 +- .../Microsoft.PowerShell.Security.psd1 | 2 +- .../Microsoft.PowerShell.Utility.psd1 | 2 +- src/Modules/Windows/CimCmdlets/CimCmdlets.psd1 | 2 +- .../Microsoft.PowerShell.Diagnostics.psd1 | 2 +- .../Microsoft.PowerShell.Management.psd1 | 2 +- .../Microsoft.PowerShell.Security.psd1 | 2 +- .../Microsoft.PowerShell.Utility.psd1 | 2 +- .../Microsoft.WSMan.Management.psd1 | 2 +- .../Windows/PSDiagnostics/PSDiagnostics.psd1 | 2 +- .../help/UpdatableHelpCommandBase.cs | 14 +++++++------- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Modules/Shared/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 b/src/Modules/Shared/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 index e6d616aa61d..3c2581795f7 100644 --- a/src/Modules/Shared/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 +++ b/src/Modules/Shared/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 @@ -10,5 +10,5 @@ FunctionsToExport = @() CmdletsToExport="Start-Transcript", "Stop-Transcript" AliasesToExport = @() NestedModules="Microsoft.PowerShell.ConsoleHost.dll" -HelpInfoURI = 'https://aka.ms/powershell73-help' +HelpInfoURI = 'https://aka.ms/powershell75-help' } diff --git a/src/Modules/Unix/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 b/src/Modules/Unix/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 index 6eb576cdf03..21563c1da7c 100644 --- a/src/Modules/Unix/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 +++ b/src/Modules/Unix/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 @@ -7,7 +7,7 @@ ModuleVersion="7.0.0.0" CompatiblePSEditions = @("Core") PowerShellVersion="3.0" NestedModules="Microsoft.PowerShell.Commands.Management.dll" -HelpInfoURI = 'https://aka.ms/powershell73-help' +HelpInfoURI = 'https://aka.ms/powershell75-help' FunctionsToExport = @() AliasesToExport = @("gcb", "gtz", "scb") CmdletsToExport=@("Add-Content", diff --git a/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 b/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 index 8268326aa74..adab0df2849 100644 --- a/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 +++ b/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 @@ -10,5 +10,5 @@ FunctionsToExport = @() CmdletsToExport = "Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "ConvertFrom-SecureString", "ConvertTo-SecureString", "Get-PfxCertificate" , "Protect-CmsMessage", "Unprotect-CmsMessage", "Get-CmsMessage" AliasesToExport = @() NestedModules = "Microsoft.PowerShell.Security.dll" -HelpInfoURI = 'https://aka.ms/powershell73-help' +HelpInfoURI = 'https://aka.ms/powershell75-help' } diff --git a/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 index 1d31d5889e8..df841837696 100644 --- a/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 +++ b/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 @@ -31,5 +31,5 @@ CmdletsToExport = @( FunctionsToExport = @() AliasesToExport = @('fhx') NestedModules = @("Microsoft.PowerShell.Commands.Utility.dll") -HelpInfoURI = 'https://aka.ms/powershell73-help' +HelpInfoURI = 'https://aka.ms/powershell75-help' } diff --git a/src/Modules/Windows/CimCmdlets/CimCmdlets.psd1 b/src/Modules/Windows/CimCmdlets/CimCmdlets.psd1 index 93c68321ca1..734fe45016d 100644 --- a/src/Modules/Windows/CimCmdlets/CimCmdlets.psd1 +++ b/src/Modules/Windows/CimCmdlets/CimCmdlets.psd1 @@ -14,5 +14,5 @@ CmdletsToExport= "Get-CimAssociatedInstance", "Get-CimClass", "Get-CimInstance", "Remove-CimSession","Set-CimInstance", "Export-BinaryMiLog","Import-BinaryMiLog" AliasesToExport = "gcim","scim","ncim", "rcim","icim","gcai","rcie","ncms","rcms","gcms","ncso","gcls" -HelpInfoUri="https://aka.ms/powershell73-help" +HelpInfoUri="https://aka.ms/powershell75-help" } diff --git a/src/Modules/Windows/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 b/src/Modules/Windows/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 index 50282d8d5b8..7f77777b137 100644 --- a/src/Modules/Windows/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 +++ b/src/Modules/Windows/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 @@ -12,5 +12,5 @@ AliasesToExport = @() NestedModules="Microsoft.PowerShell.Commands.Diagnostics.dll" TypesToProcess="GetEvent.types.ps1xml" FormatsToProcess="Event.format.ps1xml", "Diagnostics.format.ps1xml" -HelpInfoURI = 'https://aka.ms/powershell73-help' +HelpInfoURI = 'https://aka.ms/powershell75-help' } diff --git a/src/Modules/Windows/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 b/src/Modules/Windows/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 index 0b49f178b25..f7582920935 100644 --- a/src/Modules/Windows/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 +++ b/src/Modules/Windows/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 @@ -7,7 +7,7 @@ ModuleVersion="7.0.0.0" CompatiblePSEditions = @("Core") PowerShellVersion="3.0" NestedModules="Microsoft.PowerShell.Commands.Management.dll" -HelpInfoURI = 'https://aka.ms/powershell73-help' +HelpInfoURI = 'https://aka.ms/powershell75-help' FunctionsToExport = @() AliasesToExport = @("gcb", "gin", "gtz", "scb", "stz") CmdletsToExport=@("Add-Content", diff --git a/src/Modules/Windows/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 b/src/Modules/Windows/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 index 7470c795fdc..0953b2d1cca 100644 --- a/src/Modules/Windows/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 +++ b/src/Modules/Windows/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 @@ -14,5 +14,5 @@ NestedModules = "Microsoft.PowerShell.Security.dll" # We declare 'Microsoft.PowerShell.Security.dll' in 'RequiredAssemblies' so as to make sure it's loaded before the type file processing. RequiredAssemblies = "Microsoft.PowerShell.Security.dll" TypesToProcess = "Security.types.ps1xml" -HelpInfoURI = 'https://aka.ms/powershell73-help' +HelpInfoURI = 'https://aka.ms/powershell75-help' } diff --git a/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 index 33db09feb9c..2043543a8a5 100644 --- a/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 +++ b/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 @@ -29,5 +29,5 @@ CmdletsToExport = @( FunctionsToExport = @() AliasesToExport = @('fhx') NestedModules = @("Microsoft.PowerShell.Commands.Utility.dll") -HelpInfoURI = 'https://aka.ms/powershell73-help' +HelpInfoURI = 'https://aka.ms/powershell75-help' } diff --git a/src/Modules/Windows/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1 b/src/Modules/Windows/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1 index 5eb367b7e7f..ced706c9fde 100644 --- a/src/Modules/Windows/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1 +++ b/src/Modules/Windows/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1 @@ -11,5 +11,5 @@ CmdletsToExport="Disable-WSManCredSSP", "Enable-WSManCredSSP", "Get-WSManCredSSP AliasesToExport = @() NestedModules="Microsoft.WSMan.Management.dll" FormatsToProcess="WSMan.format.ps1xml" -HelpInfoURI = 'https://aka.ms/powershell73-help' +HelpInfoURI = 'https://aka.ms/powershell75-help' } diff --git a/src/Modules/Windows/PSDiagnostics/PSDiagnostics.psd1 b/src/Modules/Windows/PSDiagnostics/PSDiagnostics.psd1 index 6185b589a82..3b53d6740e5 100644 --- a/src/Modules/Windows/PSDiagnostics/PSDiagnostics.psd1 +++ b/src/Modules/Windows/PSDiagnostics/PSDiagnostics.psd1 @@ -10,5 +10,5 @@ FunctionsToExport="Disable-PSTrace","Disable-PSWSManCombinedTrace","Disable-WSManTrace","Enable-PSTrace","Enable-PSWSManCombinedTrace","Enable-WSManTrace","Get-LogProperties","Set-LogProperties","Start-Trace","Stop-Trace" CmdletsToExport = @() AliasesToExport = @() - HelpInfoUri="https://aka.ms/powershell73-help" + HelpInfoUri="https://aka.ms/powershell75-help" } diff --git a/src/System.Management.Automation/help/UpdatableHelpCommandBase.cs b/src/System.Management.Automation/help/UpdatableHelpCommandBase.cs index dad75a6b69c..687faa68246 100644 --- a/src/System.Management.Automation/help/UpdatableHelpCommandBase.cs +++ b/src/System.Management.Automation/help/UpdatableHelpCommandBase.cs @@ -179,13 +179,13 @@ static UpdatableHelpCommandBase() // NOTE: The HelpInfoUri must be updated with each release. - s_metadataCache.Add("Microsoft.PowerShell.Diagnostics", "https://aka.ms/powershell73-help"); - s_metadataCache.Add("Microsoft.PowerShell.Core", "https://aka.ms/powershell73-help"); - s_metadataCache.Add("Microsoft.PowerShell.Utility", "https://aka.ms/powershell73-help"); - s_metadataCache.Add("Microsoft.PowerShell.Host", "https://aka.ms/powershell73-help"); - s_metadataCache.Add("Microsoft.PowerShell.Management", "https://aka.ms/powershell73-help"); - s_metadataCache.Add("Microsoft.PowerShell.Security", "https://aka.ms/powershell73-help"); - s_metadataCache.Add("Microsoft.WSMan.Management", "https://aka.ms/powershell73-help"); + s_metadataCache.Add("Microsoft.PowerShell.Diagnostics", "https://aka.ms/powershell75-help"); + s_metadataCache.Add("Microsoft.PowerShell.Core", "https://aka.ms/powershell75-help"); + s_metadataCache.Add("Microsoft.PowerShell.Utility", "https://aka.ms/powershell75-help"); + s_metadataCache.Add("Microsoft.PowerShell.Host", "https://aka.ms/powershell75-help"); + s_metadataCache.Add("Microsoft.PowerShell.Management", "https://aka.ms/powershell75-help"); + s_metadataCache.Add("Microsoft.PowerShell.Security", "https://aka.ms/powershell75-help"); + s_metadataCache.Add("Microsoft.WSMan.Management", "https://aka.ms/powershell75-help"); } /// From aa8f9a3bd7928b7bb8453ea6a6dc893b3e189407 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 15 Jan 2025 10:02:50 -0800 Subject: [PATCH 057/275] Deploy Box Update (#24632) (#24779) * reverted one time changes * added ob_outputDirectory * added mscode variable group * forgot to move psm1 to ToolArtifact folder * added pipeline name and passing toolartifact through context * added tools * PSPackagesOfficial * removed tools clone * added uploading CL * verbose statements for release tag and release version * trying to regerence variable with step name * checking REPOROOT * removed get child item * Deploy box update * nuget template context pipeline name correction * changed other instances of releasetag * added -Verbose to Copy-Item * checkout task, instead of git clone * changed to Build.SourcesDirectory * removed path specification * removed path * added tsa and credscan * not copying tools to artifacts * official and production --------- Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung --- .pipelines/PowerShell-Release-Official.yml | 19 +++-- .../release-SetReleaseTagandContainerName.yml | 6 +- .../templates/release-SetTagAndTools.yml | 75 +++++++++++++++++++ .pipelines/templates/release-githubtasks.yml | 53 ++++--------- .../templates/release-publish-nuget.yml | 15 ++-- .../release-validate-packagenames.yml | 2 +- .pipelines/templates/uploadToAzure.yml | 32 ++++---- .../templates/variable/release-shared.yml | 10 +++ 8 files changed, 136 insertions(+), 76 deletions(-) create mode 100644 .pipelines/templates/release-SetTagAndTools.yml diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 03defa5d128..6a17139e05e 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -63,6 +63,10 @@ resources: type: git name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main + - repository: PSInternalTools + type: git + name: PowerShellCore/Internal-PowerShellTeam-Tools + ref: refs/heads/master pipelines: - pipeline: CoOrdinatedBuildPipeline @@ -110,17 +114,14 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - stage: DownloadPackages - displayName: 'Download Packages' - dependsOn: [] + - stage: setReleaseTagAndUploadTools + displayName: 'Set Release Tag and Upload Tools' jobs: - - template: /.pipelines/templates/release-download-packages.yml@self + - template: /.pipelines/templates/release-SetTagAndTools.yml@self - stage: msixbundle displayName: 'Create MSIX Bundle' dependsOn: [] - variables: - ob_release_environment: Test jobs: - template: /.pipelines/templates/release-create-msix.yml@self @@ -278,7 +279,7 @@ extends: - stage: PublishGitHubRelease displayName: Publish GitHub Release dependsOn: - - DownloadPackages + - setReleaseTagAndUploadTools - UpdateChangeLog variables: ob_release_environment: Production @@ -316,7 +317,9 @@ extends: - stage: PublishNuGet displayName: Publish NuGet - dependsOn: PushGitTagAndMakeDraftPublic + dependsOn: + - setReleaseTagAndUploadTools + - PushGitTagAndMakeDraftPublic variables: ob_release_environment: Production jobs: diff --git a/.pipelines/templates/release-SetReleaseTagandContainerName.yml b/.pipelines/templates/release-SetReleaseTagandContainerName.yml index 7e88624b45c..667132f5f90 100644 --- a/.pipelines/templates/release-SetReleaseTagandContainerName.yml +++ b/.pipelines/templates/release-SetReleaseTagandContainerName.yml @@ -8,9 +8,10 @@ steps: } $releaseTag = $Branch -replace '^.*((release|rebuild)/)' - $vstsCommandString = "vso[task.setvariable variable=$Variable]$releaseTag" + $vstsCommandString = "vso[task.setvariable variable=$Variable;isOutput=true]$releaseTag" Write-Verbose -Message "setting $Variable to $releaseTag" -Verbose Write-Host -Object "##$vstsCommandString" + name: OutputReleaseTag displayName: Set Release Tag - pwsh: | @@ -20,7 +21,8 @@ steps: Write-Host "##$vstsCommandString" $version = '$(ReleaseTag)'.ToLowerInvariant().Substring(1) - $vstsCommandString = "vso[task.setvariable variable=Version]$version" + $vstsCommandString = "vso[task.setvariable variable=Version;isOutput=true]$version" Write-Host ("sending " + $vstsCommandString) Write-Host "##$vstsCommandString" + name: OutputVersion displayName: Set container name diff --git a/.pipelines/templates/release-SetTagAndTools.yml b/.pipelines/templates/release-SetTagAndTools.yml new file mode 100644 index 00000000000..7b8a946e323 --- /dev/null +++ b/.pipelines/templates/release-SetTagAndTools.yml @@ -0,0 +1,75 @@ +jobs: +- job: SetTagAndTools + displayName: Set Tag and Tools + condition: succeeded() + pool: + type: windows + variables: + - group: 'mscodehub-code-read-akv' + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + steps: + - template: release-SetReleaseTagandContainerName.yml@self + + - checkout: self + clean: true + env: + ob_restore_phase: true + + - checkout: PSInternalTools + clean: true + env: + ob_restore_phase: true + + - pwsh: | + New-Item -ItemType Directory -Path '$(Pipeline.Workspace)/ToolArtifact' + Get-ChildItem -Path '$(Build.SourcesDirectory)/Internal-PowerShellTeam-Tools/Scripts' -Filter 'GitHubRelease.psm1' -ErrorAction SilentlyContinue | + Copy-Item -Destination '$(Pipeline.Workspace)/ToolArtifact' -Verbose + displayName: Move GitHub Tool + + - task: onebranch.pipeline.signing@1 + displayName: Sign Tools + inputs: + command: 'sign' + signing_profile: internal_azure_service + files_to_sign: '*.ps1;*.psm1' + search_root: '$(Pipeline.Workspace)/ToolArtifact' + + - pwsh: | + Write-Verbose -Verbose "Creating output directory for release tools: $(ob_outputDirectory)/ToolArtifact" + New-Item -Path $(ob_outputDirectory)/ToolArtifact -ItemType Directory -Force + Get-ChildItem -Path "$(Pipeline.Workspace)/ToolArtifact/*" -Recurse | + Copy-Item -Destination $(ob_outputDirectory)/ToolArtifact -Recurse -Verbose + displayName: Upload Tools + + - pwsh: | + Write-Verbose -Verbose "Release Tag: $(OutputReleaseTag.releaseTag)" + $releaseVersion = '$(OutputReleaseTag.releaseTag)' -replace '^v','' + Write-Verbose -Verbose "Release Version: $releaseVersion" + $semanticVersion = [System.Management.Automation.SemanticVersion]$releaseVersion + + $isPreview = $semanticVersion.PreReleaseLabel -ne $null + + $fileName = if ($isPreview) { + "preview.md" + } + else { + $semanticVersion.Major.ToString() + "." + $semanticVersion.Minor.ToString() + ".md" + } + + $filePath = "$(Build.SourcesDirectory)/PowerShell/CHANGELOG/$fileName" + Write-Verbose -Verbose "Selected Log file: $filePath" + + if (-not (Test-Path -Path $filePath)) { + Write-Error "Changelog file not found: $filePath" + exit 1 + } + + Write-Verbose -Verbose "Creating output directory for CHANGELOG: $(ob_outputDirectory)/CHANGELOG" + New-Item -Path $(ob_outputDirectory)/CHANGELOG -ItemType Directory -Force + Copy-Item -Path $filePath -Destination $(ob_outputDirectory)/CHANGELOG + displayName: Upload Changelog diff --git a/.pipelines/templates/release-githubtasks.yml b/.pipelines/templates/release-githubtasks.yml index bfc500585b0..ed3ae028934 100644 --- a/.pipelines/templates/release-githubtasks.yml +++ b/.pipelines/templates/release-githubtasks.yml @@ -8,32 +8,26 @@ jobs: templateContext: inputs: - input: pipelineArtifact - artifactName: drop_DownloadPackages_upload_packages + artifactName: drop_setReleaseTagAndUploadTools_SetTagAndTools + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_upload_upload_packages variables: - - template: ./variable/release-shared.yml@self + - template: ./variable/release-shared.yml@self + parameters: + RELEASETAG: $[ stageDependencies.setReleaseTagAndUploadTools.SetTagAndTools.outputs['OutputReleaseTag.releaseTag'] ] steps: - task: PowerShell@2 inputs: targetType: inline script: | - Get-ChildItem Env: | Out-String -Stream | write-Verbose -Verbose + Write-Verbose -Verbose "Release Tag: $(ReleaseTag)" + Get-ChildItem Env: | Out-String -Stream | Write-Verbose -Verbose displayName: 'Capture Environment Variables' - template: release-install-pwsh.yml - - template: release-checkout-pwsh-repo.yml - - - template: release-SetReleaseTagAndContainerName.yml - - - task: PowerShell@2 - inputs: - targetType: inline - pwsh: true - script: | - git clone --depth 1 https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/Internal-PowerShellTeam-Tools '$(Pipeline.Workspace)/tools' - displayName: Clone Internal-Tools repository - - task: PowerShell@2 inputs: targetType: inline @@ -55,17 +49,6 @@ jobs: Write-Verbose -Verbose -Message $fileContent displayName: Add sha256 hashes - - task: PowerShell@2 - inputs: - targetType: inline - pwsh: true - script: | - $releaseVersion = '$(ReleaseTag)' -replace '^v','' - $vstsCommandString = "vso[task.setvariable variable=ReleaseVersion]$releaseVersion" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: 'Set release version' - - task: PowerShell@2 inputs: targetType: inline @@ -79,21 +62,11 @@ jobs: targetType: inline pwsh: true script: | - Import-module '$(Pipeline.Workspace)/tools/Scripts/GitHubRelease.psm1' - $releaseVersion = '$(ReleaseTag)' -replace '^v','' - $semanticVersion = [System.Management.Automation.SemanticVersion]$releaseVersion - - $isPreview = $semanticVersion.PreReleaseLabel -ne $null - - $fileName = if ($isPreview) { - "preview.md" - } - else { - $semanticVersion.Major.ToString() + "." + $semanticVersion.Minor.ToString() + ".md" - } + Import-module '$(Pipeline.Workspace)/ToolArtifact/GitHubRelease.psm1' + Write-Verbose -Verbose "Available modules: " + Get-Module | Write-Verbose -Verbose - $filePath = "$(Pipeline.Workspace)/PowerShell/CHANGELOG/$fileName" - Write-Verbose -Verbose "Selected Log file: $filePath" + $filePath = Get-ChildItem -Path "$(Pipeline.Workspace)/CHANGELOG" -Filter '*.md' | Select-Object -First 1 -ExpandProperty FullName if (-not (Test-Path $filePath)) { throw "$filePath not found" diff --git a/.pipelines/templates/release-publish-nuget.yml b/.pipelines/templates/release-publish-nuget.yml index db0978e0b0b..78338d7d87c 100644 --- a/.pipelines/templates/release-publish-nuget.yml +++ b/.pipelines/templates/release-publish-nuget.yml @@ -13,20 +13,19 @@ jobs: templateContext: inputs: - input: pipelineArtifact - artifactName: drop_DownloadPackages_upload_packages - + pipeline: PSPackagesOfficial + artifactName: drop_upload_upload_packages variables: - template: ./variable/release-shared.yml@self + parameters: + VERSION: $[ stageDependencies.setReleaseTagAndUploadTools.SetTagAndTools.outputs['OutputVersion.Version'] ] steps: - template: release-install-pwsh.yml - - template: release-checkout-pwsh-repo.yml - - - template: release-SetReleaseTagAndContainerName.yml - - pwsh: | - Get-ChildItem Env: + Write-Verbose -Verbose "Version: $(Version)" + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: 'Capture Environment Variables' - pwsh: | @@ -34,7 +33,7 @@ jobs: $null = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/release" Copy-Item "$(Pipeline.Workspace)/NuGetPackages/*.nupkg" -Destination "$(Pipeline.Workspace)/release" -Exclude "PowerShell.*.nupkg" -Force -Verbose - $releaseVersion = '$(VERSION)' + $releaseVersion = '$(Version)' $globalToolPath = "$(Pipeline.Workspace)/NuGetPackages/PowerShell.$releaseVersion.nupkg" if ($releaseVersion -notlike '*-*') { diff --git a/.pipelines/templates/release-validate-packagenames.yml b/.pipelines/templates/release-validate-packagenames.yml index cadf0c1ba12..8b08f8d8436 100644 --- a/.pipelines/templates/release-validate-packagenames.yml +++ b/.pipelines/templates/release-validate-packagenames.yml @@ -23,7 +23,7 @@ jobs: displayName: Capture environment - pwsh: | - $name = "{0}_{1:x}" -f '$(releaseTag)', (Get-Date).Ticks + $name = "{0}_{1:x}" -f '$(OutputReleaseTag.releaseTag)', (Get-Date).Ticks Write-Host $name Write-Host "##vso[build.updatebuildnumber]$name" displayName: Set Release Name diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index 50a4a676fee..35a11ec383c 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -235,23 +235,21 @@ jobs: Get-ChildItem '$(Build.ArtifactStagingDirectory)/downloads' | Select-Object -ExpandProperty FullName displayName: 'Capture downloads' - # - pwsh: | - # Write-Verbose -Verbose "Copying Github Release files in $(Build.ArtifactStagingDirectory)/downloads to use in Release Pipeline" - # - # Write-Verbose -Verbose "Creating output directory for GitHub Release files: $(ob_outputDirectory)/GitHubPackages" - # New-Item -Path $(ob_outputDirectory)/GitHubPackages -ItemType Directory -Force - # Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)/downloads/*" -Recurse | - # Where-Object { $_.Extension -notin '.msix', '.nupkg' } | - # ForEach-Object { Write-Verbose -Verbose $_.FullName ; $_ } | - # Copy-Item -Destination $(ob_outputDirectory)/GitHubPackages -Recurse - # - # Write-Verbose -Verbose "Creating output directory for NuGet packages: $(ob_outputDirectory)/NuGetPackages" - # New-Item -Path $(ob_outputDirectory)/NuGetPackages -ItemType Directory -Force - # Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)/downloads/*" -Recurse | - # Where-Object { $_.Extension -eq '.nupkg' } | - # ForEach-Object { Write-Verbose -Verbose $_.FullName ; $_ } | - # Copy-Item -Destination $(ob_outputDirectory)/NuGetPackages -Recurse - # displayName: Copy downloads to Artifacts + - pwsh: | + Write-Verbose -Verbose "Copying Github Release files in $(Build.ArtifactStagingDirectory)/downloads to use in Release Pipeline" + + Write-Verbose -Verbose "Creating output directory for GitHub Release files: $(ob_outputDirectory)/GitHubPackages" + New-Item -Path $(ob_outputDirectory)/GitHubPackages -ItemType Directory -Force + Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)/downloads/*" -Recurse | + Where-Object { $_.Extension -notin '.msix', '.nupkg' } | + Copy-Item -Destination $(ob_outputDirectory)/GitHubPackages -Recurse -Verbose + + Write-Verbose -Verbose "Creating output directory for NuGet packages: $(ob_outputDirectory)/NuGetPackages" + New-Item -Path $(ob_outputDirectory)/NuGetPackages -ItemType Directory -Force + Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)/downloads/*" -Recurse | + Where-Object { $_.Extension -eq '.nupkg' } | + Copy-Item -Destination $(ob_outputDirectory)/NuGetPackages -Recurse -Verbose + displayName: Copy downloads to Artifacts - pwsh: | # Create output directory for packages which have been uploaded to blob storage diff --git a/.pipelines/templates/variable/release-shared.yml b/.pipelines/templates/variable/release-shared.yml index 92ab56199d4..f944639a908 100644 --- a/.pipelines/templates/variable/release-shared.yml +++ b/.pipelines/templates/variable/release-shared.yml @@ -5,6 +5,12 @@ parameters: - name: SBOM type: boolean default: false + - name: RELEASETAG + type: string + default: 'Not Initialized' + - name: VERSION + type: string + default: 'Not Initialized' variables: - name: ob_signing_setup_enabled @@ -30,3 +36,7 @@ variables: value: ${{ parameters.REPOROOT }}\.config\suppress.json - name: ob_sdl_codeql_compiled_enabled value: false + - name: ReleaseTag + value: ${{ parameters.RELEASETAG }} + - name: Version + value: ${{ parameters.VERSION }} From f4c17e489265c0c0df4afc5993199fe1b622a828 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 15 Jan 2025 11:10:15 -0800 Subject: [PATCH 058/275] Make the `AssemblyVersion` not change for servicing releases (#24667) (#24783) Co-authored-by: Dongbo Wang --- .pipelines/templates/nupkg.yml | 4 ++-- PowerShell.Common.props | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index f9238bb09e8..be4b704557e 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -120,7 +120,7 @@ jobs: $refAssemblyFolder = Join-Path '$(System.ArtifactsDirectory)' 'RefAssembly' $null = New-Item -Path $refAssemblyFolder -Force -Verbose -Type Directory - Start-PSBuild -Clean -Runtime linux-x64 -Configuration Release + Start-PSBuild -Clean -Runtime linux-x64 -Configuration Release -ReleaseTag $(ReleaseTagVar) $sharedModules | Foreach-Object { $refFile = Get-ChildItem -Path "$(PowerShellRoot)\src\$_\obj\Release\net9.0\refint\$_.dll" @@ -136,7 +136,7 @@ jobs: } } - Start-PSBuild -Clean -Runtime win7-x64 -Configuration Release + Start-PSBuild -Clean -Runtime win7-x64 -Configuration Release -ReleaseTag $(ReleaseTagVar) $winOnlyModules | Foreach-Object { $refFile = Get-ChildItem -Path "$(PowerShellRoot)\src\$_\obj\Release\net9.0\refint\*.dll" diff --git a/PowerShell.Common.props b/PowerShell.Common.props index b73b3e60a7b..28bc08cc5db 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -58,6 +58,11 @@ $(ReleaseTagVersionPart).$(ReleaseTagSemVersionPart) $(ReleaseTagVersionPart).$(GAIncrementValue) + + $(PSCoreFileVersion) + $([System.Version]::Parse($(PSCoreFileVersion)).Major).$([System.Version]::Parse($(PSCoreFileVersion)).Minor).0.$([System.Version]::Parse($(PSCoreFileVersion)).Revision) @@ -84,7 +89,7 @@ --> $(PSCoreFileVersion) From 7fd9e974d56bf39761ad55500b056f514ad16256 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 15 Jan 2025 13:09:39 -0800 Subject: [PATCH 059/275] Update `Microsoft.PowerShell.PSResourceGet` to `1.1.0` (#24767) (#24785) Co-authored-by: Anam Navied --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index 9df1121f38b..5f9f89a4563 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + From 39b96b5d9afab13cbdea0ef859efac0f4a2e11de Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 15 Jan 2025 13:47:32 -0800 Subject: [PATCH 060/275] [release/v7.5] Update branch for release - Transitive - true - minor (#24786) * Update .NET SDK to latest version * Update package references * Update cgmanifest --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 4 +- ...soft.PowerShell.Commands.Management.csproj | 4 +- ...crosoft.PowerShell.Commands.Utility.csproj | 6 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 80 ++++++++------ .../Microsoft.WSMan.Management.csproj | 4 +- .../System.Management.Automation.csproj | 24 ++--- .../BenchmarkDotNet.Extensions.csproj | 2 +- .../ResultsComparer/ResultsComparer.csproj | 2 +- ...soft.PowerShell.NamedPipeConnection.csproj | 24 ++--- test/tools/TestService/TestService.csproj | 78 ++++++++------ test/tools/WebListener/WebListener.csproj | 6 +- test/xUnit/xUnit.tests.csproj | 8 +- tools/cgmanifest.json | 102 +++++++++--------- 16 files changed, 191 insertions(+), 159 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 472b5958a8c..644b79dcd7a 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "9.0.100", + "sdkImageVersion": "9.0.102", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 65324522984..ee2876ea570 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.100" + "version": "9.0.102" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index e575d8ef567..d17d99b190d 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,9 +7,9 @@ - + - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 748df04b328..a4cb9ad9dfb 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index e60c27d28a6..bc15337da1f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -13,7 +13,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + @@ -41,8 +41,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 5c28e4fe256..bd8754bff4d 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index bc5206ea9fa..75492f49c6c 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -17,39 +17,55 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 5a379621c85..c9d448a5091 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,11 +7,11 @@ - + - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 12177ffd61c..d0e81fddb6d 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,25 +32,25 @@ - - - - - - + + + + + + - + - - - - + + + + - + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 4c1975ac342..427245af6d8 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -13,7 +13,7 @@ - + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 61a9818dc23..f4874cfa6d7 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -13,7 +13,7 @@ - + diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index 0acf5c81d43..8bf1139db7d 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -20,18 +20,18 @@ - - - - - - - + + + + + + + - - - - - + + + + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index e96e4defa48..68452edfdb5 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,40 +15,56 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index fc11e328e7e..7117e235557 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,9 +7,9 @@ - - + + - + diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 2b04741dba8..114c1f8114d 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -26,13 +26,13 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index 4abc0cd4000..bb4fd3edb1c 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -115,7 +115,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "8.0.11" + "Version": "8.0.12" } }, "DevelopmentDependency": false @@ -185,7 +185,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -205,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -215,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -235,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -245,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -255,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -265,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -275,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -285,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -295,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -305,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -315,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -325,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -335,7 +335,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -345,7 +345,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -355,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -365,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -385,7 +385,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -395,7 +395,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -405,7 +405,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -465,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -485,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -495,7 +495,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -505,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -515,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -525,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -545,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.DiagnosticSource", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -555,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -565,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -575,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -585,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -595,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -605,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -615,7 +615,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -625,7 +625,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -635,7 +635,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -645,7 +645,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -675,7 +675,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -705,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -725,7 +725,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -735,7 +735,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -745,7 +745,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -755,7 +755,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -825,7 +825,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -835,7 +835,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -845,7 +845,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -855,7 +855,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encoding.CodePages", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -865,7 +865,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encodings.Web", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -875,7 +875,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false @@ -895,7 +895,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.0" + "Version": "9.0.1" } }, "DevelopmentDependency": false From a0d00d805631ce92cf2234990d088da584d908c3 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 15 Jan 2025 14:43:54 -0800 Subject: [PATCH 061/275] Mark build as latest stable (#24789) --- tools/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/metadata.json b/tools/metadata.json index c4cb3dd7bd3..1da6d7f42e7 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -6,5 +6,5 @@ "LTSReleaseTag" : ["v7.2.22", "v7.4.4"], "NextReleaseTag": "v7.5.0-preview.4", "LTSRelease": { "Latest": false, "Package": false }, - "StableRelease": { "Latest": false, "Package": false } + "StableRelease": { "Latest": true, "Package": true } } From dd66a64db7d3e2adadaca603c385803d158b549b Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 15 Jan 2025 14:52:20 -0800 Subject: [PATCH 062/275] Fix Changelog content grab during GitHub Release (#24788) (#24791) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung --- .pipelines/templates/release-githubtasks.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.pipelines/templates/release-githubtasks.yml b/.pipelines/templates/release-githubtasks.yml index ed3ae028934..4af3c973205 100644 --- a/.pipelines/templates/release-githubtasks.yml +++ b/.pipelines/templates/release-githubtasks.yml @@ -74,14 +74,12 @@ jobs: $changelog = Get-Content -Path $filePath - $startPattern = "^## \[" + ([regex]::Escape($releaseVersion)) + "\]" - $endPattern = "^## \[{0}\.{1}\.{2}*" -f $semanticVersion.Major, $semanticVersion.Minor, $semanticVersion.Patch + $headingPattern = "^## \[\d+\.\d+\.\d+" + $headingStartLines = $changelog | Select-String -Pattern $headingPattern | Select-Object -ExpandProperty LineNumber + $startLine = $headingStartLines[0] + $endLine = $headingStartLines[1] - 1 - $clContent = $changelog | ForEach-Object { - if ($_ -match $startPattern) { $outputLine = $true } - elseif ($_ -match $endPattern) { $outputLine = $false } - if ($outputLine) { $_} - } | Out-String + $clContent = $changelog | Select-Object -Skip ($startLine-1) -First ($endLine - $startLine) | Out-String Write-Verbose -Verbose "Selected content: `n$clContent" From 4fc335669732c348fb3ef1167ed72c0145fffd7b Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 15 Jan 2025 14:53:53 -0800 Subject: [PATCH 063/275] Add tool package download in publish nuget stage (#24790) (#24792) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung --- .pipelines/templates/release-publish-nuget.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pipelines/templates/release-publish-nuget.yml b/.pipelines/templates/release-publish-nuget.yml index 78338d7d87c..98249844d4c 100644 --- a/.pipelines/templates/release-publish-nuget.yml +++ b/.pipelines/templates/release-publish-nuget.yml @@ -12,6 +12,8 @@ jobs: os: windows templateContext: inputs: + - input: pipelineArtifact + artifactName: drop_setReleaseTagAndUploadTools_SetTagAndTools - input: pipelineArtifact pipeline: PSPackagesOfficial artifactName: drop_upload_upload_packages From 7c35f34553d27730710092eb3682fd2c9bc50a56 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 16 Jan 2025 11:55:27 -0800 Subject: [PATCH 064/275] Update the TPN (#24797) --- ThirdPartyNotices.txt | 159 ++++++++++++++++++++++++++++-------------- 1 file changed, 108 insertions(+), 51 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index a11a42b0aab..4abb1717d67 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -284,7 +284,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 8.0.11 - MIT +Microsoft.Extensions.ObjectPool 8.0.12 - MIT Copyright Jorn Zaefferer @@ -446,7 +446,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Win32.Registry.AccessControl 9.0.0 - MIT +Microsoft.Win32.Registry.AccessControl 9.0.1 - MIT Copyright (c) 2021 @@ -536,7 +536,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Win32.SystemEvents 9.0.0 - MIT +Microsoft.Win32.SystemEvents 9.0.1 - MIT Copyright (c) 2021 @@ -626,7 +626,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Windows.Compatibility 9.0.0 - MIT +Microsoft.Windows.Compatibility 9.0.1 - MIT (c) Microsoft Corporation @@ -679,7 +679,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.android-arm.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.android-arm.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -769,7 +769,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-arm64.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.android-arm64.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -859,7 +859,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x64.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.android-x64.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -949,7 +949,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x86.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.android-x86.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -1039,7 +1039,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.linux-arm.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -1129,7 +1129,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -1219,7 +1219,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -1309,7 +1309,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -1399,7 +1399,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -1489,7 +1489,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -1579,7 +1579,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -1669,7 +1669,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-x64.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.linux-x64.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -1759,7 +1759,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -1849,7 +1849,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -1992,7 +1992,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -2082,7 +2082,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -2172,7 +2172,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-x64.runtime.native.System.IO.Ports 9.0.0 - MIT +runtime.osx-x64.runtime.native.System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -2262,7 +2262,7 @@ SOFTWARE. --------------------------------------------------------- -System.CodeDom 9.0.0 - MIT +System.CodeDom 9.0.1 - MIT Copyright (c) 2021 @@ -2438,7 +2438,7 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition 9.0.0 - MIT +System.ComponentModel.Composition 9.0.1 - MIT Copyright (c) 2021 @@ -2528,7 +2528,7 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition.Registration 9.0.0 - MIT +System.ComponentModel.Composition.Registration 9.0.1 - MIT Copyright (c) 2021 @@ -2618,7 +2618,7 @@ SOFTWARE. --------------------------------------------------------- -System.Configuration.ConfigurationManager 9.0.0 - MIT +System.Configuration.ConfigurationManager 9.0.1 - MIT Copyright (c) 2021 @@ -2708,7 +2708,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.Odbc 9.0.0 - MIT +System.Data.Odbc 9.0.1 - MIT Copyright (c) 2021 @@ -2798,7 +2798,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.OleDb 9.0.0 - MIT +System.Data.OleDb 9.0.1 - MIT Copyright (c) 2021 @@ -2941,9 +2941,66 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.DiagnosticSource 9.0.0 - MIT +System.Diagnostics.DiagnosticSource 9.0.1 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors +(c) Microsoft Corporation +Copyright (c) 2022 FormatJS +Copyright (c) Andrew Arnott +Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft +Copyright 2018 Daniel Lemire +Copyright (c) .NET Foundation +Copyright (c) 2011, Google Inc. +Copyright (c) 2020 Dan Shechter +(c) 1997-2005 Sean Eron Anderson +Copyright (c) 2015 Andrew Gallant +Copyright (c) 2022, Wojciech Mula +Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) 2022, Geoff Langdale +Copyright (c) 2005-2020 Rich Felker +Copyright (c) 2012-2021 Yann Collet +Copyright (c) Microsoft Corporation +Copyright (c) 2007 James Newton-King +Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic +Copyright 2012 the V8 project authors +Copyright (c) 1999 Lucent Technologies +Copyright (c) 2008-2016, Wojciech Mula +Copyright (c) 2011-2020 Microsoft Corp +Copyright (c) 2015-2017, Wojciech Mula +Copyright (c) 2015-2018, Wojciech Mula +Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2015 The Chromium Authors +Copyright (c) 2018 Alexander Chermyanin +Copyright (c) The Internet Society 1997 +Copyright (c) 2004-2006 Intel Corporation +Copyright (c) 2011-2015 Intel Corporation +Copyright (c) 2013-2017, Milosz Krajewski +Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) The Internet Society (2003) +Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler +Copyright (c) 2020 Mara Bos +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2012 - present, Victor Zverovich +Copyright (c) 2006 Jb Evain (jbevain@gmail.com) +Copyright (c) 2008-2020 Advanced Micro Devices, Inc. +Copyright (c) 2019 Microsoft Corporation, Daan Leijen +Copyright (c) 2011 Novell, Inc (http://www.novell.com) +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors +Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com +Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip +Copyright (c) 1980, 1986, 1993 The Regents of the University of California +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass The MIT License (MIT) @@ -2974,7 +3031,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.EventLog 9.0.0 - MIT +System.Diagnostics.EventLog 9.0.1 - MIT Copyright (c) 2021 @@ -3064,7 +3121,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.PerformanceCounter 9.0.0 - MIT +System.Diagnostics.PerformanceCounter 9.0.1 - MIT Copyright (c) 2021 @@ -3154,7 +3211,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices 9.0.0 - MIT +System.DirectoryServices 9.0.1 - MIT Copyright (c) 2021 @@ -3244,7 +3301,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.AccountManagement 9.0.0 - MIT +System.DirectoryServices.AccountManagement 9.0.1 - MIT Copyright (c) 2021 @@ -3334,7 +3391,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.Protocols 9.0.0 - MIT +System.DirectoryServices.Protocols 9.0.1 - MIT Copyright (c) 2021 @@ -3424,7 +3481,7 @@ SOFTWARE. --------------------------------------------------------- -System.Drawing.Common 9.0.0 - MIT +System.Drawing.Common 9.0.1 - MIT (c) Microsoft Corporation @@ -3459,7 +3516,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Packaging 9.0.0 - MIT +System.IO.Packaging 9.0.1 - MIT Copyright (c) 2021 @@ -3549,7 +3606,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Ports 9.0.0 - MIT +System.IO.Ports 9.0.1 - MIT Copyright (c) 2021 @@ -3639,7 +3696,7 @@ SOFTWARE. --------------------------------------------------------- -System.Management 9.0.0 - MIT +System.Management 9.0.1 - MIT Copyright (c) 2021 @@ -3729,7 +3786,7 @@ SOFTWARE. --------------------------------------------------------- -System.Net.Http.WinHttpHandler 9.0.0 - MIT +System.Net.Http.WinHttpHandler 9.0.1 - MIT Copyright (c) 2021 @@ -3904,7 +3961,7 @@ SOFTWARE. --------------------------------------------------------- -System.Reflection.Context 9.0.0 - MIT +System.Reflection.Context 9.0.1 - MIT Copyright (c) 2021 @@ -4134,7 +4191,7 @@ SOFTWARE. --------------------------------------------------------- -System.Runtime.Caching 9.0.0 - MIT +System.Runtime.Caching 9.0.1 - MIT Copyright (c) 2021 @@ -4299,7 +4356,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Pkcs 9.0.0 - MIT +System.Security.Cryptography.Pkcs 9.0.1 - MIT Copyright (c) 2021 @@ -4389,7 +4446,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.ProtectedData 9.0.0 - MIT +System.Security.Cryptography.ProtectedData 9.0.1 - MIT Copyright (c) 2021 @@ -4479,7 +4536,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Xml 9.0.0 - MIT +System.Security.Cryptography.Xml 9.0.1 - MIT Copyright (c) 2021 @@ -4569,7 +4626,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Permissions 9.0.0 - MIT +System.Security.Permissions 9.0.1 - MIT Copyright (c) 2021 @@ -4908,7 +4965,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Syndication 9.0.0 - MIT +System.ServiceModel.Syndication 9.0.1 - MIT Copyright (c) 2021 @@ -4998,7 +5055,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceProcess.ServiceController 9.0.0 - MIT +System.ServiceProcess.ServiceController 9.0.1 - MIT Copyright (c) 2021 @@ -5088,7 +5145,7 @@ SOFTWARE. --------------------------------------------------------- -System.Speech 9.0.0 - MIT +System.Speech 9.0.1 - MIT Copyright (c) 2021 @@ -5178,7 +5235,7 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encoding.CodePages 9.0.0 - MIT +System.Text.Encoding.CodePages 9.0.1 - MIT Copyright (c) 2021 @@ -5268,7 +5325,7 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encodings.Web 9.0.0 - MIT +System.Text.Encodings.Web 9.0.1 - MIT Copyright (c) 2021 @@ -5358,7 +5415,7 @@ SOFTWARE. --------------------------------------------------------- -System.Threading.AccessControl 9.0.0 - MIT +System.Threading.AccessControl 9.0.1 - MIT Copyright (c) 2021 @@ -5484,7 +5541,7 @@ SOFTWARE. --------------------------------------------------------- -System.Windows.Extensions 9.0.0 - MIT +System.Windows.Extensions 9.0.1 - MIT Copyright (c) 2021 From 99dab561892364d82d4965068f7f8b175e768b1b Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 16 Jan 2025 12:08:46 -0800 Subject: [PATCH 065/275] Add a parameter that skips verify packages step (#24763) (#24784) * added a parameter that skips verify packages step * fix parameter string to boolean value --------- Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung --- .pipelines/apiscan-gen-notice.yml | 4 ++++ .pipelines/templates/compliance/generateNotice.yml | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.pipelines/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml index f469a49eef5..f4fd167d7a0 100644 --- a/.pipelines/apiscan-gen-notice.yml +++ b/.pipelines/apiscan-gen-notice.yml @@ -8,6 +8,9 @@ parameters: displayName: Debugging - Enable CodeQL and set cadence to 1 hour type: boolean default: false + - name: SkipVerifyPackages + type: boolean + default: false variables: - name: ob_outputDirectory @@ -103,3 +106,4 @@ extends: - template: /.pipelines/templates/compliance/generateNotice.yml@self parameters: parentJobs: [] + SkipVerifyPackages: ${{ parameters.SkipVerifyPackages }} diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml index 0c1282ea8ce..9a00ed6f01d 100644 --- a/.pipelines/templates/compliance/generateNotice.yml +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -4,6 +4,8 @@ parameters: - name: parentJobs type: jobList + - name: SkipVerifyPackages + type: boolean jobs: - job: generateNotice @@ -60,7 +62,7 @@ jobs: - pwsh: | $(repoRoot)/tools/clearlyDefined/ClearlyDefined.ps1 -TestAndHarvest displayName: Verify that packages have license data - + condition: eq(${{ parameters.SkipVerifyPackages }}, false) - task: msospo.ospo-extension.8d7f9abb-6896-461d-9e25-4f74ed65ddb2.notice@0 displayName: 'NOTICE File Generator' @@ -71,7 +73,6 @@ jobs: # this isn't working # additionaldata: $(Build.SourcesDirectory)\assets\additionalAttributions.txt - - pwsh: | Get-Content -Raw -Path $(repoRoot)\assets\additionalAttributions.txt | Out-File '$(ob_outputDirectory)\ThirdPartyNotices.txt' -Encoding utf8NoBOM -Force -Append Get-Content -Raw -Path $(repoRoot)\assets\additionalAttributions.txt From 3031ef7e6f020947a0c9d808783ca7a16ab67df7 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 17 Jan 2025 12:52:12 -0800 Subject: [PATCH 066/275] Create changelog for v7.5.0 (#24808) (#24811) * Add changelog for 7.5.0 * move 7.5 history to the 7.5 changelog * Update CHANGELOG/7.5.md * Update CHANGELOG/7.5.md * Update changelog for 7.5.0-rc.1 release * Update CHANGELOG/7.5.md --------- Co-authored-by: Justin Chung --- CHANGELOG/7.5.md | 622 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 622 insertions(+) create mode 100644 CHANGELOG/7.5.md diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md new file mode 100644 index 00000000000..702c60346e7 --- /dev/null +++ b/CHANGELOG/7.5.md @@ -0,0 +1,622 @@ +# 7.5 Changelog + +## [7.5.0] + +### Build and Packaging Improvements + +
+ + + +

Update .NET SDK to 9.0.102

+ +
+ +
    +
  • Add tool package download in publish nuget stage (#24790) (#24792)
  • +
  • Fix Changelog content grab during GitHub Release (#24788) (#24791)
  • +
  • Mark build as latest stable (#24789)
  • +
  • [release/v7.5] Update branch for release - Transitive - true - minor (#24786)
  • +
  • Update Microsoft.PowerShell.PSResourceGet to 1.1.0 (#24767) (#24785)
  • +
  • Make the AssemblyVersion not change for servicing releases (#24667) (#24783)
  • +
  • Deploy Box Update (#24632) (#24779)
  • +
  • Update machine pool for copy blob and upload buildinfo stage (#24587) (#24776)
  • +
  • Update nuget publish to use Deploy Box (#24596) (#24597)
  • +
  • Added Deploy Box Product Pathway to GitHub Release and NuGet Release Pipelines (#24583) (#24595)
  • +
+ +
+ +### Documentation and Help Content + +- Update `HelpInfoUri` for 7.5 (#24610) (#24777) + +[7.5.0]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-rc.1...v7.5.0 + +## [7.5.0-rc.1] - 2024-11-14 + +**NOTE:** Due to technical issues, release of packages to packages.microsoft.com ~and release to NuGet.org~ is delayed. + +### Build and Packaging Improvements + +
+ + + +

Bump to .NET 9.0.100

+ +
+ +
    +
  • Update ThirdPartyNotices file (#24582) (#24536)
  • +
  • Bump to .NET 9.0.100 (#24576) (#24535)
  • +
  • Add a way to use only NuGet feed sources (#24528) (#24530)
  • +
  • Update PSResourceGet to v1.1.0-RC2 (#24512) (#24525)
  • +
  • Add PMC mapping for debian 12 (bookworm) (#24413) (#24518)
  • +
  • Bump .NET to 9.0.100-rc.2.24474.11 (#24509) (#24522)
  • +
  • Keep the roff file when gzipping it. (#24450) (#24520)
  • +
  • Checkin generated manpage (#24423) (#24519)
  • +
  • Update PSReadLine to 2.3.6 (#24380) (#24517)
  • +
  • Download package from package build for generating vpack (#24481) (#24521)
  • +
  • Delete the msix blob if it's already there (#24353) (#24516)
  • +
  • Add CodeQL scanning to APIScan build (#24303) (#24515)
  • +
  • Update vpack pipeline (#24281) (#24514)
  • +
  • Fix seed max value for Container Linux CI (#24510) (#24511)
  • +
  • Bring preview.5 release fixes to release/v7.5 (#24379) (#24368)
  • +
  • Add BaseUrl to buildinfo json file (#24376) (#24377)
  • +
+ +
+ +[7.5.0-rc.1]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-preview.5...v7.5.0-rc.1 + +## [7.5.0-preview.5] - 2024-10-01 + +### Breaking Changes + +- Treat large `Enum` values as numbers in `ConvertTo-Json` (#20999) (#24304) + +### Engine Updates and Fixes + +- Fix how processor architecture is validated in `Import-Module` (#24265) (#24317) + +### Experimental Features + +### General Cmdlet Updates and Fixes + +- Add `-Force` parameter to `Resolve-Path` and `Convert-Path` cmdlets to support wildcard hidden files (#20981) (#24344) +- Add telemetry to track the use of features (#24247) (#24331) +- Treat large `Enum` values as numbers in `ConvertTo-Json` (#20999) (#24304) +- Make features `PSCommandNotFoundSuggestion`, `PSCommandWithArgs`, and `PSModuleAutoLoadSkipOfflineFiles` stable (#24246) (#24310) +- Handle global tool when prepending `$PSHome` to `PATH` (#24228) (#24307) + +### Tests + +- Fix cleanup in `PSResourceGet` test (#24339) (#24345) + +### Build and Packaging Improvements + +
+ + + +

Bump .NET SDK to 9.0.100-rc.1.24452.12

+ +
+ +
    +
  • Fixed Test Scenario for Compress-PSResource (Internal 32696)
  • +
  • Add back local NuGet source for test packages (Internal 32693)
  • +
  • Fix typo in release-MakeBlobPublic.yml (Internal 32689)
  • +
  • Copy to static site instead of making blob public (#24269) (#24343)
  • +
  • Update Microsoft.PowerShell.PSResourceGet to 1.1.0-preview2 (#24300) (#24337)
  • +
  • Remove the MD5 branch in the strong name signing token calculation (#24288) (#24321)
  • +
  • Update experimental-feature json files (#24271) (#24319)
  • +
  • Add updated libicu dependency for Debian packages (#24301) (#24324)
  • +
  • Add mapping to AzureLinux repo (#24290) (#24322)
  • +
  • Update and add new NuGet package sources for different environments. (#24264) (#24316)
  • +
  • Bump .NET 9 to 9.0.100-rc.1.24452.12 (#24273) (#24320)
  • +
  • Make some release tests run in a hosted pools (#24270) (#24318)
  • +
  • Do not build the exe for Global tool shim project (#24263) (#24315)
  • +
  • Delete assets/AppImageThirdPartyNotices.txt (#24256) (#24313)
  • +
  • Create new pipeline for compliance (#24252) (#24312)
  • +
  • Add specific path for issues in tsaconfig (#24244) (#24309)
  • +
  • Use Managed Identity for APIScan authentication (#24243) (#24308)
  • +
  • Add Windows signing for pwsh.exe (#24219) (#24306)
  • +
  • Check Create and Submit in vPack build by default (#24181) (#24305)
  • +
+ +
+ +### Documentation and Help Content + +- Delete demos directory (#24258) (#24314) + +[7.5.0-preview.5]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-preview.4...v7.5.0-preview.5 + +## [7.5.0-preview.4] - 2024-08-28 + +### Engine Updates and Fixes + +- RecommendedAction: Explicitly start and stop ANSI Error Color (#24065) (Thanks @JustinGrote!) +- Improve .NET overload definition of generic methods (#21326) (Thanks @jborean93!) +- Optimize the `+=` operation for a collection when it's an object array (#23901) (Thanks @jborean93!) +- Allow redirecting to a variable as experimental feature `PSRedirectToVariable` (#20381) + +### General Cmdlet Updates and Fixes + +- Change type of `LineNumber` to `ulong` in `Select-String` (#24075) (Thanks @Snowman-25!) +- Fix `Invoke-RestMethod` to allow `-PassThru` and `-Outfile` work together (#24086) (Thanks @jshigetomi!) +- Fix Hyper-V Remoting when the module is imported via implicit remoting (#24032) (Thanks @jborean93!) +- Add `ConvertTo-CliXml` and `ConvertFrom-CliXml` cmdlets (#21063) (Thanks @ArmaanMcleod!) +- Add `OutFile` property in `WebResponseObject` (#24047) (Thanks @jshigetomi!) +- Show filename in `Invoke-WebRequest -OutFile -Verbose` (#24041) (Thanks @jshigetomi!) +- `Set-Acl`: Do not fail on untranslatable SID (#21096) (Thanks @jborean93!) +- Fix the extent of the parser error when a number constant is invalid (#24024) +- Fix `Move-Item` to throw error when moving into itself (#24004) +- Fix up .NET method invocation with `Optional` argument (#21387) (Thanks @jborean93!) +- Fix progress calculation on `Remove-Item` (#23869) (Thanks @jborean93!) +- Fix WebCmdlets when `-Body` is specified but `ContentType` is not (#23952) (Thanks @CarloToso!) +- Enable `-NoRestart` to work with `Register-PSSessionConfiguration` (#23891) +- Add `IgnoreComments` and `AllowTrailingCommas` options to `Test-Json` cmdlet (#23817) (Thanks @ArmaanMcleod!) +- Get-Help may report parameters with `ValueFromRemainingArguments` attribute as pipeline-able (#23871) + +### Code Cleanup + +
+ + + +

We thank the following contributors!

+

@xtqqczze, @eltociear

+ +
+ +
    +
  • Minor cleanup on local variable names within a method (#24105)
  • +
  • Remove explicit IDE1005 suppressions (#21217) (Thanks @xtqqczze!)
  • +
  • Fix a typo in WebRequestSession.cs (#23963) (Thanks @eltociear!)
  • +
+ +
+ +### Tools + +- devcontainers: mount workspace in /PowerShell (#23857) (Thanks @rzippo!) + +### Tests + +- Add debugging to the MTU size test (#21463) + +### Build and Packaging Improvements + +
+ + + +

We thank the following contributors!

+

@bosesubham2011

+ +
+ +
    +
  • Update third party notices (Internal 32128)
  • +
  • Update cgmanifest (#24163)
  • +
  • Fixes to Azure Public feed usage (#24149)
  • +
  • Add support for back porting PRs from GitHub or the Private Azure Repos (#20670)
  • +
  • Move to 9.0.0-preview.6.24327.7 (#24133)
  • +
  • update path (#24134)
  • +
  • Update to the latest NOTICES file (#24131)
  • +
  • Fix semver issue with updating cgmanifest (#24132)
  • +
  • Add ability to capture MSBuild Binary logs when restore fails (#24128)
  • +
  • add ability to skip windows stage (#24116)
  • +
  • chore: Refactor Nuget package source creation to use New-NugetPackageSource function (#24104)
  • +
  • Make Microsoft feeds the default (#24098)
  • +
  • Cleanup unused csproj (#23951)
  • +
  • Add script to update SDK version during release (#24034)
  • +
  • Enumerate over all signed zip packages (#24063)
  • +
  • Update metadata.json for PowerShell July releases (#24082)
  • +
  • Add macos signing for package files (#24015)
  • +
  • Update install-powershell.sh to support azure-linux (#23955) (Thanks @bosesubham2011!)
  • +
  • Skip build steps that do not have exe packages (#23945)
  • +
  • Update metadata.json for PowerShell June releases (#23973)
  • +
  • Create powershell.config.json for PowerShell.Windows.x64 global tool (#23941)
  • +
  • Fix error in the vPack release, debug script that blocked release (#23904)
  • +
  • Add vPack release (#23898)
  • +
  • Fix exe signing with third party signing for WiX engine (#23878)
  • +
  • Update wix installation in CI (#23870)
  • +
  • Add checkout to fix TSA config paths (#23865)
  • +
  • Merge the v7.5.0-preview.3 release branch to GitHub master branch
  • +
  • Update metadata.json for the v7.5.0-preview.3 release (#23862)
  • +
  • Bump PSResourceGet to 1.1.0-preview1 (#24129)
  • +
  • Bump github/codeql-action from 3.25.8 to 3.26.0 (#23953) (#23999) (#24053) (#24069) (#24095) (#24118)
  • +
  • Bump actions/upload-artifact from 4.3.3 to 4.3.6 (#24019) (#24113) (#24119)
  • +
  • Bump agrc/create-reminder-action from 1.1.13 to 1.1.15 (#24029) (#24043)
  • +
  • Bump agrc/reminder-action from 1.0.12 to 1.0.14 (#24028) (#24042)
  • +
  • Bump super-linter/super-linter from 5.7.2 to 6.8.0 (#23809) (#23856) (#23894) (#24030) (#24103)
  • +
  • Bump ossf/scorecard-action from 2.3.1 to 2.4.0 (#23802) (#24096)
  • +
  • Bump actions/dependency-review-action from 4.3.2 to 4.3.4 (#23897) (#24046)
  • +
  • Bump actions/checkout from 4.1.5 to 4.1.7 (#23813) (#23947)
  • +
  • Bump github/codeql-action from 3.25.4 to 3.25.8 (#23801) (#23893)
  • +
+ +
+ +### Documentation and Help Content + +- Update docs sample nuget.config (#24109) +- Update Code of Conduct and Security Policy (#23811) +- Update working-group-definitions.md for the Security WG (#23884) +- Fix up broken links in Markdown files (#23863) +- Update Engine Working Group Members (#23803) (Thanks @kilasuit!) +- Remove outdated and contradictory information from `README` (#23812) + +[7.5.0-preview.4]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-preview.3...v7.5.0-preview.4 + +## [7.5.0-preview.3] - 2024-05-16 + +### Breaking Changes + +- Remember installation options and used them to initialize options for the next installation (#20420) (Thanks @reduckted!) +- `ConvertTo-Json`: Serialize `BigInteger` as a number (#21000) (Thanks @jborean93!) + +### Engine Updates and Fixes + +- Fix generating `OutputType` when running in Constrained Language Mode (#21605) +- Revert the PR #17856 (Do not preserve temporary results when no need to do so) (#21368) +- Make sure the assembly/library resolvers are registered at early stage (#21361) +- Fix PowerShell class to support deriving from an abstract class with abstract properties (#21331) +- Fix error formatting for pipeline enumeration exceptions (#20211) + +### General Cmdlet Updates and Fixes + +- Added progress bar for `Remove-Item` cmdlet (#20778) (Thanks @ArmaanMcleod!) +- Expand `~` to `$home` on Windows with tab completion (#21529) +- Separate DSC configuration parser check for ARM processor (#21395) (Thanks @dkontyko!) +- Fix `[semver]` type to pass `semver.org` tests (#21401) +- Don't complete when declaring parameter name and class member (#21182) (Thanks @MartinGC94!) +- Add `RecommendedAction` to `ConciseView` of the error reporting (#20826) (Thanks @JustinGrote!) +- Fix the error when using `Start-Process -Credential` without the admin privilege (#21393) (Thanks @jborean93!) +- Fix `Test-Path -IsValid` to check for invalid path and filename characters (#21358) +- Fix build failure due to missing reference in `GlobalToolShim.cs` (#21388) +- Fix argument passing in `GlobalToolShim` (#21333) (Thanks @ForNeVeR!) +- Make sure both stdout and stderr can be redirected from a native executable (#20997) +- Handle the case that `Runspace.DefaultRunspace == null` when logging for WDAC Audit (#21344) +- Fix a typo in `releaseTools.psm1` (#21306) (Thanks @eltociear!) +- `Get-Process`: Remove admin requirement for `-IncludeUserName` (#21302) (Thanks @jborean93!) +- Fall back to type inference when hashtable key-value cannot be retrieved from safe expression (#21184) (Thanks @MartinGC94!) +- Fix the regression when doing type inference for `$_` (#21223) (Thanks @MartinGC94!) +- Revert "Adjust PUT method behavior to POST one for default content type in WebCmdlets" (#21049) +- Fix a regression in `Format-Table` when header label is empty (#21156) + +### Code Cleanup + +
+ + + +

We thank the following contributors!

+

@xtqqczze

+ +
+ +
    +
  • Enable CA1868: Unnecessary call to 'Contains' for sets (#21165) (Thanks @xtqqczze!)
  • +
  • Remove JetBrains.Annotations attributes (#21246) (Thanks @xtqqczze!)
  • +
+ +
+ +### Tests + +- Update `metadata.json` and `README.md` (#21454) +- Skip test on Windows Server 2012 R2 for `no-nl` (#21265) + +### Build and Packaging Improvements + +
+ + + +

Bump to .NET 9.0.0-preview.3

+

We thank the following contributors!

+

@alerickson, @tgauth, @step-security-bot, @xtqqczze

+ +
+ +
    +
  • Fix PMC publish and the file path for msixbundle
  • +
  • Fix release version and stage issues in build and packaging
  • +
  • Add release tag if the environment variable is set
  • +
  • Update installation on Wix module (#23808)
  • +
  • Updates to package and release pipelines (#23800)
  • +
  • Update PSResourceGet to 1.0.5 (#23796)
  • +
  • Bump actions/upload-artifact from 4.3.2 to 4.3.3 (#21520)
  • +
  • Bump actions/dependency-review-action from 4.2.5 to 4.3.2 (#21560)
  • +
  • Bump actions/checkout from 4.1.2 to 4.1.5 (#21613)
  • +
  • Bump github/codeql-action from 3.25.1 to 3.25.4 (#22071)
  • +
  • Use feed with Microsoft Wix toolset (#21651) (Thanks @tgauth!)
  • +
  • Bump to .NET 9 preview 3 (#21782)
  • +
  • Use PSScriptRoot to find path to Wix module (#21611)
  • +
  • Create the Windows.x64 global tool with shim for signing (#21559)
  • +
  • Update Wix package install (#21537) (Thanks @tgauth!)
  • +
  • Add branch counter variables for daily package builds (#21523)
  • +
  • Use correct signing certificates for RPM and DEBs (#21522)
  • +
  • Revert to version available on Nuget for Microsoft.CodeAnalysis.Analyzers (#21515)
  • +
  • Official PowerShell Package pipeline (#21504)
  • +
  • Add a PAT for fetching PMC cli (#21503)
  • +
  • Bump ossf/scorecard-action from 2.0.6 to 2.3.1 (#21485)
  • +
  • Apply security best practices (#21480) (Thanks @step-security-bot!)
  • +
  • Bump Microsoft.CodeAnalysis.Analyzers (#21449)
  • +
  • Fix package build to not check some files for a signature. (#21458)
  • +
  • Update PSResourceGet version from 1.0.2 to 1.0.4.1 (#21439) (Thanks @alerickson!)
  • +
  • Verify environment variable for OneBranch before we try to copy (#21441)
  • +
  • Add back two transitive dependency packages (#21415)
  • +
  • Multiple fixes in official build pipeline (#21408)
  • +
  • Update PSReadLine to v2.3.5 (#21414)
  • +
  • PowerShell co-ordinated build OneBranch pipeline (#21364)
  • +
  • Add file description to pwsh.exe (#21352)
  • +
  • Suppress MacOS package manager output (#21244) (Thanks @xtqqczze!)
  • +
  • Update metadata.json and README.md (#21264)
  • +
+ +
+ +### Documentation and Help Content + +- Update the doc about how to build PowerShell (#21334) (Thanks @ForNeVeR!) +- Update the member lists for the Engine and Interactive-UX working groups (#20991) (Thanks @kilasuit!) +- Update CHANGELOG for `v7.2.19`, `v7.3.12` and `v7.4.2` (#21462) +- Fix grammar in `FAQ.md` (#21468) (Thanks @CodingGod987!) +- Fix typo in `SessionStateCmdletAPIs.cs` (#21413) (Thanks @eltociear!) +- Fix typo in a test (#21337) (Thanks @testwill!) +- Fix typo in `ast.cs` (#21350) (Thanks @eltociear!) +- Adding Working Group membership template (#21153) + +[7.5.0-preview.3]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-preview.2...v7.5.0-preview.3 + +## [7.5.0-preview.2] - 2024-02-22 + +### Engine Updates and Fixes + +- Fix `using assembly` to use `Path.Combine` when constructing assembly paths (#21169) +- Validate the value for `using namespace` during semantic checks to prevent declaring invalid namespaces (#21162) + +### General Cmdlet Updates and Fixes + +- Add `WinGetCommandNotFound` and `CompletionPredictor` modules to track usage (#21040) +- `ConvertFrom-Json`: Add `-DateKind` parameter (#20925) (Thanks @jborean93!) +- Add tilde expansion for windows native executables (#20402) (Thanks @domsleee!) +- Add `DirectoryInfo` to the `OutputType` for `New-Item` (#21126) (Thanks @MartinGC94!) +- Fix `Get-Error` serialization of array values (#21085) (Thanks @jborean93!) + +### Code Cleanup + +
+ + + +

We thank the following contributors!

+

@eltociear

+ +
+ +
    +
  • Fix a typo in CoreAdapter.cs (#21179) (Thanks @eltociear!)
  • +
  • Remove PSScheduledJob module source code (#21189)
  • +
+ +
+ +### Tests + +- Rewrite the mac syslog tests to make them less flaky (#21174) + +### Build and Packaging Improvements + +
+ + +

Bump to .NET 9 Preview 1

+

We thank the following contributors!

+

@gregsdennis

+ +
+ +
    +
  • Bump to .NET 9 Preview 1 (#21229)
  • +
  • Add dotnet-runtime-9.0 as a dependency for the Mariner package
  • +
  • Add dotenv install as latest version does not work with current Ruby version (#21239)
  • +
  • Remove surrogateFile setting of APIScan (#21238)
  • +
  • Update experimental-feature json files (#21213)
  • +
  • Update to the latest NOTICES file (#21236)(#21177)
  • +
  • Update the cgmanifest (#21237)(#21093)
  • +
  • Update the cgmanifest (#21178)
  • +
  • Bump XunitXml.TestLogger from 3.1.17 to 3.1.20 (#21207)
  • +
  • Update versions of PSResourceGet (#21190)
  • +
  • Generate MSI for win-arm64 installer (#20516)
  • +
  • Bump JsonSchema.Net to v5.5.1 (#21120) (Thanks @gregsdennis!)
  • +
+ +
+ +### Documentation and Help Content + +- Update `README.md` and `metadata.json` for v7.5.0-preview.1 release (#21094) +- Fix incorrect examples in XML docs in `PowerShell.cs` (#21173) +- Update WG members (#21091) +- Update changelog for v7.4.1 (#21098) + +[7.5.0-preview.2]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-preview.1...v7.5.0-preview.2 + +## [7.5.0-preview.1] - 2024-01-18 + +### Breaking Changes + +- Fix `-OlderThan` and `-NewerThan` parameters for `Test-Path` when using `PathType` and date range (#20942) (Thanks @ArmaanMcleod!) +- Previously `-OlderThan` would be ignored if specified together +- Change `New-FileCatalog -CatalogVersion` default to 2 (#20428) (Thanks @ThomasNieto!) + +### General Cmdlet Updates and Fixes + +- Fix completion crash for the SCCM provider (#20815, #20919, #20915) (Thanks @MartinGC94!) +- Fix regression in `Get-Content` when `-Tail 0` and `-Wait` are used together (#20734) (Thanks @CarloToso!) +- Add `Aliases` to the properties shown up when formatting the help content of the parameter returned by `Get-Help` (#20994) +- Add implicit localization fallback to `Import-LocalizedData` (#19896) (Thanks @chrisdent-de!) +- Change `Test-FileCatalog` to use `File.OpenRead` to better handle the case where the file is being used (#20939) (Thanks @dxk3355!) +- Added `-Module` completion for `Save-Help` and `Update-Help` commands (#20678) (Thanks @ArmaanMcleod!) +- Add argument completer to `-Verb` for `Start-Process` (#20415) (Thanks @ArmaanMcleod!) +- Add argument completer to `-Scope` for `*-Variable`, `*-Alias` & `*-PSDrive` commands (#20451) (Thanks @ArmaanMcleod!) +- Add argument completer to `-Verb` for `Get-Verb` and `Get-Command` (#20286) (Thanks @ArmaanMcleod!) +- Fixing incorrect formatting string in `CommandSearcher` trace logging (#20928) (Thanks @powercode!) +- Ensure the filename is not null when logging WDAC ETW events (#20910) (Thanks @jborean93!) +- Fix four regressions introduced by the WDAC logging feature (#20913) +- Leave the input, output, and error handles unset when they are not redirected (#20853) +- Fix `Start-Process -PassThru` to make sure the `ExitCode` property is accessible for the returned `Process` object (#20749) (Thanks @CodeCyclone!) +- Fix `Group-Object` output using interpolated strings (#20745) (Thanks @mawosoft!) +- Fix rendering of `DisplayRoot` for network `PSDrive` (#20793) +- Fix `Invoke-WebRequest` to report correct size when `-Resume` is specified (#20207) (Thanks @LNKLEO!) +- Add `PSAdapter` and `ConsoleGuiTools` to module load telemetry allow list (#20641) +- Fix Web Cmdlets to allow `WinForm` apps to work correctly (#20606) +- Block getting help from network locations in restricted remoting sessions (#20593) +- Fix `Group-Object` to use current culture for its output (#20608) +- Add argument completer to `-Version` for `Set-StrictMode` (#20554) (Thanks @ArmaanMcleod!) +- Fix `Copy-Item` progress to only show completed when all files are copied (#20517) +- Fix UNC path completion regression (#20419) (Thanks @MartinGC94!) +- Add telemetry to check for specific tags when importing a module (#20371) +- Report error if invalid `-ExecutionPolicy` is passed to `pwsh` (#20460) +- Add `HelpUri` to `Remove-Service` (#20476) +- Fix `unixmode` to handle `setuid` and `sticky` when file is not an executable (#20366) +- Fix `Test-Connection` due to .NET 8 changes (#20369) +- Fix implicit remoting proxy cmdlets to act on common parameters (#20367) +- Set experimental features to stable for 7.4 release (#20285) +- Revert changes to continue using `BinaryFormatter` for `Out-GridView` (#20300) +- Fix `Get-Service` non-terminating error message to include category (#20276) +- Prevent `Export-CSV` from flushing with every input (#20282) (Thanks @Chris--A!) +- Fix a regression in DSC (#20268) +- Include the module version in error messages when module is not found (#20144) (Thanks @ArmaanMcleod!) +- Add `-Empty` and `-InputObject` parameters to `New-Guid` (#20014) (Thanks @CarloToso!) +- Remove the comment trigger from feedback provider (#20136) +- Prevent fallback to file completion when tab completing type names (#20084) (Thanks @MartinGC94!) +- Add the alias `r` to the parameter `-Recurse` for the `Get-ChildItem` command (#20100) (Thanks @kilasuit!) + +### Code Cleanup + +
+ + + +

We thank the following contributors!

+

@eltociear, @ImportTaste, @ThomasNieto, @0o001

+ +
+ +
    +
  • Fix typos in the code base (#20147, #20492, #20632, #21015, #20838) (Thanks @eltociear!)
  • +
  • Add the missing alias LP to -LiteralPath for some cmdlets (#20820) (Thanks @ImportTaste!)
  • +
  • Remove parenthesis for empty attribute parameters (#20087) (Thanks @ThomasNieto!)
  • +
  • Add space around keyword according to the CodeFactor rule (#20090) (Thanks @ThomasNieto!)
  • +
  • Remove blank lines as instructed by CodeFactor rules (#20086) (Thanks @ThomasNieto!)
  • +
  • Remove trailing whitespace (#20085) (Thanks @ThomasNieto!)
  • +
  • Fix typo in error message (#20145) (Thanks @0o001!)
  • +
+ +
+ +### Tools + +- Make sure feedback link in the bot's comment is clickable (#20878) (Thanks @floh96!) +- Fix bot so anyone who comments will remove the "Resolution-No Activity" label (#20788) +- Fix bot configuration to prevent multiple comments about "no activity" (#20758) +- Add bot logic for closing GitHub issues after 6 months of "no activity" (#20525) +- Refactor bot for easier use and updating (#20805) +- Configure bot to add survey comment for closed issues (#20397) + +### Tests + +- Suppress error output from `Set-Location` tests (#20499) +- Fix typo in `FileCatalog.Tests.ps1` (#20329) (Thanks @eltociear!) +- Continue to improve tests for release automation (#20182) +- Skip the test on x86 as `InstallDate` is not visible on `Wow64` (#20165) +- Harden some problematic release tests (#20155) + +### Build and Packaging Improvements + +
+ + + +

We thank the following contributors!

+

@alerickson, @Zhoneym, @0o001

+ +
+ +
    +
  • Bump .NET SDK to 8.0.101 (#21084)
  • +
  • Update the cgmanifest (#20083, #20436, #20523, #20560, #20627, #20764, #20906, #20933, #20955, #21047)
  • +
  • Update to the latest NOTICES file (#20074, #20161, #20385, #20453, #20576, #20590, #20880, #20905)
  • +
  • Bump StyleCop.Analyzers from 1.2.0-beta.507 to 1.2.0-beta.556 (#20953)
  • +
  • Bump xUnit to 2.6.6 (#21071)
  • +
  • Bump JsonSchema.Net to 5.5.0 (#21027)
  • +
  • Fix failures in GitHub action markdown-link-check (#20996)
  • +
  • Bump xunit.runner.visualstudio to 2.5.6 (#20966)
  • +
  • Bump github/codeql-action from 2 to 3 (#20927)
  • +
  • Bump Markdig.Signed to 0.34.0 (#20926)
  • +
  • Bump Microsoft.ApplicationInsights from 2.21.0 to 2.22.0 (#20888)
  • +
  • Bump Microsoft.NET.Test.Sdk to 17.8.0 (#20660)
  • +
  • Update apiscan.yml to have access to the AzDevOpsArtifacts variable group (#20671)
  • +
  • Set the ollForwardOnNoCandidateFx in runtimeconfig.json to roll forward only on minor and patch versions (#20689)
  • +
  • Sign the global tool shim executable (#20794)
  • +
  • Bump actions/github-script from 6 to 7 (#20682)
  • +
  • Remove RHEL7 publishing to packages.microsoft.com as it's no longer supported (#20849)
  • +
  • Bump Microsoft.CodeAnalysis.CSharp to 4.8.0 (#20751)
  • +
  • Add internal nuget feed to compliance build (#20669)
  • +
  • Copy azure blob with PowerShell global tool to private blob and move to CDN during release (#20659)
  • +
  • Fix release build by making the internal SDK parameter optional (#20658)
  • +
  • Update PSResourceGet version to 1.0.1 (#20652)
  • +
  • Make internal .NET SDK URL as a parameter for release builld (#20655)
  • +
  • Fix setting of variable to consume internal SDK source (#20644)
  • +
  • Bump Microsoft.Management.Infrastructure to v3.0.0 (#20642)
  • +
  • Bump Microsoft.PowerShell.Native to v7.4.0 (#20617)
  • +
  • Bump Microsoft.Security.Extensions from 1.2.0 to 1.3.0 (#20556)
  • +
  • Fix package version for .NET nuget packages (#20551)
  • +
  • Add SBOM for release pipeline (#20519)
  • +
  • Block any preview vPack release (#20243)
  • +
  • Only registry App Path for release package (#20478)
  • +
  • Increase timeout when publishing packages to pacakages.microsoft.com (#20470)
  • +
  • Fix alpine tar package name and do not crossgen alpine fxdependent package (#20459)
  • +
  • Bump PSReadLine from 2.2.6 to 2.3.4 (#20305)
  • +
  • Remove the ref folder before running compliance (#20373)
  • +
  • Updates RIDs used to generate component Inventory (#20370)
  • +
  • Bump XunitXml.TestLogger from 3.1.11 to 3.1.17 (#20293)
  • +
  • Update experimental-feature json files (#20335)
  • +
  • Use fxdependent-win-desktop runtime for compliance runs (#20326)
  • +
  • Release build: Change the names of the PATs (#20307)
  • +
  • Add mapping for mariner arm64 stable (#20213)
  • +
  • Put the calls to Set-AzDoProjectInfo and Set-AzDoAuthToken in the right order (#20306)
  • +
  • Enable vPack provenance data (#20220)
  • +
  • Bump actions/checkout from 3 to 4 (#20205)
  • +
  • Start using new packages.microsoft.com cli (#20140, #20141)
  • +
  • Add mariner arm64 to PMC release (#20176)
  • +
  • Fix typo donet to dotnet in build scripts and pipelines (#20122) (Thanks @0o001!)
  • +
  • Install the pmc cli
  • +
  • Add skip publish parameter
  • +
  • Add verbose to clone
  • +
+ +
+ +### Documentation and Help Content + +- Include information about upgrading in readme (#20993) +- Expand "iff" to "if-and-only-if" in XML doc content (#20852) +- Update LTS links in README.md to point to the v7.4 packages (#20839) (Thanks @kilasuit!) +- Update `README.md` to improve readability (#20553) (Thanks @AnkitaSikdar005!) +- Fix link in `docs/community/governance.md` (#20515) (Thanks @suravshresth!) +- Update `ADOPTERS.md` (#20555) (Thanks @AnkitaSikdar005!) +- Fix a typo in `ADOPTERS.md` (#20504, #20520) (Thanks @shruti-sen2004!) +- Correct grammatical errors in `README.md` (#20509) (Thanks @alienishi!) +- Add 7.3 changelog URL to readme (#20473) (Thanks @Saibamen!) +- Clarify some comments and documentation (#20462) (Thanks @darkstar!) + +[7.5.0-preview.1]: https://github.com/PowerShell/PowerShell/compare/v7.4.1...v7.5.0-preview.1 From a6525aa080d9949073ce8a7a94e817aa5c591ff3 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 17 Jan 2025 13:26:45 -0800 Subject: [PATCH 067/275] Fixed release pipeline errors and switched to KS3 (#24751) (#24815) * Fixed an error in the release pipeline * Fixed ReleaseTag and Version variable in validate packages * Switched from Netlock to KS3 --------- Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung --- .pipelines/PowerShell-Release-Official.yml | 2 +- .../templates/release-SetReleaseTagandContainerName.yml | 6 +++--- .pipelines/templates/release-create-msix.yml | 2 +- .pipelines/templates/release-githubtasks.yml | 1 + .pipelines/templates/release-validate-globaltools.yml | 4 ++-- .pipelines/templates/release-validate-packagenames.yml | 2 +- .pipelines/templates/release-validate-sdk.yml | 2 +- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 6a17139e05e..30c820cabcc 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -88,7 +88,7 @@ extends: featureFlags: WindowsHostVersion: Version: 2022 - Network: Netlock + Network: KS3 cloudvault: enabled: false globalSdl: diff --git a/.pipelines/templates/release-SetReleaseTagandContainerName.yml b/.pipelines/templates/release-SetReleaseTagandContainerName.yml index 667132f5f90..407a3a8f91d 100644 --- a/.pipelines/templates/release-SetReleaseTagandContainerName.yml +++ b/.pipelines/templates/release-SetReleaseTagandContainerName.yml @@ -15,12 +15,12 @@ steps: displayName: Set Release Tag - pwsh: | - $azureVersion = '$(ReleaseTag)'.ToLowerInvariant() -replace '\.', '-' - $vstsCommandString = "vso[task.setvariable variable=AzureVersion]$azureVersion" + $azureVersion = '$(OutputReleaseTag.ReleaseTag)'.ToLowerInvariant() -replace '\.', '-' + $vstsCommandString = "vso[task.setvariable variable=AzureVersion;isOutput=true]$azureVersion" Write-Host "sending " + $vstsCommandString Write-Host "##$vstsCommandString" - $version = '$(ReleaseTag)'.ToLowerInvariant().Substring(1) + $version = '$(OutputReleaseTag.ReleaseTag)'.ToLowerInvariant().Substring(1) $vstsCommandString = "vso[task.setvariable variable=Version;isOutput=true]$version" Write-Host ("sending " + $vstsCommandString) Write-Host "##$vstsCommandString" diff --git a/.pipelines/templates/release-create-msix.yml b/.pipelines/templates/release-create-msix.yml index 448a46c1194..3b1573d9777 100644 --- a/.pipelines/templates/release-create-msix.yml +++ b/.pipelines/templates/release-create-msix.yml @@ -96,7 +96,7 @@ jobs: azurePowerShellVersion: LatestVersion pwsh: true inline: | - $containerName = '$(AzureVersion)-private' + $containerName = '$(OutputVersion.AzureVersion)-private' $storageAccount = '$(StorageAccount)' $storageContext = New-AzStorageContext -StorageAccountName $storageAccount -UseConnectedAccount diff --git a/.pipelines/templates/release-githubtasks.yml b/.pipelines/templates/release-githubtasks.yml index 4af3c973205..31e66b793a4 100644 --- a/.pipelines/templates/release-githubtasks.yml +++ b/.pipelines/templates/release-githubtasks.yml @@ -63,6 +63,7 @@ jobs: pwsh: true script: | Import-module '$(Pipeline.Workspace)/ToolArtifact/GitHubRelease.psm1' + $releaseVersion = '$(ReleaseTag)' -replace '^v','' Write-Verbose -Verbose "Available modules: " Get-Module | Write-Verbose -Verbose diff --git a/.pipelines/templates/release-validate-globaltools.yml b/.pipelines/templates/release-validate-globaltools.yml index fba8b7b3f91..0820e5591f6 100644 --- a/.pipelines/templates/release-validate-globaltools.yml +++ b/.pipelines/templates/release-validate-globaltools.yml @@ -85,7 +85,7 @@ jobs: $packageName = '${{ parameters.globalToolPackageName }}' Write-Verbose -Verbose "Installing $packageName" - dotnet tool install --add-source "$ENV:PIPELINE_WORKSPACE/PSPackagesOfficial/drop_nupkg_build_nupkg" --tool-path $toolPath --version '$(Version)' $packageName + dotnet tool install --add-source "$ENV:PIPELINE_WORKSPACE/PSPackagesOfficial/drop_nupkg_build_nupkg" --tool-path $toolPath --version '$(OutputVersion.Version)' $packageName Get-ChildItem -Path $toolPath @@ -133,7 +133,7 @@ jobs: $versionFound = & $toolPath -c '$PSVersionTable.PSVersion.ToString()' - if ( '$(Version)' -ne $versionFound) + if ( '$(OutputVersion.Version)' -ne $versionFound) { throw "Expected version of global tool not found. Installed version is $versionFound" } diff --git a/.pipelines/templates/release-validate-packagenames.yml b/.pipelines/templates/release-validate-packagenames.yml index 8b08f8d8436..3e2987591aa 100644 --- a/.pipelines/templates/release-validate-packagenames.yml +++ b/.pipelines/templates/release-validate-packagenames.yml @@ -50,7 +50,7 @@ jobs: inline: | $storageAccount = Get-AzStorageAccount -ResourceGroupName '$(StorageResourceGroup)' -Name '$(StorageAccount)' $ctx = $storageAccount.Context - $container = '$(AzureVersion)' + $container = '$(OutputVersion.AzureVersion)' $destinationPath = '$(System.ArtifactsDirectory)' $blobList = Get-AzStorageBlob -Container $container -Context $ctx diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index db3f550b965..3f365f5ebb9 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -95,7 +95,7 @@ jobs: "@ - $releaseVersion = '$(Version)' + $releaseVersion = '$(OutputVersion.Version)' Write-Verbose -Message "Release Version: $releaseVersion" -Verbose From 713e77f15f63bae9f23fb02045c7843ad6a8769b Mon Sep 17 00:00:00 2001 From: Justin Chung Date: Thu, 23 Jan 2025 14:15:16 -0600 Subject: [PATCH 068/275] Finish 7.5.0 release From 8f315cdec5a7a5d00f7b90cd7367e80454d95ea9 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Thu, 23 Jan 2025 14:22:52 -0600 Subject: [PATCH 069/275] Finish 7.5.0 release (#24855) Co-authored-by: Justin Chung From 06997b40057bbddb9f7cec7bca2c2a418296a2c2 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 23 Jan 2025 17:02:32 -0500 Subject: [PATCH 070/275] [release/v7.5]Add EV2 support for publishing PowerShell packages to PMC (#24856) Signed-off-by: dependabot[bot] Co-authored-by: Justin Chung Co-authored-by: Justin Chung Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Aditya Patwardhan Co-authored-by: alerickson <25858831+alerickson@users.noreply.github.com> Co-authored-by: Patrick Meinecke Co-authored-by: Travis Plunk Co-authored-by: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jordan Borean --- .../ServiceGroupRoot/RolloutSpec.json | 28 ++ .../ServiceGroupRoot/ScopeBindings.json | 23 ++ .../ServiceGroupRoot/ServiceModel.json | 51 +++ .../ServiceGroupRoot/Shell/Run/Run.ps1 | 384 ++++++++++++++++++ .../ServiceGroupRoot/UploadLinux.Rollout.json | 54 +++ .../EV2Specs/ServiceGroupRoot/buildVer.txt | 1 + .../PowerShell-Release-Official-Azure.yml | 101 +++++ .../release-SetReleaseTagandContainerName.yml | 8 + .pipelines/templates/release-prep-for-ev2.yml | 237 +++++++++++ .pipelines/templates/release-publish-pmc.yml | 125 ++---- 10 files changed, 923 insertions(+), 89 deletions(-) create mode 100644 .pipelines/EV2Specs/ServiceGroupRoot/RolloutSpec.json create mode 100644 .pipelines/EV2Specs/ServiceGroupRoot/ScopeBindings.json create mode 100644 .pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json create mode 100644 .pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 create mode 100644 .pipelines/EV2Specs/ServiceGroupRoot/UploadLinux.Rollout.json create mode 100644 .pipelines/EV2Specs/ServiceGroupRoot/buildVer.txt create mode 100644 .pipelines/PowerShell-Release-Official-Azure.yml create mode 100644 .pipelines/templates/release-prep-for-ev2.yml diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/RolloutSpec.json b/.pipelines/EV2Specs/ServiceGroupRoot/RolloutSpec.json new file mode 100644 index 00000000000..9ed971068cc --- /dev/null +++ b/.pipelines/EV2Specs/ServiceGroupRoot/RolloutSpec.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/rolloutSpecification.json", + "contentVersion": "1.0.0.0", + "rolloutMetadata": { + "serviceModelPath": "ServiceModel.json", + "ScopeBindingsPath": "ScopeBindings.json", + "name": "OneBranch-Demo-Container-Deployment", + "rolloutType": "Major", + "buildSource": { + "parameters": { + "versionFile": "buildver.txt" + } + }, + "Notification": { + "Email": { + "To": "default" + } + } + }, + "orchestratedSteps": [ + { + "name": "UploadLinuxContainer", + "targetType": "ServiceResource", + "targetName": "LinuxContainerUpload", + "actions": ["Shell/Run"] + } + ] +} diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/ScopeBindings.json b/.pipelines/EV2Specs/ServiceGroupRoot/ScopeBindings.json new file mode 100644 index 00000000000..c3a98555867 --- /dev/null +++ b/.pipelines/EV2Specs/ServiceGroupRoot/ScopeBindings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/scopeBindings.json", + "contentVersion": "0.0.0.1", + "scopeBindings": [ + { + "scopeTagName": "Global", + "bindings": [ + { + "find": "__SUBSCRIPTION_ID__", + "replaceWith": "$azureSubscriptionId()" + }, + { + "find": "__RESOURCE_GROUP__", + "replaceWith": "$azureResourceGroup()" + }, + { + "find": "__BUILD_VERSION__", + "replaceWith": "$buildVersion()" + } + ] + } + ] +} diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json b/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json new file mode 100644 index 00000000000..00555349c35 --- /dev/null +++ b/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/serviceModel.json", + "contentVersion": "1.0.0.0", + "serviceMetadata": { + "serviceGroup": "OneBranch-PowerShellDocker", + "environment": "Test" + }, + "serviceResourceGroupDefinitions": [ + { + "name": "OneBranch-PowerShellDocker-RGDef", + "serviceResourceDefinitions": [ + { + "name": "OneBranch-PowerShellDocker.Shell-SRDef", + "composedOf": { + "extension": { + "shell": [ + { + "type": "Run", + "properties": { + "imageName": "adm-mariner-20-l", + "imageVersion": "v11" + } + } + ] + } + } + } + ] + } + ], + "serviceResourceGroups": [ + { + "azureResourceGroupName": "default", + "location": "West US 3", + "instanceOf": "OneBranch-PowerShellDocker-RGDef", + "azureSubscriptionId": "default", + "scopeTags": [ + { + "name": "Global" + } + ], + "serviceResources": [ + { + "Name": "LinuxContainerUpload", + "InstanceOf": "OneBranch-PowerShellDocker.Shell-SRDef", + "RolloutParametersPath": "UploadLinux.Rollout.json" + } + ] + } + ] +} diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 new file mode 100644 index 00000000000..fc00c871c94 --- /dev/null +++ b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 @@ -0,0 +1,384 @@ +<# +This function gets info from pmc's derived list of all repositories and from mapping.json (which contains info on just the repositories powershell publishes packages to, their package formats, etc) +to create a list of repositories PowerShell cares about along with repository Ids, repository full Urls and associated package that will be published to it. +#> +function Get-MappedRepositoryIds { + param( + [Parameter(Mandatory)] + [hashtable] + $Mapping, + + [Parameter(Mandatory)] + $RepoList, + + # LTS is not consider a package in this context. + # LTS is just another package name. + [Parameter(Mandatory)] + [ValidateSet('stable', 'preview')] + $Channel + ) + + $mappedReposUsedByPwsh = @() + foreach ($package in $Mapping.Packages) + { + Write-Verbose "package: $package" + $packageChannel = $package.channel + if (!$packageChannel) { + $packageChannel = 'all' + } + + Write-Verbose "package channel: $packageChannel" + if ($packageChannel -eq 'all' -or $packageChannel -eq $Channel) + { + $repoIds = [System.Collections.Generic.List[string]]::new() + $packageFormat = $package.PackageFormat + Write-Verbose "package format: $packageFormat" -Verbose + $extension = [System.io.path]::GetExtension($packageFormat) + $packageType = $extension -replace '^\.' + + if ($package.distribution.count -gt 1) { + throw "Package $($package | out-string) has more than one Distribution." + } + + foreach ($distribution in $package.distribution) + { + $urlGlob = $package.url + switch ($packageType) + { + 'deb' { + $urlGlob = $urlGlob + '-apt' + } + 'rpm' { + $urlGlob = $urlGlob + '-yum' + } + default { + throw "Unknown package type: $packageType" + } + } + + Write-Verbose "---Finding repo id for: $urlGlob---" -Verbose + $repos = $RepoList | Where-Object { $_.name -eq $urlGlob } + + if ($repos.id) { + Write-Verbose "Found repo id: $($repos.id)" -Verbose + $repoIds.AddRange(([string[]]$repos.id)) + } + else { + Write-Failure "Could not find repo for $urlGlob" + } + + if ($repoIds.Count -gt 0) { + $mappedReposUsedByPwsh += ($package + @{ "RepoId" = $repoIds.ToArray() }) + } + } + } + } + + Write-Verbose -Verbose "mapped repos length: $($mappedReposUsedByPwsh.Length)" + return $mappedReposUsedByPwsh +} + +<# +This function creates package objects for the packages to be published, +with the package name (ie package name format resolve with channel based PackageName and pwsh version), repoId, distribution and package path. +#> +function Get-PackageObjects() { + param( + [Parameter(Mandatory)] + [psobject[]] + $RepoObjects, + + [Parameter(Mandatory)] + [string] + $ReleaseVersion, + + [Parameter(Mandatory)] + [string[]] + $PackageName + ) + + $packages = @() + + foreach ($pkg in $RepoObjects) + { + if ($pkg.RepoId.count -gt 1) { + throw "Package $($pkg.name) has more than one repo id." + } + + if ($pkg.Distribution.count -gt 1) { + throw "Package $($pkg.name) has more than one Distribution." + } + + $pkgRepo = $pkg.RepoId | Select-Object -First 1 + $pkgDistribution = $pkg.Distribution | Select-Object -First 1 + + foreach ($name in $PackageName) { + $pkgName = $pkg.PackageFormat.Replace('PACKAGE_NAME', $name).Replace('POWERSHELL_RELEASE', $ReleaseVersion) + + if ($pkgName.EndsWith('.rpm')) { + $pkgName = $pkgName.Replace($ReleaseVersion, $ReleaseVersion.Replace('-', '_')) + } + + $packagePath = "$pwshPackagesFolder/$pkgName" + $packagePathExists = Test-Path -Path $packagePath + if (!$packagePathExists) + { + throw "package path $packagePath does not exist" + } + + Write-Verbose "Creating package info object for package '$pkgName' for repo '$pkgRepo'" + $packages += @{ + PackagePath = $packagePath + PackageName = $pkgName + RepoId = $pkgRepo + Distribution = $pkgDistribution + } + + Write-Verbose -Verbose "package info obj: Name: $pkgName RepoId: $pkgRepo Distribution: $pkgDistribution PackagePath: $packagePath" + } + } + + Write-Verbose -Verbose "count of packages objects: $($packages.Length)" + return $packages +} + +<# +This function stages, uploads and publishes the powershell packages to their associated repositories in PMC. +#> +function Publish-PackageToPMC() { + param( + [Parameter(Mandatory)] + [pscustomobject[]] + $PackageObject, + + [Parameter(Mandatory)] + [string] + $ConfigPath, + + [Parameter(Mandatory)] + [bool] + $SkipPublish + ) + + # Don't fail outright when an error occurs, but instead pool them until + # after attempting to publish every package. That way we can choose to + # proceed for a partial failure. + $errorMessage = [System.Collections.Generic.List[string]]::new() + foreach ($finalPackage in $PackageObject) + { + Write-Verbose "---Staging package: $($finalPackage.PackageName)---" -Verbose + $packagePath = $finalPackage.PackagePath + $pkgRepo = $finalPackage.RepoId + + $extension = [System.io.path]::GetExtension($packagePath) + $packageType = $extension -replace '^\.' + Write-Verbose "packageType: $packageType" -Verbose + + $packageListJson = pmc --config $ConfigPath package $packageType list --file $packagePath + $list = $packageListJson | ConvertFrom-Json + + $packageId = @() + if ($list.count -ne 0) + { + Write-Verbose "Package '$packagePath' already exists, skipping upload" -Verbose + $packageId = $list.results.id | Select-Object -First 1 + } + else { + # PMC UPLOAD COMMAND + Write-Verbose -Verbose "Uploading package, config: '$ConfigPath' package: '$packagePath'" + $uploadResult = $null + try { + $uploadResult = pmc --config $ConfigPath package upload $packagePath --type $packageType + } + catch { + $errorMessage.Add("Uploading package $($finalPackage.PackageName) to $pkgRepo failed. See errors above for details.") + continue + } + + $packageId = ($uploadResult | ConvertFrom-Json).id + } + + Write-Verbose "Got package ID: '$packageId'" -Verbose + $distribution = $finalPackage.Distribution | select-object -First 1 + Write-Verbose "distribution: $distribution" -Verbose + + if (!$SkipPublish) + { + Write-Verbose "---Publishing package: $($finalPackage.PackageName) to $pkgRepo---" -Verbose + + if (($packageType -ne 'rpm') -and ($packageType -ne 'deb')) + { + throw "Unsupported package type: $packageType" + return 1 + } + else { + # PMC UPDATE COMMAND + $rawUpdateResponse = $null + try { + if ($packageType -eq 'rpm') { + $rawUpdateResponse = pmc --config $ConfigPath repo package update $pkgRepo --add-packages $packageId + } elseif ($packageType -eq 'deb') { + $rawUpdateResponse = pmc --config $ConfigPath repo package update $pkgRepo $distribution --add-packages $packageId + } + } + catch { + $errorMessage.Add("Invoking update for package $($finalPackage.PackageName) to $pkgRepo failed. See errors above for details.") + continue + } + + $state = $rawUpdateResponse.state + if ($state -ne 'Completed') { + $errorMessage.Add("Publishing package $($finalPackage.PackageName) to $pkgRepo failed: $rawUpdateResponse") + continue + } + } + + # PMC PUBLISH COMMAND + # The CLI outputs messages and JSON in the same stream, so we must sift through it for now + # This is planned to be fixed with a switch in a later release + Write-Verbose -Verbose ([pscustomobject]($package + @{ + PackageId = $packageId + })) + + # At this point, the changes are staged and will eventually be publish. + # Running publish, causes them to go live "immediately" + try { + pmc --config $ConfigPath repo publish $pkgRepo + } + catch { + $errorMessage.Add("Running final publish for package $($finalPackage.PackageName) to $pkgRepo failed. See errors above for details.") + continue + } + } else { + Write-Verbose -Verbose "Skipping Uploading package --config-file '$ConfigPath' package add '$packagePath' --repoID '$pkgRepo'" + } + } + + if ($errorMessage) { + throw $errorMessage -join [Environment]::NewLine + } +} + +if ($null -eq $env:MAPPING_FILE) +{ + Write-Verbose -Verbose "MAPPING_FILE variable didn't get passed correctly" + return 1 +} + +if ($null -eq $env:PWSH_PACKAGES_TARGZIP) +{ + Write-Verbose -Verbose "PWSH_PACKAGES_TARGZIP variable didn't get passed correctly" + return 1 +} + +if ($null -eq $env:PMC_METADATA) +{ + Write-Verbose -Verbose "PMC_METADATA variable didn't get passed correctly" + return 1 +} + +try { + Write-Verbose -Verbose "Downloading files" + Invoke-WebRequest -Uri $env:MAPPING_FILE -OutFile mapping.json + Invoke-WebRequest -Uri $env:PWSH_PACKAGES_TARGZIP -OutFile packages.tar.gz + Invoke-WebRequest -Uri $env:PMC_METADATA -OutFile pmcMetadata.json + + # create variables to those paths and test them + $mappingFilePath = Join-Path "/package/unarchive/" -ChildPath "mapping.json" + $mappingFilePathExists = Test-Path $mappingFilePath + if (!$mappingFilePathExists) + { + Write-Verbose -Verbose "mapping.json expected at $mappingFilePath does not exist" + return 1 + } + + $packagesTarPath = Join-Path -Path "/package/unarchive/" -ChildPath "packages.tar.gz" + $packagesTarPathExists = Test-Path $packagesTarPath + if (!$packagesTarPathExists) + { + Write-Verbose -Verbose "packages.tar.gz expected at $packagesTarPath does not exist" + return 1 + } + + # Extract files from 'packages.tar.gz' + Write-Verbose -Verbose "---Extracting files from packages.tar.gz---" + $pwshPackagesFolder = Join-Path -Path "/package/unarchive/" -ChildPath "packages" + New-Item -Path $pwshPackagesFolder -ItemType Directory + tar -xzvf $packagesTarPath -C $pwshPackagesFolder --force-local + Get-ChildItem $pwshPackagesFolder -Recurse + + $metadataFilePath = Join-Path -Path "/package/unarchive/" -ChildPath "pmcMetadata.json" + $metadataFilePathExists = Test-Path $metadataFilePath + if (!$metadataFilePathExists) + { + Write-Verbose -Verbose "pmcMetadata.json expected at $metadataFilePath does not exist" + return 1 + } + + # files in the extracted Run dir + $configPath = Join-Path '/package/unarchive/Run' -ChildPath 'settings.toml' + $configPathExists = Test-Path -Path $configPath + if (!$configPathExists) + { + Write-Verbose -Verbose "settings.toml expected at $configPath does not exist" + return 1 + } + + $pythonDlFolder = Join-Path '/package/unarchive/Run' -ChildPath 'python_dl' + $pyPathExists = Test-Path -Path $pythonDlFolder + if (!$pyPathExists) + { + Write-Verbose -Verbose "python_dl expected at $pythonDlFolder does not exist" + return 1 + } + + Write-Verbose -Verbose "Installing pmc-cli" + pip install --upgrade pip + pip --version --verbose + pip install /package/unarchive/Run/python_dl/*.whl + + # Get metadata + $channel = "" + $packageNames = @() + $metadataContent = Get-Content -Path $metadataFilePath | ConvertFrom-Json + $releaseVersion = $metadataContent.ReleaseTag.TrimStart('v') + $skipPublish = $metadataContent.SkipPublish + $lts = $metadataContent.LTS + + if ($releaseVersion.Contains('-')) { + $channel = 'preview' + $packageNames = @('powershell-preview') + } + else { + $channel = 'stable' + $packageNames = @('powershell') + } + + if ($lts) { + $packageNames += @('powershell-lts') + } + + Write-Verbose -Verbose "---Getting repository list---" + $rawResponse = pmc --config $configPath repo list --limit 800 + $response = $rawResponse | ConvertFrom-Json + $limit = $($response.limit) + $count = $($response.count) + Write-Verbose -Verbose "'pmc repo list' limit is: $limit and count is: $count" + $repoList = $response.results + + Write-Verbose -Verbose "---Getting package info---" + + + Write-Verbose "Reading mapping file from '$mappingFilePath'" -Verbose + $mapping = Get-Content -Raw -LiteralPath $mappingFilePath | ConvertFrom-Json -AsHashtable + $mappedReposUsedByPwsh = Get-MappedRepositoryIds -Mapping $mapping -RepoList $repoList -Channel $channel + $packageObjects = Get-PackageObjects -RepoObjects $mappedReposUsedByPwsh -PackageName $packageNames -ReleaseVersion $releaseVersion + Write-Verbose -Verbose "skip publish $skipPublish" + Publish-PackageToPMC -PackageObject $packageObjects -ConfigPath $configPath -SkipPublish $skipPublish +} +catch { + Write-Error -ErrorAction Stop $_.Exception.Message + return 1 +} + +return 0 diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/UploadLinux.Rollout.json b/.pipelines/EV2Specs/ServiceGroupRoot/UploadLinux.Rollout.json new file mode 100644 index 00000000000..d7c75c2e216 --- /dev/null +++ b/.pipelines/EV2Specs/ServiceGroupRoot/UploadLinux.Rollout.json @@ -0,0 +1,54 @@ +{ + "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/rolloutParameters.json", + "contentVersion": "1.0.0.0", + "shellExtensions": [ + { + "name": "Run", + "type": "Run", + "properties": { + "maxExecutionTime": "PT2H" + }, + "package": { + "reference": { + "path": "Shell/Run.tar" + } + }, + "launch": { + "command": [ + "/bin/bash", + "-c", + "pwsh ./Run/Run.ps1" + ], + "environmentVariables": [ + { + "name": "MAPPING_FILE", + "reference": + { + "path": "Parameters\\mapping.json" + } + }, + { + "name": "PWSH_PACKAGES_TARGZIP", + "reference": + { + "path": "Parameters\\packages.tar.gz" + } + }, + { + "name": "PMC_METADATA", + "reference": + { + "path": "Parameters\\pmcMetadata.json" + } + } + ], + "identity": { + "type": "userAssigned", + "userAssignedIdentities": [ + "default" + ] + } + } + } + ] +} diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/buildVer.txt b/.pipelines/EV2Specs/ServiceGroupRoot/buildVer.txt new file mode 100644 index 00000000000..7dea76edb3d --- /dev/null +++ b/.pipelines/EV2Specs/ServiceGroupRoot/buildVer.txt @@ -0,0 +1 @@ +1.0.1 diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml new file mode 100644 index 00000000000..db6b114d901 --- /dev/null +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -0,0 +1,101 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time + - name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + - name: skipPublish + displayName: Skip PMC Publish + type: boolean + default: false + - name: SKIP_SIGNING + displayName: Skip Signing + type: string + default: 'NO' + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: ENABLE_PRS_DELAYSIGN + value: 1 + - name: ROOT + value: $(Build.SourcesDirectory) + - name: REPOROOT + value: $(Build.SourcesDirectory) + - name: OUTPUTROOT + value: $(REPOROOT)\out + - name: NUGET_XMLDOC_MODE + value: none + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\.config\tsaoptions.json + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/cbl-mariner/build:2.0 + - group: PoolNames + +resources: + repositories: + - repository: templates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated Packages-Official' + + - pipeline: PSPackagesOfficial + source: 'PowerShell-Packages-Official' + trigger: + branches: + include: + - master + - releases/* + +extends: + template: v2/OneBranch.Official.CrossPlat.yml@templates + parameters: + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: Netlock + linuxEsrpSigning: true + cloudvault: + enabled: false + globalSdl: + disableLegacyManifest: true + # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + asyncSdl: + enabled: true + tsaOptionsFile: .config/tsaoptions.json + tsa: + enabled: true + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + break: false # always break the build on binskim issues in addition to TSA upload + policheck: + break: true # always break the build on policheck issues. You can disable it by setting to 'false' + tsaOptionsFile: .config\tsaoptions.json + stages: + - template: /.pipelines/templates/release-prep-for-ev2.yml@self + parameters: + skipPublish: ${{ parameters.skipPublish }} + + - template: /.pipelines/templates/release-publish-pmc.yml@self diff --git a/.pipelines/templates/release-SetReleaseTagandContainerName.yml b/.pipelines/templates/release-SetReleaseTagandContainerName.yml index 407a3a8f91d..d40551353d2 100644 --- a/.pipelines/templates/release-SetReleaseTagandContainerName.yml +++ b/.pipelines/templates/release-SetReleaseTagandContainerName.yml @@ -1,3 +1,7 @@ +parameters: +- name: restorePhase + default: false + steps: - pwsh: | $variable = 'releaseTag' @@ -13,6 +17,8 @@ steps: Write-Host -Object "##$vstsCommandString" name: OutputReleaseTag displayName: Set Release Tag + env: + ob_restore_phase: ${{ parameters.restorePhase }} - pwsh: | $azureVersion = '$(OutputReleaseTag.ReleaseTag)'.ToLowerInvariant() -replace '\.', '-' @@ -26,3 +32,5 @@ steps: Write-Host "##$vstsCommandString" name: OutputVersion displayName: Set container name + env: + ob_restore_phase: ${{ parameters.restorePhase }} diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml new file mode 100644 index 00000000000..cf7982cd5e1 --- /dev/null +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -0,0 +1,237 @@ +parameters: +- name: skipPublish + type: boolean + default: false + +stages: +- stage: PrepForEV2 + displayName: 'Copy and prep all files needed for EV2 stage' + jobs: + - job: CopyEV2FilesToArtifact + displayName: 'Copy EV2 Files to Artifact' + pool: + type: linux + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: repoRoot + value: '$(Build.SourcesDirectory)/PowerShell' + - name: ev2ServiceGroupRootFolder + value: '$(Build.SourcesDirectory)/PowerShell/.pipelines/EV2Specs/ServiceGroupRoot' + - name: ev2ParametersFolder + value: '$(Build.SourcesDirectory)/PowerShell/.pipelines/EV2Specs/ServiceGroupRoot/Parameters' + - group: 'mscodehub-code-read-akv' + - group: 'packages.microsoft.com' + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + steps: + - checkout: self ## the global setting on lfs didn't work + lfs: false + env: + ob_restore_phase: true + + - template: release-SetReleaseTagandContainerName.yml + parameters: + restorePhase: true + + - pwsh: | + $packageVersion = '$(OutputReleaseTag.ReleaseTag)'.ToLowerInvariant() -replace '^v','' + $vstsCommandString = "vso[task.setvariable variable=packageVersion]$packageVersion" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: Set Package version + env: + ob_restore_phase: true + + - pwsh: | + $branch = 'mirror-target' + $gitArgs = "clone", + "--verbose", + "--branch", + "$branch", + "https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/Internal-PowerShellTeam-Tools", + '$(Pipeline.Workspace)/tools' + $gitArgs | Write-Verbose -Verbose + git $gitArgs + displayName: Clone Internal-PowerShellTeam-Tools from MSCodeHub + env: + ob_restore_phase: true + + - pwsh: | + Get-ChildItem Env: | Out-String -Stream | write-Verbose -Verbose + displayName: 'Capture Environment Variables' + env: + ob_restore_phase: true + + - pwsh: | + Get-ChildItem '$(Build.SourcesDirectory)' + displayName: 'Capture BuildDirectory' + env: + ob_restore_phase: true + + - pwsh: | + Get-ChildItem '$(Pipeline.Workspace)' -Recurse | Out-String -Stream | write-Verbose -Verbose + displayName: 'Capture Workspace' + env: + ob_restore_phase: true + + - pwsh: | + New-Item -Path '$(ev2ParametersFolder)' -ItemType Directory + displayName: 'Create Parameters folder under EV2Specs folder' + env: + ob_restore_phase: true + + - task: PipAuthenticate@1 + inputs: + artifactFeeds: 'PowerShellCore/PowerShellCore_PublicPackages' + displayName: 'Pip Authenticate' + env: + ob_restore_phase: true + + - pwsh: | + python3 -m pip install --upgrade pip + pip --version --verbose + + Write-Verbose -Verbose "Download pmc-cli to folder without installing it" + $pythonDlFolderPath = Join-Path '$(ev2ServiceGroupRootFolder)/Shell/Run' -ChildPath "python_dl" + pip download -d $pythonDlFolderPath pmc-cli --platform=manylinux_2_17_x86_64 --only-binary=:all: --verbose + displayName: 'Download pmc-cli package' + env: + ob_restore_phase: true + + - download: PSPackagesOfficial + artifact: 'drop_linux_package_deb' + displayName: 'Download artifact containing .deb_amd64.deb file from PSPackagesOfficial triggering pipeline' + env: + ob_restore_phase: true + + - download: PSPackagesOfficial + artifact: 'drop_linux_package_rpm' + displayName: 'Download artifact containing .rh.x64_86.rpm file from PSPackagesOfficial triggering pipeline' + env: + ob_restore_phase: true + + - download: PSPackagesOfficial + artifact: 'drop_linux_package_mariner_x64' + displayName: 'Download artifact containing .cm.x86_64.rpm file from PSPackagesOfficial triggering pipeline' + env: + ob_restore_phase: true + + - download: PSPackagesOfficial + artifact: 'drop_linux_package_mariner_arm64' + displayName: 'Download artifact containing .cm.aarch64.rpm file from PSPackagesOfficial triggering pipeline' + env: + ob_restore_phase: true + + - pwsh: | + Write-Verbose -Verbose "Copy ESRP signed .deb and .rpm packages" + $downloadedPipelineFolder = Join-Path '$(Pipeline.Workspace)' -ChildPath 'PSPackagesOfficial' + $srcFilesFolder = Join-Path -Path '$(Pipeline.Workspace)' -ChildPath 'SourceFiles' + New-Item -Path $srcFilesFolder -ItemType Directory + $packagesFolder = Join-Path -Path $srcFilesFolder -ChildPath 'packages' + New-Item -Path $packagesFolder -ItemType Directory + + $packageFiles = Get-ChildItem -Path $downloadedPipelineFolder -Recurse -Directory -Filter "drop_*" | Get-ChildItem -File -Include *.deb, *.rpm + foreach ($file in $packageFiles) + { + Write-Verbose -Verbose "copying file: $($file.FullName)" + Copy-Item -Path $($file.FullName) -Destination $packagesFolder -Verbose + } + + $packagesTarGzDestination = Join-Path -Path '$(ev2ParametersFolder)' -ChildPath 'packages.tar.gz' + tar -czvf $packagesTarGzDestination -C $packagesFolder . + displayName: 'Copy signed .deb and .rpm packages to .tar.gz to pass as a file var to shell extension' + env: + ob_restore_phase: true + + - pwsh: | + $pathToPMCMetadataFile = Join-Path -Path '$(ev2ParametersFolder)' -ChildPath 'pmcMetadata.json' + + $metadata = Get-Content -Path "$(repoRoot)/tools/metadata.json" -Raw | ConvertFrom-Json + $metadataHash = @{} + $skipPublishValue = '${{ parameters.skipPublish }}' + $metadataHash["ReleaseTag"] = '$(OutputReleaseTag.ReleaseTag)' + $metadataHash["LTS"] = $metadata.LTSRelease.Latest + $metadataHash["ForProduction"] = $true + $metadataHash["SkipPublish"] = [System.Convert]::ToBoolean($skipPublishValue) + + $metadataHash | ConvertTo-Json | Out-File $pathToPMCMetadataFile + + $mappingFilePath = Join-Path -Path '$(repoRoot)/tools/packages.microsoft.com' -ChildPath 'mapping.json' + $mappingFilePathExists = Test-Path $mappingFilePath + $mappingFileEV2Path = Join-Path -Path '$(ev2ParametersFolder)' -ChildPath "mapping.json" + Write-Verbose -Verbose "Copy mapping.json file at: $mappingFilePath which exists: $mappingFilePathExists to: $mappingFileEV2Path" + Copy-Item -Path $mappingFilePath -Destination $mappingFileEV2Path + displayName: 'Create pmcScriptMetadata.json and mapping.json file' + env: + ob_restore_phase: true + + - pwsh: | + $pathToJsonFile = Join-Path -Path '$(ev2ServiceGroupRootFolder)' -ChildPath 'RolloutSpec.json' + $content = Get-Content -Path $pathToJsonFile | ConvertFrom-Json + $content.RolloutMetadata.Notification.Email.To = '$(PmcEV2SupportEmail)' + Remove-Item -Path $pathToJsonFile + $content | ConvertTo-Json -Depth 4 | Out-File $pathToJsonFile + displayName: 'Replace values in RolloutSpecPath.json' + env: + ob_restore_phase: true + + - pwsh: | + $pathToJsonFile = Join-Path -Path '$(ev2ServiceGroupRootFolder)' -ChildPath 'UploadLinux.Rollout.json' + $content = Get-Content -Path $pathToJsonFile | ConvertFrom-Json + + $identityString = "/subscriptions/$(PmcSubscription)/resourcegroups/$(PmcResourceGroup)/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$(PmcMIName)" + $content.shellExtensions.launch.identity.userAssignedIdentities[0] = $identityString + + Remove-Item -Path $pathToJsonFile + $content | ConvertTo-Json -Depth 6 | Out-File $pathToJsonFile + displayName: 'Replace values in UploadLinux.Rollout.json file' + env: + ob_restore_phase: true + + - pwsh: | + $pathToJsonFile = Join-Path -Path '$(ev2ServiceGroupRootFolder)' -ChildPath 'ServiceModel.json' + $content = Get-Content -Path $pathToJsonFile | ConvertFrom-Json + $content.ServiceResourceGroups[0].AzureResourceGroupName = '$(PmcResourceGroup)' + $content.ServiceResourceGroups[0].AzureSubscriptionId = '$(PmcSubscription)' + + Remove-Item -Path $pathToJsonFile + $content | ConvertTo-Json -Depth 9 | Out-File $pathToJsonFile + displayName: 'Replace values in ServiceModel.json' + env: + ob_restore_phase: true + + - pwsh: | + $settingFilePath = Join-Path '$(ev2ServiceGroupRootFolder)/Shell/Run' -ChildPath 'settings.toml' + New-Item -Path $settingFilePath -ItemType File + $pmcMIClientID = '$(PmcMIClientID)' + $pmcEndpoint = '$(PmcEndpointUrl)' + + Add-Content -Path $settingFilePath -Value "[default]" + Add-Content -Path $settingFilePath -Value "base_url = `"$pmcEndpoint`"" + Add-Content -Path $settingFilePath -Value "auth_type = `"msi`"" + Add-Content -Path $settingFilePath -Value "client_id = `"$pmcMIClientID`"" + displayName: 'Create settings.toml file with MI clientId populated' + env: + ob_restore_phase: true + + - task: onebranch.pipeline.signing@1 + inputs: + command: 'sign' + signing_profile: external_distribution + files_to_sign: '*.ps1' + search_root: '$(repoRoot)/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run' + displayName: Sign Run.ps1 + + - pwsh: | + # folder to tar must have: Run.ps1, settings.toml, python_dl + $srcPath = Join-Path '$(ev2ServiceGroupRootFolder)' -ChildPath 'Shell' + $pathToRunTarFile = Join-Path $srcPath -ChildPath "Run.tar" + tar -cvf $pathToRunTarFile -C $srcPath ./Run + displayName: 'Create archive for the shell extension' + + - task: CopyFiles@2 + inputs: + SourceFolder: '$(repoRoot)/.pipelines' + Contents: 'EV2Specs/**' + TargetFolder: $(ob_outputDirectory) diff --git a/.pipelines/templates/release-publish-pmc.yml b/.pipelines/templates/release-publish-pmc.yml index 27311611e61..d5454845211 100644 --- a/.pipelines/templates/release-publish-pmc.yml +++ b/.pipelines/templates/release-publish-pmc.yml @@ -1,90 +1,37 @@ -parameters: - - name: skipPublish - default: false - type: boolean - -jobs: -- job: PMCPublish - displayName: Publish to PMC - condition: succeeded() - pool: - type: linux - isCustom: true - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMSUbuntu20.04-Secure +stages: +- stage: 'Prod_Release' + displayName: 'Deploy packages to PMC with EV2' + dependsOn: + - PrepForEV2 variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE - value: 1 - - group: 'mscodehub-code-read-akv' - - group: 'packages.microsoft.com' - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: ob_sdl_codeSignValidation_enabled - value: false - - name: ob_sdl_binskim_enabled - value: false - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - - steps: - - checkout: self ## the global setting on lfs didn't work - lfs: false - - - template: release-SetReleaseTagAndContainerName.yml - - - pwsh: | - $packageVersion = '$(ReleaseTag)'.ToLowerInvariant() -replace '^v','' - $vstsCommandString = "vso[task.setvariable variable=packageVersion]$packageVersion" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Set Package version - - - pwsh: | - $branch = 'mirror-target' - $gitArgs = "clone", - "--verbose", - "--branch", - "$branch", - "https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/Internal-PowerShellTeam-Tools", - '$(Pipeline.Workspace)/tools' - $gitArgs | Write-Verbose -Verbose - git $gitArgs - displayName: Clone Internal-PowerShellTeam-Tools from MSCodeHub - - - task: PipAuthenticate@1 - inputs: - artifactFeeds: 'pmc' - pythonDownloadServiceConnections: pmcDownload - - - pwsh: | - pip install pmc-cli==1.12.0 - - $newPath = (resolve-path '~/.local/bin').providerpath - $vstsCommandString = "vso[task.setvariable variable=PATH]${env:PATH}:$newPath" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Install pmc cli - - - pwsh: | - $metadata = Get-Content -Path "$(Build.SourcesDirectory)/tools/metadata.json" -Raw | ConvertFrom-Json - $params = @{ - ReleaseTag = "$(ReleaseTag)" - AadClientId = "$(PmcCliClientID)" - BlobFolderName = "$(ReleaseTag)" - LTS = $metadata.LTSRelease.Latest - ForProduction = $true - SkipPublish = $${{ parameters.skipPublish }} - MappingFilePath = '$(System.DefaultWorkingDirectory)/tools/packages.microsoft.com/mapping.json' - } - - $params | Out-String -width 9999 -Stream | write-Verbose -Verbose - - & '$(Pipeline.Workspace)/tools/packages.microsoft.com-v4/releaseLinuxPackages.ps1' @params - displayName: Run release script + - name: ob_release_environment + value: "Production" + - name: repoRoot + value: $(Build.SourcesDirectory) + jobs: + - job: Prod_ReleaseJob + displayName: Publish to PMC + pool: + type: release + + steps: + - task: DownloadPipelineArtifact@2 + inputs: + targetPath: '$(Pipeline.Workspace)' + artifact: drop_PrepForEV2_CopyEv2FilesToArtifact + displayName: 'Download drop_PrepForEV2_CopyEv2FilesToArtifact artifact that has all files needed' + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + targetPath: '$(Pipeline.Workspace)' + displayName: 'Download to get EV2 Files' + + - task: vsrm-ev2.vss-services-ev2.adm-release-task.ExpressV2Internal@1 + displayName: 'Ev2: Push to PMC' + inputs: + UseServerMonitorTask: true + EndpointProviderType: ApprovalService + ApprovalServiceEnvironment: Production + ServiceRootPath: '$(Pipeline.Workspace)/drop_PrepForEV2_CopyEV2FilesToArtifact/EV2Specs/ServiceGroupRoot' + RolloutSpecPath: '$(Pipeline.Workspace)/drop_PrepForEV2_CopyEV2FilesToArtifact/EV2Specs/ServiceGroupRoot/RolloutSpec.json' From 9b348193d94d972c73462e6d9b4e73369071f9b8 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 23 Jan 2025 17:22:59 -0500 Subject: [PATCH 071/275] [release/v7.5]PMC parse state correctly from update command's response (#24859) --- .../EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 index fc00c871c94..25a5686b33e 100644 --- a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 +++ b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 @@ -226,8 +226,9 @@ function Publish-PackageToPMC() { continue } - $state = $rawUpdateResponse.state - if ($state -ne 'Completed') { + $state = ($rawUpdateResponse | ConvertFrom-Json).state + Write-Verbose -Verbose "update response state: $state" + if ($state -ne 'completed') { $errorMessage.Add("Publishing package $($finalPackage.PackageName) to $pkgRepo failed: $rawUpdateResponse") continue } @@ -242,11 +243,19 @@ function Publish-PackageToPMC() { # At this point, the changes are staged and will eventually be publish. # Running publish, causes them to go live "immediately" + $rawPublishResponse = $null try { - pmc --config $ConfigPath repo publish $pkgRepo + $rawPublishResponse = pmc --config $ConfigPath repo publish $pkgRepo } catch { - $errorMessage.Add("Running final publish for package $($finalPackage.PackageName) to $pkgRepo failed. See errors above for details.") + $errorMessage.Add("Invoking final publish for package $($finalPackage.PackageName) to $pkgRepo failed. See errors above for details.") + continue + } + + $publishState = ($rawPublishResponse | ConvertFrom-Json).state + Write-Verbose -Verbose "publish response state: $publishState" + if ($publishState -ne 'completed') { + $errorMessage.Add("Final publishing of package $($finalPackage.PackageName) to $pkgRepo failed: $rawPublishResponse") continue } } else { From cf8256680c0285d47a3cc066141c8ecbc6a514f4 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Tue, 4 Feb 2025 14:26:09 -0800 Subject: [PATCH 072/275] [release/v7.5]Convert powershell/PowerShell-Windows-CI to GitHub Actions (#24931) --- .github/actions/build/ci/action.yml | 49 ++++++++ .github/actions/test/verify_xunit/action.yml | 21 ++++ .github/actions/test/windows/action.yml | 107 ++++++++++++++++ .github/workflows/AssignPrs.yml | 3 +- .github/workflows/rebase.yml | 39 ------ .github/workflows/windows-ci.yml | 124 +++++++++++++++++++ .gitignore | 7 ++ build.psm1 | 10 ++ tools/ci.psm1 | 40 +++++- 9 files changed, 356 insertions(+), 44 deletions(-) create mode 100644 .github/actions/build/ci/action.yml create mode 100644 .github/actions/test/verify_xunit/action.yml create mode 100644 .github/actions/test/windows/action.yml delete mode 100644 .github/workflows/rebase.yml create mode 100644 .github/workflows/windows-ci.yml diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml new file mode 100644 index 00000000000..90968d81cfe --- /dev/null +++ b/.github/actions/build/ci/action.yml @@ -0,0 +1,49 @@ +name: CI Build +description: 'Builds PowerShell' +runs: + using: composite + steps: + - name: Capture Environment + if: success() || failure() + run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' + shell: pwsh + - name: Set Build Name for Non-PR + if: github.event_name != 'PullRequest' + run: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhmmss"))" + shell: pwsh + - name: Bootstrap + if: success() + run: |- + Write-Verbose -Verbose "Running Bootstrap..." + Import-Module .\tools\ci.psm1 + Invoke-CIInstall -SkipUser + Write-Verbose -Verbose "Start Sync-PSTags" + Sync-PSTags -AddRemoteIfMissing + Write-Verbose -Verbose "End Sync-PSTags" + shell: pwsh + - name: Build + if: success() + run: |- + Write-Verbose -Verbose "Running Build..." + Import-Module .\tools\ci.psm1 + Invoke-CIBuild + shell: pwsh + - name: xUnit Tests + if: success() + continue-on-error: true + run: |- + Write-Verbose -Verbose "Running xUnit tests..." + Import-Module .\tools\ci.psm1 + Restore-PSOptions + Invoke-CIxUnit -SkipFailing + shell: pwsh + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + name: build + path: ${{ runner.workspace }}/build + - name: Upload xunit artifact + uses: actions/upload-artifact@v4 + with: + name: testResults-xunit + path: ${{ runner.workspace }}/xunit diff --git a/.github/actions/test/verify_xunit/action.yml b/.github/actions/test/verify_xunit/action.yml new file mode 100644 index 00000000000..fccca27182f --- /dev/null +++ b/.github/actions/test/verify_xunit/action.yml @@ -0,0 +1,21 @@ +name: verify_xunit +description: 'Verify xUnit Results' + +runs: + using: composite + steps: + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + path: "${{ github.workspace }}" + - name: Capture artifacts directory + continue-on-error: true + run: dir "${{ github.workspace }}\testResults-xunit\*" -Recurse + shell: pwsh + - name: Test + if: success() + run: |- + Import-Module .\tools\ci.psm1 + $xUnitTestResultsFile = "${{ github.workspace }}\testResults-xunit\xUnitTestResults.xml" + Test-XUnitTestResults -TestResultsFile $xUnitTestResultsFile + shell: pwsh diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml new file mode 100644 index 00000000000..6cb5cbc1d74 --- /dev/null +++ b/.github/actions/test/windows/action.yml @@ -0,0 +1,107 @@ +name: windows_test +description: 'Test PowerShell on Windows' + +inputs: + purpose: + required: false + default: '' + type: string + tagSet: + required: false + default: CI + type: string + ctrfFolder: + required: false + default: ctrf + type: string + +runs: + using: composite + steps: + - name: Capture Environment + if: success() || failure() + run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' + shell: pwsh + - name: Download Build Artifacts + uses: actions/download-artifact@v4 + with: + path: "${{ github.workspace }}" + - name: Capture Artifacts Directory + continue-on-error: true + run: Get-ChildItem "${{ github.workspace }}\build\*" -Recurse + shell: pwsh + + - name: Bootstrap + shell: powershell + run: |- + # Remove "Program Files\dotnet" from the env variable PATH, so old SDKs won't affect us. + Write-Host "Old Path:" + Write-Host $env:Path + $dotnetPath = Join-Path $env:SystemDrive 'Program Files\dotnet' + $paths = $env:Path -split ";" | Where-Object { -not $_.StartsWith($dotnetPath) } + $env:Path = $paths -join ";" + Write-Host "New Path:" + Write-Host $env:Path + # Bootstrap + Import-Module .\tools\ci.psm1 + Invoke-CIInstall + + - name: Test + if: success() + run: |- + Import-Module .\build.psm1 -force + Start-PSBootstrap + Import-Module .\tools\ci.psm1 + Restore-PSOptions -PSOptionsPath '${{ github.workspace }}\build\psoptions.json' + $options = (Get-PSOptions) + $path = split-path -path $options.Output + $rootPath = split-Path -path $path + Expand-Archive -Path '${{ github.workspace }}\build\build.zip' -DestinationPath $rootPath -Force + Invoke-CITest -Purpose '${{ inputs.purpose }}' -TagSet '${{ inputs.tagSet }}' -OutputFormat JUnitXml + shell: pwsh + + - name: Convert JUnit to CTRF + run: |- + Get-ChildItem -Path "${{ runner.workspace }}/testResults/*.xml" -Recurse | ForEach-Object { + npx --yes junit-to-ctrf $_.FullName --output .\${{ inputs.ctrfFolder }}\$($_.BaseName).json --tool Pester --env 'Windows ${{ inputs.purpose }} ${{ inputs.tagSet }}' + } + shell: powershell + + # this task only takes / as directory separators + - name: Publish Test Report + uses: ctrf-io/github-test-reporter@v1 + with: + report-path: './${{ inputs.ctrfFolder }}/*.json' + exit-on-fail: true + summary-report: true + test-report: false + test-list-report: false + failed-report: false + fail-rate-report: false + flaky-report: false + flaky-rate-report: false + failed-folded-report: true + previous-results-report: false + ai-report: true + skipped-report: false + suite-folded-report: false + suite-list-report: false + pull-request-report: false + commit-report: false + custom-report: false + + if: always() + + - name: Upload testResults artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: junit-pester-${{ inputs.purpose }}-${{ inputs.tagSet }} + path: ${{ runner.workspace }}\testResults + + - name: Upload ctrf artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: ctrf-pester-${{ inputs.purpose }}-${{ inputs.tagSet }} + path: ${{ inputs.ctrfFolder }} diff --git a/.github/workflows/AssignPrs.yml b/.github/workflows/AssignPrs.yml index 419d704ce1d..d398cd7cffe 100644 --- a/.github/workflows/AssignPrs.yml +++ b/.github/workflows/AssignPrs.yml @@ -1,6 +1,6 @@ name: Auto Assign PR Maintainer on: - pull_request: + issues: types: [opened, edited] permissions: contents: read @@ -13,6 +13,7 @@ jobs: pull-requests: write steps: - uses: wow-actions/auto-assign@67fafa03df61d7e5f201734a2fa60d1ab111880d # v3.0.2 + if: github.event.issue.pull_request with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # using the `org/team_slug` or `/team_slug` syntax to add git team as reviewers diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml deleted file mode 100644 index df5b4789fb3..00000000000 --- a/.github/workflows/rebase.yml +++ /dev/null @@ -1,39 +0,0 @@ -# This cannot rebase workflow changes into a PR -# It also only works if the GITHUB_TOKEN has permission to push to the branch -# see: https://github.com/cirrus-actions/rebase/issues/12#issuecomment-632594995 -on: - issue_comment: - types: [created] -name: Automatic Rebase -permissions: - contents: read - -jobs: - rebase: - permissions: - contents: write # for cirrus-actions/rebase to push code to rebase - pull-requests: write # for actions/github-script to create PR comment - name: Rebase - if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') - runs-on: ubuntu-latest - steps: - - name: Checkout the latest code - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - with: - fetch-depth: 0 - - name: Post rebase started comment to pull request - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - continue-on-error: true - with: - script: | - const backport_start_body = `Started rebase: https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${process.env.GITHUB_RUN_ID}`; - await github.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: backport_start_body - }); - - name: Automatic Rebase - uses: cirrus-actions/rebase@b87d48154a87a85666003575337e27b8cd65f691 # 1.8 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml new file mode 100644 index 00000000000..010c775ee53 --- /dev/null +++ b/.github/workflows/windows-ci.yml @@ -0,0 +1,124 @@ +name: Windows-CI +on: + workflow_dispatch: + push: + branches: + - master + - release/** + - feature* + paths: + - "*" + - "!.vsts-ci/misc-analysis.yml" + - "!.github/ISSUE_TEMPLATE/*" + - "!.github/workflows/*" + - "!.dependabot/config.yml" + - "!test/perf/*" + - "!.pipelines/*" + pull_request: + branches: + - master + - release/** + - feature* + paths: + - ".vsts-ci/templates/*" + - ".vsts-ci/windows.yml" + - "*.props" + - build.psm1 + - src/* + - test/* + - tools/buildCommon/* + - tools/ci.psm1 + - tools/WindowsCI.psm1 + - "!test/common/markdown/*" + - "!test/perf/*" +permissions: + contents: read + +run-name: "${{ github.ref_name }} - ${{ github.run_number }}" + +env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" + NugetSecurityAnalysisWarningLevel: none + POWERSHELL_TELEMETRY_OPTOUT: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none +jobs: + ci_build: + name: Build PowerShell + runs-on: windows-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Build + uses: "./.github/actions/build/ci" + windows_test: + name: Windows Unelevated CI + needs: ci_build + runs-on: windows-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Windows Unelevated CI + uses: "./.github/actions/test/windows" + with: + purpose: UnelevatedPesterTests + tagSet: CI + windows_test_2: + name: Windows Elevated CI + needs: ci_build + runs-on: windows-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Windows Elevated CI + uses: "./.github/actions/test/windows" + with: + purpose: ElevatedPesterTests + tagSet: CI + windows_test_3: + name: Windows Unelevated Others + needs: ci_build + runs-on: windows-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Windows Unelevated Others + uses: "./.github/actions/test/windows" + with: + purpose: UnelevatedPesterTests + tagSet: Others + windows_test_4: + name: Windows Elevated Others + needs: ci_build + runs-on: windows-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Windows Elevated Others + uses: "./.github/actions/test/windows" + with: + purpose: ElevatedPesterTests + tagSet: Others + verify_xunit: + name: Verify xUnit test results + needs: ci_build + runs-on: windows-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Verify xUnit test results + uses: "./.github/actions/test/verify_xunit" diff --git a/.gitignore b/.gitignore index cb12a297984..ccadde27182 100644 --- a/.gitignore +++ b/.gitignore @@ -111,3 +111,10 @@ msbuild.binlog # Ignore gzip files in the manpage folder assets/manpage/*.gz + +# Ignore files and folders generated by some gh cli extensions +tmp/* +.env.local + +# Ignore CTRF report files +crtf/* diff --git a/build.psm1 b/build.psm1 index e21194c9af9..e05b5639af1 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1758,6 +1758,16 @@ function Publish-TestResults $resolvedPath = (Resolve-Path -Path $Path).ProviderPath Write-Host "##vso[artifact.upload containerfolder=testResults;artifactname=testResults]$resolvedPath" + } elseif ($env:GITHUB_WORKFLOW -and $env:RUNNER_WORKSPACE) { + # In GitHub Actions + $destinationPath = Join-Path -Path $env:RUNNER_WORKSPACE -ChildPath 'testResults' + + # Create the folder if it does not exist + if (!(Test-Path -Path $destinationPath)) { + $null = New-Item -ItemType Directory -Path $destinationPath -Force + } + + Copy-Item -Path $Path -Destination $destinationPath -Force -Verbose } } diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 6628d54e043..7dda90f14f3 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -17,8 +17,15 @@ if(Test-Path $dotNetPath) # import build into the global scope so it can be used by packaging # argumentList $true says ignore tha we may not be able to build -Import-Module (Join-Path $repoRoot 'build.psm1') -Verbose -Scope Global -ArgumentList $true -Import-Module (Join-Path $repoRoot 'tools\packaging') -Verbose -Scope Global +Write-Verbose "Importing build.psm1" -Verbose +Import-Module (Join-Path $repoRoot 'build.psm1') -Scope Global -ArgumentList $true +$buildCommands = Get-Command -Module build +Write-Verbose "Imported build.psm1 commands: $($buildCommands.Count)" -Verbose + +Write-Verbose "Importing packaging.psm1" -Verbose +Import-Module (Join-Path $repoRoot 'tools\packaging') -Scope Global +$packagingCommands = Get-Command -Module packaging +Write-Verbose "Imported packaging.psm1 commands: $($packagingCommands.Count)" -Verbose # import the windows specific functcion only in Windows PowerShell or on Windows if($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) @@ -224,9 +231,12 @@ function Invoke-CITest [string] $Purpose, [ValidateSet('CI', 'Others')] [string] $TagSet, - [string] $TitlePrefix + [string] $TitlePrefix, + [string] $OutputFormat = "NUnitXml" ) + Write-Verbose -Verbose "CI test: OutputFormat: $OutputFormat" + # Set locale correctly for Linux CIs Set-CorrectLocale @@ -281,12 +291,14 @@ function Invoke-CITest Terse = $true Tag = @() ExcludeTag = $ExcludeTag + 'RequireAdminOnWindows' + OutputFormat = $OutputFormat } $title = "Pester Unelevated - $TagSet" if ($TitlePrefix) { $title = "$TitlePrefix - $title" } + Write-Verbose -Verbose "Starting Pester with output format $($arguments.OutputFormat)" Start-PSPester @arguments -Title $title # Fail the build, if tests failed @@ -314,7 +326,10 @@ function Invoke-CITest if ($TitlePrefix) { $title = "$TitlePrefix - $title" } - Start-PSPester @arguments -Title $title + + # We just built the test tools, we don't need to rebuild them + Write-Verbose -Verbose "Starting Pester with output format $($arguments.OutputFormat)" + Start-PSPester @arguments -Title $title -SkipTestToolBuild # Fail the build, if tests failed Test-PSPesterResults -TestResultsFile $expFeatureTestResultFile @@ -328,12 +343,15 @@ function Invoke-CITest OutputFile = $testResultsAdminFile Tag = @('RequireAdminOnWindows') ExcludeTag = $ExcludeTag + OutputFormat = $OutputFormat } $title = "Pester Elevated - $TagSet" if ($TitlePrefix) { $title = "$TitlePrefix - $title" } + + Write-Verbose -Verbose "Starting Pester with output format $($arguments.OutputFormat)" Start-PSPester @arguments -Title $title # Fail the build, if tests failed @@ -364,6 +382,8 @@ function Invoke-CITest if ($TitlePrefix) { $title = "$TitlePrefix - $title" } + + Write-Verbose -Verbose "Starting Pester with output format $($arguments.OutputFormat)" Start-PSPester @arguments -Title $title # Fail the build, if tests failed @@ -437,6 +457,18 @@ function Push-Artifact if ($env:TF_BUILD) { # In Azure DevOps Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName;]$Path" + } elseif ($env:GITHUB_WORKFLOW -and $env:RUNNER_WORKSPACE) { + # In GitHub Actions + $destinationPath = Join-Path -Path $env:RUNNER_WORKSPACE -ChildPath $artifactName + + # Create the folder if it does not exist + if (!(Test-Path -Path $destinationPath)) { + $null = New-Item -ItemType Directory -Path $destinationPath -Force + } + + Copy-Item -Path $Path -Destination $destinationPath -Force -Verbose + } else { + Write-Warning "Push-Artifact is not supported in this environment." } } From 5492f07de0396d84e0ded369e36572a2c11df64e Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 5 Feb 2025 11:32:01 -0800 Subject: [PATCH 073/275] [release/v7.5]Convert powershell/PowerShell-CI-linux to GitHub Actions (#24946) --- .../actions/test/linux-packaging/action.yml | 95 ++++++++++++ .github/actions/test/nix/action.yml | 91 +++++++++++ .../test/process-pester-results/action.yml | 64 ++++++++ .github/actions/test/windows/action.yml | 49 +----- .github/workflows/linux-ci.yml | 141 ++++++++++++++++++ .github/workflows/windows-ci.yml | 25 ++-- tools/ci.psm1 | 28 ++-- 7 files changed, 425 insertions(+), 68 deletions(-) create mode 100644 .github/actions/test/linux-packaging/action.yml create mode 100644 .github/actions/test/nix/action.yml create mode 100644 .github/actions/test/process-pester-results/action.yml create mode 100644 .github/workflows/linux-ci.yml diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml new file mode 100644 index 00000000000..61d23742056 --- /dev/null +++ b/.github/actions/test/linux-packaging/action.yml @@ -0,0 +1,95 @@ +name: linux_packaging +description: 'Test very basic Linux packaging' + +# This isn't working yet +# It fails with + +# ERROR: While executing gem ... (Gem::FilePermissionError) +# You don't have write permissions for the /var/lib/gems/2.7.0 directory. +# WARNING: Installation of gem dotenv 2.8.1 failed! Must resolve manually. + +runs: + using: composite + steps: + - name: Capture Environment + if: success() || failure() + run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' + shell: pwsh + - name: Download Build Artifacts + uses: actions/download-artifact@v4 + with: + path: "${{ github.workspace }}" + - name: Capture Artifacts Directory + continue-on-error: true + run: Get-ChildItem "${{ github.workspace }}/build/*" -Recurse + shell: pwsh + + - name: Bootstrap + run: |- + Import-Module ./build.psm1 + Start-PSBootstrap -Package + shell: pwsh + - name: Capture Artifacts Directory + continue-on-error: true + run: Import-Module ./build.psm1 + shell: pwsh + - name: Extract Files + uses: actions/github-script@v7.0.0 + env: + DESTINATION_FOLDER: "${{ github.workspace }}/bins" + ARCHIVE_FILE_PATTERNS: "${{ github.workspace }}/build/build.zip" + with: + script: |- + const fs = require('fs').promises + const path = require('path') + const target = path.resolve(process.env.DESTINATION_FOLDER) + const patterns = process.env.ARCHIVE_FILE_PATTERNS + const globber = await glob.create(patterns) + await io.mkdirP(path.dirname(target)) + for await (const file of globber.globGenerator()) { + if ((await fs.lstat(file)).isDirectory()) continue + await exec.exec(`7z x ${file} -o${target} -aoa`) + } + - name: Fix permissions + continue-on-error: true + run: |- + find "${{ github.workspace }}/bins" -type d -exec chmod +rwx {} \; + find "${{ github.workspace }}/bins" -type f -exec chmod +rw {} \; + shell: bash + - name: Capture Extracted Build ZIP + continue-on-error: true + run: Get-ChildItem "${{ github.workspace }}/bins/*" -Recurse -ErrorAction SilentlyContinue + shell: pwsh + - name: Packaging Tests + if: success() + run: |- + Import-Module ./tools/ci.psm1 + Restore-PSOptions -PSOptionsPath '${{ github.workspace }}/build/psoptions.json' + $options = (Get-PSOptions) + $rootPath = '${{ github.workspace }}/bins' + $originalRootPath = Split-Path -path $options.Output + $path = Join-Path -path $rootPath -ChildPath (split-path -leaf -path $originalRootPath) + $pwshPath = Join-Path -path $path -ChildPath 'pwsh' + chmod a+x $pwshPath + $options.Output = $pwshPath + Set-PSOptions $options + Invoke-CIFinish + shell: pwsh + - name: Upload packages + run: |- + Get-ChildItem "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}/*.deb" -Recurse | ForEach-Object { + $packagePath = $_.FullName + Write-Host "Uploading $packagePath" + Write-Host "##vso[artifact.upload containerfolder=deb;artifactname=deb]$packagePath" + } + Get-ChildItem "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}/*.rpm" -Recurse | ForEach-Object { + $packagePath = $_.FullName + Write-Host "Uploading $packagePath" + Write-Host "##vso[artifact.upload containerfolder=rpm;artifactname=rpm]$packagePath" + } + Get-ChildItem "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}/*.tar.gz" -Recurse | ForEach-Object { + $packagePath = $_.FullName + Write-Host "Uploading $packagePath" + Write-Host "##vso[artifact.upload containerfolder=rpm;artifactname=rpm]$packagePath" + } + shell: pwsh diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml new file mode 100644 index 00000000000..97575b6b54d --- /dev/null +++ b/.github/actions/test/nix/action.yml @@ -0,0 +1,91 @@ +name: nix_test +description: 'Test PowerShell on non-Windows platforms' + +inputs: + purpose: + required: false + default: '' + type: string + tagSet: + required: false + default: CI + type: string + ctrfFolder: + required: false + default: ctrf + type: string + +runs: + using: composite + steps: + - name: Capture Environment + if: success() || failure() + run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' + shell: pwsh + - name: Download Build Artifacts + uses: actions/download-artifact@v4 + with: + path: "${{ github.workspace }}" + - name: Capture Artifacts Directory + continue-on-error: true + run: Get-ChildItem "${{ github.workspace }}/build/*" -Recurse + shell: pwsh + + - name: Bootstrap + shell: pwsh + run: |- + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + + - name: Extract Files + uses: actions/github-script@v7.0.0 + env: + DESTINATION_FOLDER: "${{ github.workspace }}/bins" + ARCHIVE_FILE_PATTERNS: "${{ github.workspace }}/build/build.zip" + with: + script: |- + const fs = require('fs').promises + const path = require('path') + const target = path.resolve(process.env.DESTINATION_FOLDER) + const patterns = process.env.ARCHIVE_FILE_PATTERNS + const globber = await glob.create(patterns) + await io.mkdirP(path.dirname(target)) + for await (const file of globber.globGenerator()) { + if ((await fs.lstat(file)).isDirectory()) continue + await exec.exec(`7z x ${file} -o${target} -aoa`) + } + + - name: Fix permissions + continue-on-error: true + run: |- + find "${{ github.workspace }}/bins" -type d -exec chmod +rwx {} \; + find "${{ github.workspace }}/bins" -type f -exec chmod +rw {} \; + shell: bash + + - name: Capture Extracted Build ZIP + continue-on-error: true + run: Get-ChildItem "${{ github.workspace }}/bins/*" -Recurse -ErrorAction SilentlyContinue + shell: pwsh + + - name: Test + if: success() + run: |- + Import-Module ./tools/ci.psm1 + Restore-PSOptions -PSOptionsPath '${{ github.workspace }}/build/psoptions.json' + $options = (Get-PSOptions) + $rootPath = '${{ github.workspace }}/bins' + $originalRootPath = Split-Path -path $options.Output + $path = Join-Path -path $rootPath -ChildPath (split-path -leaf -path $originalRootPath) + $pwshPath = Join-Path -path $path -ChildPath 'pwsh' + chmod a+x $pwshPath + $options.Output = $pwshPath + Set-PSOptions $options + Invoke-CITest -Purpose '${{ inputs.purpose }}' -TagSet '${{ inputs.tagSet }}' -TitlePrefix '${{ inputs.buildName }}' -OutputFormat JUnitXml + shell: pwsh + + - name: Convert, Publish, and Upload Pester Test Results + uses: "./.github/actions/test/process-pester-results" + with: + name: "${{ inputs.purpose }}-${{ inputs.tagSet }}" + testResultsFolder: "${{ runner.workspace }}/testResults" + ctrfFolder: "${{ inputs.ctrfFolder }}" diff --git a/.github/actions/test/process-pester-results/action.yml b/.github/actions/test/process-pester-results/action.yml new file mode 100644 index 00000000000..758bbdfc353 --- /dev/null +++ b/.github/actions/test/process-pester-results/action.yml @@ -0,0 +1,64 @@ +name: process-pester-test-results +description: 'Process Pester test results' + +inputs: + name: + required: true + default: '' + type: string + testResultsFolder: + required: false + default: "${{ runner.workspace }}/testResults" + type: string + ctrfFolder: + required: false + default: ctrf + type: string + +runs: + using: composite + steps: + - name: Convert JUnit to CTRF + run: |- + Get-ChildItem -Path "${{ inputs.testResultsFolder }}/*.xml" -Recurse | ForEach-Object { + npx --yes junit-to-ctrf $_.FullName --output ./${{ inputs.ctrfFolder }}/$($_.BaseName).json --tool Pester + } + shell: pwsh + + # this task only takes / as directory separators + - name: Publish Test Report + uses: ctrf-io/github-test-reporter@v1 + with: + report-path: './${{ inputs.ctrfFolder }}/*.json' + exit-on-fail: true + summary-report: true + test-report: false + test-list-report: false + failed-report: false + fail-rate-report: false + flaky-report: false + flaky-rate-report: false + failed-folded-report: true + previous-results-report: false + ai-report: true + skipped-report: false + suite-folded-report: false + suite-list-report: false + pull-request-report: false + commit-report: false + custom-report: false + if: always() + + - name: Upload testResults artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: junit-pester-${{ inputs.name }} + path: ${{ runner.workspace }}/testResults + + - name: Upload ctrf artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: ctrf-pester-${{ inputs.name }} + path: ${{ inputs.ctrfFolder }} diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index 6cb5cbc1d74..c8e1c86024a 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -60,48 +60,9 @@ runs: Invoke-CITest -Purpose '${{ inputs.purpose }}' -TagSet '${{ inputs.tagSet }}' -OutputFormat JUnitXml shell: pwsh - - name: Convert JUnit to CTRF - run: |- - Get-ChildItem -Path "${{ runner.workspace }}/testResults/*.xml" -Recurse | ForEach-Object { - npx --yes junit-to-ctrf $_.FullName --output .\${{ inputs.ctrfFolder }}\$($_.BaseName).json --tool Pester --env 'Windows ${{ inputs.purpose }} ${{ inputs.tagSet }}' - } - shell: powershell - - # this task only takes / as directory separators - - name: Publish Test Report - uses: ctrf-io/github-test-reporter@v1 - with: - report-path: './${{ inputs.ctrfFolder }}/*.json' - exit-on-fail: true - summary-report: true - test-report: false - test-list-report: false - failed-report: false - fail-rate-report: false - flaky-report: false - flaky-rate-report: false - failed-folded-report: true - previous-results-report: false - ai-report: true - skipped-report: false - suite-folded-report: false - suite-list-report: false - pull-request-report: false - commit-report: false - custom-report: false - - if: always() - - - name: Upload testResults artifact - if: always() - uses: actions/upload-artifact@v4 - with: - name: junit-pester-${{ inputs.purpose }}-${{ inputs.tagSet }} - path: ${{ runner.workspace }}\testResults - - - name: Upload ctrf artifact - if: always() - uses: actions/upload-artifact@v4 + - name: Convert, Publish, and Upload Pester Test Results + uses: "./.github/actions/test/process-pester-results" with: - name: ctrf-pester-${{ inputs.purpose }}-${{ inputs.tagSet }} - path: ${{ inputs.ctrfFolder }} + name: "${{ inputs.purpose }}-${{ inputs.tagSet }}" + testResultsFolder: ${{ runner.workspace }}\testResults + ctrfFolder: "${{ inputs.ctrfFolder }}" diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml new file mode 100644 index 00000000000..8bb61c2c541 --- /dev/null +++ b/.github/workflows/linux-ci.yml @@ -0,0 +1,141 @@ +name: Linux-CI + +run-name: "${{ github.ref_name }} - ${{ github.run_number }}" + +on: + workflow_dispatch: + + push: + branches: + - master + - release* + - feature* + paths: + - "**" + - "!.github/ISSUE_TEMPLATE/**" + - "!.dependabot/config.yml" + - "!.pipelines/**" + - "!test/perf/**" + pull_request: + branches: + - master + - release/** + - feature* + paths: + - ".github/actions/**" + - ".github/workflows/linux-ci.yml" + - "**.props" + - build.psm1 + - src/** + - test/** + - tools/buildCommon/** + - tools/ci.psm1 + - tools/WindowsCI.psm1 + - "!test/common/markdown/**" + - "!test/perf/**" +env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + FORCE_FEATURE: 'False' + FORCE_PACKAGE: 'False' + NUGET_KEY: none + POWERSHELL_TELEMETRY_OPTOUT: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + system_debug: 'false' +jobs: + ci_build: + name: Build PowerShell + runs-on: ubuntu-20.04 + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Build + uses: "./.github/actions/build/ci" + linux_test_unelevated_ci: + name: Linux Unelevated CI + needs: ci_build + runs-on: ubuntu-20.04 + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Linux Unelevated CI + uses: "./.github/actions/test/nix" + with: + purpose: UnelevatedPesterTests + tagSet: CI + linux_test_elevated_ci: + name: Linux Elevated CI + needs: ci_build + runs-on: ubuntu-20.04 + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Linux Elevated CI + uses: "./.github/actions/test/nix" + with: + purpose: ElevatedPesterTests + tagSet: CI + linux_test_unelevated_others: + name: Linux Unelevated Others + needs: ci_build + runs-on: ubuntu-20.04 + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Linux Unelevated Others + uses: "./.github/actions/test/nix" + with: + purpose: UnelevatedPesterTests + tagSet: Others + linux_test_elevated_others: + name: Linux Elevated Others + needs: ci_build + runs-on: ubuntu-20.04 + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Linux Elevated Others + uses: "./.github/actions/test/nix" + with: + purpose: ElevatedPesterTests + tagSet: Others + verify_xunit: + name: Verify xUnit test results + needs: ci_build + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Verify xUnit test results + uses: "./.github/actions/test/verify_xunit" + + # TODO: Enable this when we have a Linux packaging workflow + + # ERROR: While executing gem ... (Gem::FilePermissionError) + # You don't have write permissions for the /var/lib/gems/2.7.0 directory. + # WARNING: Installation of gem dotenv 2.8.1 failed! Must resolve manually. + + # linux_packaging: + # name: Attempt Linux Packaging + # needs: ci_build + # runs-on: ubuntu-20.04 + # steps: + # - name: checkout + # uses: actions/checkout@v4.1.0 + # with: + # fetch-depth: 1000 + # - name: Verify xUnit test results + # uses: "./.github/actions/test/linux-packaging" diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 010c775ee53..958ee26b6d4 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -7,30 +7,29 @@ on: - release/** - feature* paths: - - "*" + - "**" - "!.vsts-ci/misc-analysis.yml" - - "!.github/ISSUE_TEMPLATE/*" - - "!.github/workflows/*" + - "!.github/ISSUE_TEMPLATE/**" - "!.dependabot/config.yml" - - "!test/perf/*" - - "!.pipelines/*" + - "!test/perf/**" + - "!.pipelines/**" pull_request: branches: - master - release/** - feature* paths: - - ".vsts-ci/templates/*" - - ".vsts-ci/windows.yml" - - "*.props" + - ".github/actions/**" + - ".github/workflows/windows-ci.yml" + - "**.props" - build.psm1 - - src/* - - test/* - - tools/buildCommon/* + - src/** + - test/** + - tools/buildCommon/** - tools/ci.psm1 - tools/WindowsCI.psm1 - - "!test/common/markdown/*" - - "!test/perf/*" + - "!test/common/markdown/**" + - "!test/perf/**" permissions: contents: read diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 7dda90f14f3..f09d159b4c8 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -259,7 +259,7 @@ function Invoke-CITest if($IsLinux -or $IsMacOS) { - return Invoke-LinuxTestsCore -Purpose $Purpose -ExcludeTag $ExcludeTag -TagSet $TagSet -TitlePrefix $TitlePrefix + return Invoke-LinuxTestsCore -Purpose $Purpose -ExcludeTag $ExcludeTag -TagSet $TagSet -TitlePrefix $TitlePrefix -OutputFormat $OutputFormat } # CoreCLR @@ -384,7 +384,8 @@ function Invoke-CITest } Write-Verbose -Verbose "Starting Pester with output format $($arguments.OutputFormat)" - Start-PSPester @arguments -Title $title + # We just built the test tools, we don't need to rebuild them + Start-PSPester @arguments -Title $title -SkipTestToolBuild # Fail the build, if tests failed Test-PSPesterResults -TestResultsFile $expFeatureTestResultFile @@ -702,7 +703,8 @@ function Invoke-LinuxTestsCore [string] $Purpose = 'All', [string[]] $ExcludeTag = @('Slow', 'Feature', 'Scenario'), [string] $TagSet = 'CI', - [string] $TitlePrefix + [string] $TitlePrefix, + [string] $OutputFormat = "NUnitXml" ) $output = Split-Path -Parent (Get-PSOutput -Options (Get-PSOptions)) @@ -715,12 +717,13 @@ function Invoke-LinuxTestsCore $sudoResultsWithExpFeatures = $null $noSudoPesterParam = @{ - 'BinDir' = $output - 'PassThru' = $true - 'Terse' = $true - 'Tag' = @() - 'ExcludeTag' = $testExcludeTag - 'OutputFile' = $testResultsNoSudo + 'BinDir' = $output + 'PassThru' = $true + 'Terse' = $true + 'Tag' = @() + 'ExcludeTag' = $testExcludeTag + 'OutputFile' = $testResultsNoSudo + 'OutputFormat' = $OutputFormat } # Get the experimental feature names and the tests associated with them @@ -758,7 +761,7 @@ function Invoke-LinuxTestsCore if ($TitlePrefix) { $title = "$TitlePrefix - $title" } - $passThruResult = Start-PSPester @noSudoPesterParam -Title $title + $passThruResult = Start-PSPester @noSudoPesterParam -Title $title -SkipTestToolBuild $noSudoResultsWithExpFeatures += $passThruResult } @@ -773,6 +776,7 @@ function Invoke-LinuxTestsCore $sudoPesterParam['ExcludeTag'] = $ExcludeTag $sudoPesterParam['Sudo'] = $true $sudoPesterParam['OutputFile'] = $testResultsSudo + $sudoPesterParam['OutputFormat'] = $OutputFormat $title = "Pester Sudo - $TagSet" if ($TitlePrefix) { @@ -805,7 +809,9 @@ function Invoke-LinuxTestsCore if ($TitlePrefix) { $title = "$TitlePrefix - $title" } - $passThruResult = Start-PSPester @sudoPesterParam -Title $title + + # We just built the test tools for the main test run, we don't need to rebuild them + $passThruResult = Start-PSPester @sudoPesterParam -Title $title -SkipTestToolBuild $sudoResultsWithExpFeatures += $passThruResult } From 7103b6f58a51e20577c53a4713cc3ce6aff4e527 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 5 Feb 2025 13:57:27 -0800 Subject: [PATCH 074/275] [release/v7.5]Convert powershell/PowerShell-CI-macos to GitHub Actions (#24954) --- .github/workflows/codeql-analysis.yml | 69 ---------- .github/workflows/linux-ci.yml | 139 ++++++++++++++++--- .github/workflows/macos-ci.yml | 188 ++++++++++++++++++++++++++ .github/workflows/windows-ci.yml | 92 ++++++++++--- .vsts-ci/linux.yml | 87 ------------ 5 files changed, 381 insertions(+), 194 deletions(-) delete mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/macos-ci.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 37a76edfeef..00000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: "CodeQL" - -on: - push: - branches: [master] - pull_request: - # The branches below must be a subset of the branches above - branches: [master] - -defaults: - run: - shell: pwsh - -env: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 - -permissions: - contents: read - -jobs: - analyze: - permissions: - actions: read # for github/codeql-action/init to get workflow details - contents: read # for actions/checkout to fetch code - security-events: write # for github/codeql-action/analyze to upload SARIF results - name: Analyze - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - # Override automatic language detection by changing the below list - # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - language: ['csharp'] - # Learn more... - # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection - - steps: - - name: Checkout repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - with: - fetch-depth: '0' - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - - run: | - Get-ChildItem -Path env: - name: Capture Environment - - - run: | - Import-Module .\tools\ci.psm1 - Invoke-CIInstall -SkipUser - name: Bootstrap - - - run: | - Import-Module .\tools\ci.psm1 - Invoke-CIBuild - name: Build - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0 diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 8bb61c2c541..25437e70fc8 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -21,18 +21,12 @@ on: - master - release/** - feature* - paths: - - ".github/actions/**" - - ".github/workflows/linux-ci.yml" - - "**.props" - - build.psm1 - - src/** - - test/** - - tools/buildCommon/** - - tools/ci.psm1 - - tools/WindowsCI.psm1 - - "!test/common/markdown/**" - - "!test/perf/**" +# Path filters for PRs need to go into the changes job + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ contains(github.ref, 'merge')}} + env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 @@ -44,9 +38,37 @@ env: nugetMultiFeedWarnLevel: none system_debug: 'false' jobs: + changes: + name: Change Detection + runs-on: ubuntu-latest + # Required permissions + permissions: + pull-requests: read + # Set job outputs to values from filter step + outputs: + source: ${{ steps.filter.outputs.source }} + steps: + # For pull requests it's not necessary to checkout the code + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + source: + - ".github/actions/**" + - ".github/workflows/linux-ci.yml" + - "**.props" + - build.psm1 + - src/** + - test/** + - tools/buildCommon/** + - tools/ci.psm1 + - "!test/common/markdown/**" + - "!test/perf/**" ci_build: name: Build PowerShell runs-on: ubuntu-20.04 + needs: changes + if: ${{ needs.changes.outputs.source == 'true' }} steps: - name: checkout uses: actions/checkout@v4.1.0 @@ -56,7 +78,10 @@ jobs: uses: "./.github/actions/build/ci" linux_test_unelevated_ci: name: Linux Unelevated CI - needs: ci_build + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} runs-on: ubuntu-20.04 steps: - name: checkout @@ -70,7 +95,10 @@ jobs: tagSet: CI linux_test_elevated_ci: name: Linux Elevated CI - needs: ci_build + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} runs-on: ubuntu-20.04 steps: - name: checkout @@ -84,7 +112,10 @@ jobs: tagSet: CI linux_test_unelevated_others: name: Linux Unelevated Others - needs: ci_build + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} runs-on: ubuntu-20.04 steps: - name: checkout @@ -98,7 +129,10 @@ jobs: tagSet: Others linux_test_elevated_others: name: Linux Elevated Others - needs: ci_build + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} runs-on: ubuntu-20.04 steps: - name: checkout @@ -112,7 +146,10 @@ jobs: tagSet: Others verify_xunit: name: Verify xUnit test results - needs: ci_build + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -122,6 +159,74 @@ jobs: - name: Verify xUnit test results uses: "./.github/actions/test/verify_xunit" + analyze: + permissions: + actions: read # for github/codeql-action/init to get workflow details + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/analyze to upload SARIF results + name: Analyze + runs-on: ubuntu-latest + needs: changes + if: ${{ needs.changes.outputs.source == 'true' }} + + strategy: + fail-fast: false + matrix: + # Override automatic language detection by changing the below list + # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] + language: ['csharp'] + # Learn more... + # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection + + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: '0' + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + - run: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + name: Capture Environment + shell: pwsh + + - run: | + Import-Module .\tools\ci.psm1 + Invoke-CIInstall -SkipUser + name: Bootstrap + shell: pwsh + + - run: | + Import-Module .\tools\ci.psm1 + Invoke-CIBuild + name: Build + shell: pwsh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 + + ready_to_merge: + name: Linux ready to merge + needs: + - verify_xunit + - linux_test_elevated_ci + - linux_test_elevated_others + - linux_test_unelevated_ci + - linux_test_unelevated_others + - analyze + if: always() + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@master + with: + needs_context: ${{ toJson(needs) }} # TODO: Enable this when we have a Linux packaging workflow # ERROR: While executing gem ... (Gem::FilePermissionError) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml new file mode 100644 index 00000000000..5a497114b90 --- /dev/null +++ b/.github/workflows/macos-ci.yml @@ -0,0 +1,188 @@ +name: macOS-CI + +run-name: "${{ github.ref_name }} - ${{ github.run_number }}" + +on: + push: + branches: + - master + - release/** + - feature* + paths: + - "**" + - "!.github/ISSUE_TEMPLATE/**" + - "!.dependabot/config.yml" + - "!.pipelines/**" + - "!test/perf/**" + pull_request: + branches: + - master + - release/** + - feature* +# Path filters for PRs need to go into the changes job + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ contains(github.ref, 'merge')}} + +env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + FORCE_FEATURE: 'False' + FORCE_PACKAGE: 'False' + HOMEBREW_NO_ANALYTICS: 1 + NUGET_KEY: none + POWERSHELL_TELEMETRY_OPTOUT: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + system_debug: 'false' +jobs: + changes: + name: Change Detection + runs-on: ubuntu-latest + # Required permissions + permissions: + pull-requests: read + # Set job outputs to values from filter step + outputs: + source: ${{ steps.filter.outputs.source }} + steps: + # For pull requests it's not necessary to checkout the code + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + source: + - ".github/actions/**" + - ".github/workflows/macos-ci.yml" + - "**.props" + - build.psm1 + - src/** + - test/** + - tools/buildCommon/** + - tools/ci.psm1 + - "!test/common/markdown/**" + - "!test/perf/**" + ci_build: + name: Build PowerShell + runs-on: macos-latest + needs: changes + if: ${{ needs.changes.outputs.source == 'true' }} + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Build + uses: "./.github/actions/build/ci" + macos_test_unelevated_ci: + name: macos Unelevated CI + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} + runs-on: macos-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: macOS Unelevated CI + uses: "./.github/actions/test/nix" + with: + purpose: UnelevatedPesterTests + tagSet: CI + macos_test_elevated_ci: + name: macOS Elevated CI + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} + runs-on: macos-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: macOS Elevated CI + uses: "./.github/actions/test/nix" + with: + purpose: ElevatedPesterTests + tagSet: CI + macos_test_unelevated_others: + name: macOS Unelevated Others + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} + runs-on: macos-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: macOS Unelevated Others + uses: "./.github/actions/test/nix" + with: + purpose: UnelevatedPesterTests + tagSet: Others + macos_test_elevated_others: + name: macOS Elevated Others + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} + runs-on: macos-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: macOS Elevated Others + uses: "./.github/actions/test/nix" + with: + purpose: ElevatedPesterTests + tagSet: Others + verify_xunit: + name: Verify xUnit test results + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Verify xUnit test results + uses: "./.github/actions/test/verify_xunit" + PackageMac-macos_packaging: + name: macOS packaging (bootstrap only) + needs: + - changes + if: ${{ needs.changes.outputs.source == 'true' }} + runs-on: + - macos-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + - name: Bootstrap packaging + if: success() || failure() + run: |- + import-module ./build.psm1 + start-psbootstrap -package + shell: pwsh + ready_to_merge: + name: macos ready to merge + needs: + - verify_xunit + - PackageMac-macos_packaging + - macos_test_elevated_ci + - macos_test_elevated_others + - macos_test_unelevated_ci + - macos_test_unelevated_others + if: always() + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@master + with: + needs_context: ${{ toJson(needs) }} diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 958ee26b6d4..2801a4f2bdc 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -18,18 +18,12 @@ on: - master - release/** - feature* - paths: - - ".github/actions/**" - - ".github/workflows/windows-ci.yml" - - "**.props" - - build.psm1 - - src/** - - test/** - - tools/buildCommon/** - - tools/ci.psm1 - - tools/WindowsCI.psm1 - - "!test/common/markdown/**" - - "!test/perf/**" +# Path filters for PRs need to go into the changes job + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ contains(github.ref, 'merge')}} + permissions: contents: read @@ -44,8 +38,37 @@ env: __SuppressAnsiEscapeSequences: 1 nugetMultiFeedWarnLevel: none jobs: + changes: + name: Change Detection + runs-on: ubuntu-latest + # Required permissions + permissions: + pull-requests: read + # Set job outputs to values from filter step + outputs: + source: ${{ steps.filter.outputs.source }} + steps: + # For pull requests it's not necessary to checkout the code + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + source: + - ".github/actions/**" + - ".github/workflows/windows-ci.yml" + - "**.props" + - build.psm1 + - src/** + - test/** + - tools/buildCommon/** + - tools/ci.psm1 + - tools/WindowsCI.psm1 + - "!test/common/markdown/**" + - "!test/perf/**" ci_build: name: Build PowerShell + needs: changes + if: ${{ needs.changes.outputs.source == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -54,9 +77,12 @@ jobs: fetch-depth: 1000 - name: Build uses: "./.github/actions/build/ci" - windows_test: + windows_test_unelevated_ci: name: Windows Unelevated CI - needs: ci_build + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -68,9 +94,12 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: CI - windows_test_2: + windows_test_elevated_ci: name: Windows Elevated CI - needs: ci_build + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -82,9 +111,12 @@ jobs: with: purpose: ElevatedPesterTests tagSet: CI - windows_test_3: + windows_test_unelevated_others: name: Windows Unelevated Others - needs: ci_build + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -96,9 +128,12 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: Others - windows_test_4: + windows_test_elevated_others: name: Windows Elevated Others - needs: ci_build + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -112,7 +147,10 @@ jobs: tagSet: Others verify_xunit: name: Verify xUnit test results - needs: ci_build + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -121,3 +159,15 @@ jobs: fetch-depth: 1000 - name: Verify xUnit test results uses: "./.github/actions/test/verify_xunit" + ready_to_merge: + name: windows ready to merge + needs: + - verify_xunit + - windows_test_elevated_ci + - windows_test_elevated_others + - windows_test_unelevated_ci + - windows_test_unelevated_others + if: always() + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@master + with: + needs_context: ${{ toJson(needs) }} diff --git a/.vsts-ci/linux.yml b/.vsts-ci/linux.yml index c1a1fd5c0ab..b1bb74197a0 100644 --- a/.vsts-ci/linux.yml +++ b/.vsts-ci/linux.yml @@ -79,93 +79,6 @@ stages: jobName: linux_build displayName: linux Build -- stage: TestUbuntu - displayName: Test for Ubuntu - dependsOn: [BuildLinuxStage] - jobs: - - template: templates/nix-test.yml - parameters: - name: Ubuntu - pool: ubuntu-20.04 - purpose: UnelevatedPesterTests - tagSet: CI - - - template: templates/nix-test.yml - parameters: - name: Ubuntu - pool: ubuntu-20.04 - purpose: ElevatedPesterTests - tagSet: CI - - - template: templates/nix-test.yml - parameters: - name: Ubuntu - pool: ubuntu-20.04 - purpose: UnelevatedPesterTests - tagSet: Others - - - template: templates/nix-test.yml - parameters: - name: Ubuntu - pool: ubuntu-20.04 - purpose: ElevatedPesterTests - tagSet: Others - - - template: templates/verify-xunit.yml - parameters: - pool: ubuntu-20.04 - -- stage: TestContainer - displayName: Test in a container - dependsOn: [BuildLinuxStage] - jobs: - - job: getContainerJob - displayName: Choose a container - pool: - vmImage: ubuntu-20.04 - steps: - - checkout: self - clean: true - - - checkout: Docker - clean: true - - - pwsh: | - # Initialize container test stage - Import-Module ./PowerShell/tools/ci.psm1 - Invoke-InitializeContainerStage -ContainerPattern '${{ parameters.ContainerPattern }}' - name: getContainerTask - displayName: Initialize Container Stage - continueOnError: true - - - template: templates/test/nix-container-test.yml - parameters: - name: container - pool: ubuntu-20.04 - purpose: UnelevatedPesterTests - tagSet: CI - - - template: templates/test/nix-container-test.yml - parameters: - name: container - pool: ubuntu-20.04 - purpose: ElevatedPesterTests - tagSet: CI - - - template: templates/test/nix-container-test.yml - parameters: - name: container - pool: ubuntu-20.04 - purpose: UnelevatedPesterTests - tagSet: Others - - - template: templates/test/nix-container-test.yml - parameters: - name: container - pool: ubuntu-20.04 - purpose: ElevatedPesterTests - tagSet: Others - - stage: PackageLinux displayName: Package Linux dependsOn: ["BuildLinuxStage"] From caa937a1dc037f067b7545856fa1e38cc99b4b07 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 5 Feb 2025 14:57:50 -0800 Subject: [PATCH 075/275] [release/v7.5]Fix release branch filters (#24959) --- .github/workflows/linux-ci.yml | 4 +--- .github/workflows/macos-ci.yml | 2 -- .github/workflows/windows-ci.yml | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 25437e70fc8..2ab1d8adab5 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -8,8 +8,7 @@ on: push: branches: - master - - release* - - feature* + - release/** paths: - "**" - "!.github/ISSUE_TEMPLATE/**" @@ -20,7 +19,6 @@ on: branches: - master - release/** - - feature* # Path filters for PRs need to go into the changes job concurrency: diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 5a497114b90..47b4c73667a 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -7,7 +7,6 @@ on: branches: - master - release/** - - feature* paths: - "**" - "!.github/ISSUE_TEMPLATE/**" @@ -18,7 +17,6 @@ on: branches: - master - release/** - - feature* # Path filters for PRs need to go into the changes job concurrency: diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 2801a4f2bdc..b0f65c15bba 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -5,7 +5,6 @@ on: branches: - master - release/** - - feature* paths: - "**" - "!.vsts-ci/misc-analysis.yml" @@ -17,7 +16,6 @@ on: branches: - master - release/** - - feature* # Path filters for PRs need to go into the changes job concurrency: From 7be439282abcca43b59bf091a742469d32a90e0b Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 5 Feb 2025 15:09:25 -0800 Subject: [PATCH 076/275] [release/v7.5]Fix GitHub Action filter overmatching (#24958) --- .github/action-filters.yml | 23 +++++++++++++++++++ .github/workflows/linux-ci.yml | 37 +++++++++++++++++-------------- .github/workflows/macos-ci.yml | 37 +++++++++++++++++-------------- .github/workflows/windows-ci.yml | 38 ++++++++++++++++++-------------- 4 files changed, 86 insertions(+), 49 deletions(-) create mode 100644 .github/action-filters.yml diff --git a/.github/action-filters.yml b/.github/action-filters.yml new file mode 100644 index 00000000000..9a61bc1947b --- /dev/null +++ b/.github/action-filters.yml @@ -0,0 +1,23 @@ +github: &github + - .github/actions/** + - .github/workflows/**-ci.yml +tools: &tools + - tools/buildCommon/** + - tools/ci.psm1 +props: &props + - '**.props' +tests: &tests + - test/powershell/** + - test/tools/** + - test/xUnit/** +mainSource: &mainSource + - src/** +buildModule: &buildModule + - build.psm1 +source: + - *github + - *tools + - *props + - *buildModule + - *mainSource + - *tests diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 2ab1d8adab5..8f15e9a080d 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -46,22 +46,27 @@ jobs: outputs: source: ${{ steps.filter.outputs.source }} steps: - # For pull requests it's not necessary to checkout the code - - uses: dorny/paths-filter@v3 - id: filter - with: - filters: | - source: - - ".github/actions/**" - - ".github/workflows/linux-ci.yml" - - "**.props" - - build.psm1 - - src/** - - test/** - - tools/buildCommon/** - - tools/ci.psm1 - - "!test/common/markdown/**" - - "!test/perf/**" + - name: checkout + uses: actions/checkout@v4.1.0 + + # For pull requests it's not necessary to checkout the code + - uses: dorny/paths-filter@v3 + id: filter + with: + list-files: json + filters: .github/action-filters.yml + + - name: Capture outputs + run: | + "source: ${{ steps.filter.outputs.source }}" + "github: ${{ steps.filter.outputs.github }}" + "tools: ${{ steps.filter.outputs.tools }}" + "props: ${{ steps.filter.outputs.props }}" + "tests: ${{ steps.filter.outputs.tests }}" + "mainSource: ${{ steps.filter.outputs.mainSource }}" + "buildModule: ${{ steps.filter.outputs.buildModule }}" + shell: pwsh + ci_build: name: Build PowerShell runs-on: ubuntu-20.04 diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 47b4c73667a..fafb6140285 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -45,22 +45,27 @@ jobs: outputs: source: ${{ steps.filter.outputs.source }} steps: - # For pull requests it's not necessary to checkout the code - - uses: dorny/paths-filter@v3 - id: filter - with: - filters: | - source: - - ".github/actions/**" - - ".github/workflows/macos-ci.yml" - - "**.props" - - build.psm1 - - src/** - - test/** - - tools/buildCommon/** - - tools/ci.psm1 - - "!test/common/markdown/**" - - "!test/perf/**" + - name: checkout + uses: actions/checkout@v4.1.0 + + # For pull requests it's not necessary to checkout the code + - uses: dorny/paths-filter@v3 + id: filter + with: + list-files: json + filters: .github/action-filters.yml + + - name: Capture outputs + run: | + "source: ${{ steps.filter.outputs.source }}" + "github: ${{ steps.filter.outputs.github }}" + "tools: ${{ steps.filter.outputs.tools }}" + "props: ${{ steps.filter.outputs.props }}" + "tests: ${{ steps.filter.outputs.tests }}" + "mainSource: ${{ steps.filter.outputs.mainSource }}" + "buildModule: ${{ steps.filter.outputs.buildModule }}" + shell: pwsh + ci_build: name: Build PowerShell runs-on: macos-latest diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index b0f65c15bba..c93983a765f 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -46,23 +46,27 @@ jobs: outputs: source: ${{ steps.filter.outputs.source }} steps: - # For pull requests it's not necessary to checkout the code - - uses: dorny/paths-filter@v3 - id: filter - with: - filters: | - source: - - ".github/actions/**" - - ".github/workflows/windows-ci.yml" - - "**.props" - - build.psm1 - - src/** - - test/** - - tools/buildCommon/** - - tools/ci.psm1 - - tools/WindowsCI.psm1 - - "!test/common/markdown/**" - - "!test/perf/**" + - name: checkout + uses: actions/checkout@v4.1.0 + + # For pull requests it's not necessary to checkout the code + - uses: dorny/paths-filter@v3 + id: filter + with: + list-files: json + filters: .github/action-filters.yml + + - name: Capture outputs + run: | + "source: ${{ steps.filter.outputs.source }}" + "github: ${{ steps.filter.outputs.github }}" + "tools: ${{ steps.filter.outputs.tools }}" + "props: ${{ steps.filter.outputs.props }}" + "tests: ${{ steps.filter.outputs.tests }}" + "mainSource: ${{ steps.filter.outputs.mainSource }}" + "buildModule: ${{ steps.filter.outputs.buildModule }}" + shell: pwsh + ci_build: name: Build PowerShell needs: changes From d9edb3d9bee020e24dc72effaa6335eded69ed9e Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 11 Feb 2025 16:25:35 -0800 Subject: [PATCH 077/275] [release/v7.5] Update branch for release - Transitive - true - minor (#24994) Co-authored-by: Travis Plunk --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 6 +- ...soft.PowerShell.Commands.Management.csproj | 4 +- ...crosoft.PowerShell.Commands.Utility.csproj | 6 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 97 ++++++++-------- .../Microsoft.WSMan.Management.csproj | 4 +- .../System.Management.Automation.csproj | 24 ++-- .../BenchmarkDotNet.Extensions.csproj | 2 +- .../ResultsComparer/ResultsComparer.csproj | 2 +- ...soft.PowerShell.NamedPipeConnection.csproj | 26 ++--- test/tools/TestService/TestService.csproj | 94 ++++++++-------- test/tools/WebListener/WebListener.csproj | 6 +- tools/cgmanifest.json | 106 +++++++++--------- 15 files changed, 193 insertions(+), 190 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 644b79dcd7a..a019407c86a 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "9.0.102", + "sdkImageVersion": "9.0.200", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index ee2876ea570..58b8fbe1952 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.102" + "version": "9.0.200" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index d17d99b190d..7827aa70830 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,9 +7,11 @@ - + + + - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index a4cb9ad9dfb..645f15c9ab9 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index bc15337da1f..b439f40ee1a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -13,7 +13,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all
- + @@ -41,8 +41,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index bd8754bff4d..b5360a74c89 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 75492f49c6c..821d37e94ea 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -17,55 +17,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index c9d448a5091..d4705c002dc 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,11 +7,11 @@ - + - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index d0e81fddb6d..f93991c084c 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,25 +32,25 @@ - - - - - - + + + + + + - + - - - - + + + + - + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 427245af6d8..ece797fe296 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -13,7 +13,7 @@ - + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index f4874cfa6d7..0932ca2dd6b 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -13,7 +13,7 @@ - + diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index 8bf1139db7d..92ef8c82ce4 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -17,21 +17,21 @@ - + - - - - - - - + + + + + + + - - - - - + + + + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 68452edfdb5..f4224411514 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,56 +15,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 7117e235557..b0eb19f4e37 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,9 +7,9 @@ - - + + - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index bb4fd3edb1c..bf50f1488b7 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -115,7 +116,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "8.0.12" + "Version": "8.0.13" } }, "DevelopmentDependency": false @@ -185,7 +186,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -205,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -215,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -235,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -245,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -255,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -265,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -275,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -285,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -295,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -305,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -315,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -325,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -335,7 +336,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -345,7 +346,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -355,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -365,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -385,7 +386,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -395,7 +396,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -405,7 +406,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -465,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -485,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -495,7 +496,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -505,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -515,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -525,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -545,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.DiagnosticSource", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -555,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -565,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -575,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -585,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -595,7 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -605,7 +606,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -615,7 +616,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -625,7 +626,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -635,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -645,7 +646,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -675,7 +676,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -705,7 +706,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -725,7 +726,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -735,7 +736,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -745,7 +746,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -755,7 +756,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -825,7 +826,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -835,7 +836,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -845,7 +846,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -855,7 +856,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encoding.CodePages", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -865,7 +866,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encodings.Web", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -875,7 +876,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false @@ -895,11 +896,10 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.1" + "Version": "9.0.2" } }, "DevelopmentDependency": false } - ], - "$schema": "https://json.schemastore.org/component-detection-manifest.json" + ] } From 6a8705efc7db1a89671ff961e8ae5466f96e8e76 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Mon, 24 Mar 2025 13:19:34 -0500 Subject: [PATCH 078/275] [release/v7.5]Add GitHub Actions workflow to verify PR labels (#25159) Co-authored-by: Travis Plunk --- .github/workflows/labels.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/labels.yml diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml new file mode 100644 index 00000000000..794ef64b213 --- /dev/null +++ b/.github/workflows/labels.yml @@ -0,0 +1,31 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +name: Verify PR Labels + +on: + pull_request: + types: [opened, reopened, edited, labeled, unlabeled, synchronize] + +permissions: + contents: read + pull-requests: read + +jobs: + verify-labels: + if: github.repository_owner == 'PowerShell' + runs-on: ubuntu-latest + + steps: + - name: Check out the repository + uses: actions/checkout@v2 + + - name: Verify PR has label starting with 'cl-' + id: verify-labels + uses: actions/github-script@v6 + with: + script: | + const labels = context.payload.pull_request.labels.map(label => label.name.toLowerCase()); + if (!labels.some(label => label.startsWith('cl-'))) { + core.setFailed("Every PR must have at least one label starting with 'cl-'."); + } From 8cb9646d1a4097a5520254090b6bdb18f9bd0d50 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 24 Mar 2025 20:47:48 -0700 Subject: [PATCH 079/275] [release/v7.5] Update SDK to `9.0.201` (#25163) --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 8 +- ...soft.PowerShell.Commands.Management.csproj | 4 +- ...crosoft.PowerShell.Commands.Utility.csproj | 6 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 98 ++++++++-------- .../Microsoft.WSMan.Management.csproj | 4 +- src/Modules/PSGalleryModules.csproj | 2 +- .../System.Management.Automation.csproj | 24 ++-- .../BenchmarkDotNet.Extensions.csproj | 2 +- .../ResultsComparer/ResultsComparer.csproj | 2 +- ...soft.PowerShell.NamedPipeConnection.csproj | 24 ++-- test/tools/TestService/TestService.csproj | 94 ++++++++-------- test/tools/WebListener/WebListener.csproj | 6 +- tools/cgmanifest.json | 106 +++++++++--------- 16 files changed, 193 insertions(+), 193 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index a019407c86a..e0869f46def 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "9.0.200", + "sdkImageVersion": "9.0.201", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 58b8fbe1952..4667f91bae2 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.200" + "version": "9.0.201" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 7827aa70830..d8ab11d9740 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,11 +7,11 @@ - - - + + + - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 645f15c9ab9..5494c8fa316 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index b439f40ee1a..797849a7e40 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -13,7 +13,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + @@ -41,8 +41,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index b5360a74c89..21912472c59 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 821d37e94ea..549224f457d 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -17,55 +17,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index d4705c002dc..8c0f4165524 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,11 +7,11 @@ - + - + diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index 5f9f89a4563..cb799b441fc 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index f93991c084c..d0ed69efaaf 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,25 +32,25 @@ - - - - - - + + + + + + - + - - - - + + + + - + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index ece797fe296..8eb7c19141f 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -11,7 +11,7 @@ - + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 0932ca2dd6b..a7b60b6eb1b 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -11,7 +11,7 @@ - + diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index 92ef8c82ce4..d0aeab862f9 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -20,18 +20,18 @@ - - - - - - - + + + + + + + - - - - - + + + + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index f4224411514..65837bc7e48 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,56 +15,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index b0eb19f4e37..d2181a374d7 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,9 +7,9 @@ - - + + - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index bf50f1488b7..d73e68035dd 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -1,5 +1,4 @@ { - "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -116,7 +115,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "8.0.13" + "Version": "8.0.14" } }, "DevelopmentDependency": false @@ -186,7 +185,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -206,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -216,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -236,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -246,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -256,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -266,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -276,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -286,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -296,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -306,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -316,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -326,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -336,7 +335,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -346,7 +345,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -356,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -366,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -386,7 +385,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -396,7 +395,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -406,7 +405,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -466,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -486,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -496,7 +495,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -506,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -516,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -526,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -546,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.DiagnosticSource", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -556,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -566,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -576,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -586,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -596,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -606,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -616,7 +615,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -626,7 +625,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -636,7 +635,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -646,7 +645,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -676,7 +675,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -706,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -726,7 +725,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -736,7 +735,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -746,7 +745,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -756,7 +755,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -826,7 +825,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -836,7 +835,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -846,7 +845,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -856,7 +855,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encoding.CodePages", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -866,7 +865,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encodings.Web", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -876,7 +875,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false @@ -896,10 +895,11 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.2" + "Version": "9.0.3" } }, "DevelopmentDependency": false } - ] + ], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" } From aebf10e25521697198dcd0800b7ff2d710b549ae Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Tue, 25 Mar 2025 13:33:10 -0700 Subject: [PATCH 080/275] [release/v7.5]Cleanup old release pipelines (#25236) --- tools/releaseBuild/.gitignore | 1 - .../GenericLinuxFiles/PowerShellPackage.ps1 | 145 ---- .../PowerShellPackage.ps1 | 213 ------ .../dockerInstall.psm1 | 115 --- tools/releaseBuild/README.md | 55 -- .../AzArtifactFeed/PSGalleryToAzArtifacts.yml | 33 - tools/releaseBuild/azureDevOps/compliance.yml | 67 -- tools/releaseBuild/azureDevOps/diagram.puml | 107 --- tools/releaseBuild/azureDevOps/diagram.svg | 108 --- .../releaseBuild/azureDevOps/releaseBuild.yml | 379 ---------- .../azureDevOps/releasePipeline.yml | 673 ------------------ .../templates/SetVersionVariables.yml | 63 -- .../templates/checkAzureContainer.yml | 51 -- .../templates/cloneToOfficialPath.yml | 19 - .../azureDevOps/templates/compliance.yml | 124 ---- .../templates/compliance/apiscan.yml | 180 ----- .../templates/compliance/compliance.yml | 83 --- .../templates/compliance/generateNotice.yml | 90 --- .../templates/expand-compliance.yml | 12 - .../templates/global-tool-pkg-sbom.yml | 64 -- .../templates/insert-nuget-config-azfeed.yml | 8 - .../azureDevOps/templates/json.yml | 57 -- .../templates/linux-authenticode-sign.yml | 184 ----- .../azureDevOps/templates/linux-packaging.yml | 489 ------------- .../azureDevOps/templates/linux.yml | 313 -------- .../templates/mac-file-signing.yml | 121 ---- .../templates/mac-package-build.yml | 143 ---- .../templates/mac-package-signing.yml | 135 ---- .../azureDevOps/templates/mac.yml | 68 -- .../azureDevOps/templates/nuget-pkg-sbom.yml | 139 ---- .../azureDevOps/templates/nuget.yml | 290 -------- .../templates/release-BuildJson.yml | 102 --- .../templates/release-CopyGlobalTools.yml | 56 -- .../templates/release-CreateGitHubDraft.yml | 110 --- .../templates/release-GlobalToolTest.yml | 149 ---- .../templates/release-MakeContainerPublic.yml | 20 - .../templates/release-MsixBundle.yml | 81 --- .../release-PublishPackageMsftCom.yml | 57 -- .../templates/release-PublishSymbols.yml | 51 -- .../templates/release-ReleaseToNuGet.yml | 56 -- .../templates/release-SDKTests.yml | 148 ---- .../release-SetReleaseTagAndContainerName.yml | 26 - .../templates/release-UpdateDepsJson.yml | 71 -- .../templates/release-ValidateFxdPackage.yml | 92 --- .../templates/release-ValidatePackageBOM.yml | 49 -- .../release-ValidatePackageNames.yml | 93 --- .../templates/release/approvalJob.yml | 35 - .../azureDevOps/templates/shouldSign.yml | 29 - .../azureDevOps/templates/sign-build-file.yml | 328 --------- .../azureDevOps/templates/signBuildFiles.yml | 189 ----- .../azureDevOps/templates/step/finalize.yml | 5 - .../azureDevOps/templates/testartifacts.yml | 126 ---- .../templates/upload-final-results.yml | 17 - .../azureDevOps/templates/upload.yml | 83 --- .../azureDevOps/templates/vpackReleaseJob.yml | 113 --- .../windows-component-governance.yml | 71 -- .../templates/windows-hosted-build.yml | 84 --- .../templates/windows-package-signing.yml | 132 ---- .../templates/windows-packaging.yml | 369 ---------- .../releaseBuild/azureDevOps/vpackRelease.yml | 72 -- tools/releaseBuild/build.json | 336 --------- tools/releaseBuild/createComplianceFolder.ps1 | 59 -- tools/releaseBuild/generatePackgeSigning.ps1 | 112 --- .../macOS/PowerShellPackageVsts.ps1 | 143 ---- .../macOS/PowerShellPackageVsts.sh | 1 - tools/releaseBuild/macOS/createPowerShell.sh | 8 - tools/releaseBuild/packagesigning.xml | 6 - tools/releaseBuild/setReleaseTag.ps1 | 161 ----- tools/releaseBuild/setReleaseTag.sh | 1 - tools/releaseBuild/signing.xml | 49 -- tools/releaseBuild/updateSigning.ps1 | 46 -- tools/releaseBuild/vstsbuild.ps1 | 120 ---- tools/releaseBuild/vstsbuild.sh | 1 - 73 files changed, 8386 deletions(-) delete mode 100644 tools/releaseBuild/.gitignore delete mode 100644 tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1 delete mode 100644 tools/releaseBuild/Images/microsoft_powershell_windowsservercore/PowerShellPackage.ps1 delete mode 100644 tools/releaseBuild/Images/microsoft_powershell_windowsservercore/dockerInstall.psm1 delete mode 100644 tools/releaseBuild/README.md delete mode 100644 tools/releaseBuild/azureDevOps/AzArtifactFeed/PSGalleryToAzArtifacts.yml delete mode 100644 tools/releaseBuild/azureDevOps/compliance.yml delete mode 100644 tools/releaseBuild/azureDevOps/diagram.puml delete mode 100644 tools/releaseBuild/azureDevOps/diagram.svg delete mode 100644 tools/releaseBuild/azureDevOps/releaseBuild.yml delete mode 100644 tools/releaseBuild/azureDevOps/releasePipeline.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/SetVersionVariables.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/checkAzureContainer.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/cloneToOfficialPath.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/compliance.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/compliance/compliance.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/compliance/generateNotice.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/expand-compliance.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/global-tool-pkg-sbom.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/json.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/linux-authenticode-sign.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/linux-packaging.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/linux.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/mac-file-signing.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/mac-package-build.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/mac-package-signing.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/mac.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/nuget-pkg-sbom.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/nuget.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-BuildJson.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-CopyGlobalTools.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-CreateGitHubDraft.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-GlobalToolTest.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-MakeContainerPublic.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-MsixBundle.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-PublishPackageMsftCom.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-PublishSymbols.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-ReleaseToNuGet.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-SDKTests.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-SetReleaseTagAndContainerName.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-UpdateDepsJson.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-ValidateFxdPackage.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-ValidatePackageBOM.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release-ValidatePackageNames.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/release/approvalJob.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/shouldSign.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/sign-build-file.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/signBuildFiles.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/step/finalize.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/testartifacts.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/upload-final-results.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/upload.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/vpackReleaseJob.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/windows-component-governance.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/windows-hosted-build.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/windows-package-signing.yml delete mode 100644 tools/releaseBuild/azureDevOps/templates/windows-packaging.yml delete mode 100644 tools/releaseBuild/azureDevOps/vpackRelease.yml delete mode 100644 tools/releaseBuild/build.json delete mode 100644 tools/releaseBuild/createComplianceFolder.ps1 delete mode 100644 tools/releaseBuild/generatePackgeSigning.ps1 delete mode 100644 tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 delete mode 100644 tools/releaseBuild/macOS/PowerShellPackageVsts.sh delete mode 100644 tools/releaseBuild/macOS/createPowerShell.sh delete mode 100644 tools/releaseBuild/packagesigning.xml delete mode 100644 tools/releaseBuild/setReleaseTag.ps1 delete mode 100644 tools/releaseBuild/setReleaseTag.sh delete mode 100644 tools/releaseBuild/signing.xml delete mode 100644 tools/releaseBuild/updateSigning.ps1 delete mode 100644 tools/releaseBuild/vstsbuild.ps1 delete mode 100644 tools/releaseBuild/vstsbuild.sh diff --git a/tools/releaseBuild/.gitignore b/tools/releaseBuild/.gitignore deleted file mode 100644 index 0ff566888a7..00000000000 --- a/tools/releaseBuild/.gitignore +++ /dev/null @@ -1 +0,0 @@ -PSRelease/ diff --git a/tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1 b/tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1 deleted file mode 100644 index 2475dce7d89..00000000000 --- a/tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1 +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# PowerShell Script to build and package PowerShell from specified form and branch -# Script is intented to use in Docker containers -# Ensure PowerShell is available in the provided image - -param ( - [string] $location = "/powershell", - - # Destination location of the package on docker host - [string] $destination = '/mnt', - - [ValidatePattern("^v\d+\.\d+\.\d+(-\w+(\.\d{1,2})?)?$")] - [ValidateNotNullOrEmpty()] - [string]$ReleaseTag, - - [switch]$TarX64, - [switch]$TarArm, - [switch]$TarArm64, - [switch]$TarMinSize, - [switch]$FxDependent, - [switch]$Alpine -) - -$releaseTagParam = @{} -if ($ReleaseTag) -{ - $releaseTagParam = @{ 'ReleaseTag' = $ReleaseTag } -} - -#Remove the initial 'v' from the ReleaseTag -$version = $ReleaseTag -replace '^v' -$semVersion = [System.Management.Automation.SemanticVersion] $version - -$metadata = Get-Content "$location/tools/metadata.json" -Raw | ConvertFrom-Json - -$LTS = $metadata.LTSRelease.Package - -Write-Verbose -Verbose -Message "LTS is set to: $LTS" - -function BuildPackages { - param( - [switch] $LTS - ) - - Push-Location - try { - Set-Location $location - Import-Module "$location/build.psm1" - Import-Module "$location/tools/packaging" - - Start-PSBootstrap -Package -NoSudo - - $buildParams = @{ Configuration = 'Release'; PSModuleRestore = $true; Restore = $true } - - if ($FxDependent.IsPresent) { - $projectAssetsZipName = 'linuxFxDependantProjectAssetssymbols.zip' - $buildParams.Add("Runtime", "fxdependent") - } elseif ($Alpine.IsPresent) { - $projectAssetsZipName = 'linuxAlpineProjectAssetssymbols.zip' - $buildParams.Add("Runtime", 'musl-x64') - } else { - # make the artifact name unique - $projectAssetsZipName = "linuxProjectAssets-$((Get-Date).Ticks)-symbols.zip" - } - - Start-PSBuild @buildParams @releaseTagParam - $options = Get-PSOptions - - if ($FxDependent) { - Start-PSPackage -Type 'fxdependent' @releaseTagParam -LTS:$LTS - } elseif ($Alpine) { - Start-PSPackage -Type 'tar-alpine' @releaseTagParam -LTS:$LTS - } else { - Start-PSPackage @releaseTagParam -LTS:$LTS - } - - if ($TarX64) { Start-PSPackage -Type tar @releaseTagParam -LTS:$LTS } - - if ($TarMinSize) { - Write-Verbose -Verbose "---- Min-Size ----" - Write-Verbose -Verbose "options.Output: $($options.Output)" - Write-Verbose -Verbose "options.Top $($options.Top)" - - $binDir = Join-Path -Path $options.Top -ChildPath 'bin' - Write-Verbose -Verbose "Remove $binDir, to get a clean build for min-size package" - Remove-Item -Path $binDir -Recurse -Force - - ## Build 'min-size' and create 'tar.gz' package for it. - $buildParams['ForMinimalSize'] = $true - Start-PSBuild @buildParams @releaseTagParam - Start-PSPackage -Type min-size @releaseTagParam -LTS:$LTS - } - - if ($TarArm) { - ## Build 'linux-arm' and create 'tar.gz' package for it. - ## Note that 'linux-arm' can only be built on Ubuntu environment. - Start-PSBuild -Configuration Release -Restore -Runtime linux-arm -PSModuleRestore @releaseTagParam - Start-PSPackage -Type tar-arm @releaseTagParam -LTS:$LTS - } - - if ($TarArm64) { - Start-PSBuild -Configuration Release -Restore -Runtime linux-arm64 -PSModuleRestore @releaseTagParam - Start-PSPackage -Type tar-arm64 @releaseTagParam -LTS:$LTS - } - } finally { - Pop-Location - } -} - -BuildPackages - -if ($LTS) { - Write-Verbose -Verbose "Packaging LTS" - BuildPackages -LTS -} - -$linuxPackages = Get-ChildItem "$location/powershell*" -Include *.deb,*.rpm,*.tar.gz - -foreach ($linuxPackage in $linuxPackages) -{ - $filePath = $linuxPackage.FullName - Write-Verbose "Copying $filePath to $destination" -Verbose - Copy-Item -Path $filePath -Destination $destination -Force -} - -Write-Verbose "Exporting project.assets files ..." -Verbose - -$projectAssetsCounter = 1 -$projectAssetsFolder = Join-Path -Path $destination -ChildPath 'projectAssets' -$projectAssetsZip = Join-Path -Path $destination -ChildPath $projectAssetsZipName -Get-ChildItem $location\project.assets.json -Recurse | ForEach-Object { - $subfolder = $_.FullName.Replace($location,'') - $subfolder.Replace('project.assets.json','') - $itemDestination = Join-Path -Path $projectAssetsFolder -ChildPath $subfolder - New-Item -Path $itemDestination -ItemType Directory -Force - $file = $_.FullName - Write-Verbose "Copying $file to $itemDestination" -Verbose - Copy-Item -Path $file -Destination "$itemDestination\" -Force - $projectAssetsCounter++ -} - -Compress-Archive -Path $projectAssetsFolder -DestinationPath $projectAssetsZip -Remove-Item -Path $projectAssetsFolder -Recurse -Force -ErrorAction SilentlyContinue diff --git a/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/PowerShellPackage.ps1 b/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/PowerShellPackage.ps1 deleted file mode 100644 index 41ec53fa495..00000000000 --- a/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/PowerShellPackage.ps1 +++ /dev/null @@ -1,213 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -[cmdletbinding(DefaultParameterSetName='default')] -# PowerShell Script to clone, build and package PowerShell from specified fork and branch -param ( - [string] $fork = 'powershell', - - [string] $branch = 'master', - - [string] $location = "$PWD\powershell", - - [string] $destination = "$env:WORKSPACE", - - [ValidateSet("win7-x64", "win7-x86", "win-arm", "win-arm64", "fxdependent", "fxdependent-win-desktop")] - [string] $Runtime = 'win7-x64', - - [switch] $ForMinimalSize, - - [switch] $Wait, - - [ValidatePattern("^v\d+\.\d+\.\d+(-\w+(\.\d{1,2})?)?$")] - [ValidateNotNullOrEmpty()] - [string] $ReleaseTag, - - [Parameter(Mandatory,ParameterSetName='IncludeSymbols')] - [switch] $Symbols, - - [Parameter(Mandatory,ParameterSetName='packageSigned')] - [ValidatePattern("-signed.zip$")] - [string] $BuildZip, - - [Parameter(Mandatory,ParameterSetName='ComponentRegistration')] - [switch] $ComponentRegistration -) - -$releaseTagParam = @{} -if ($ReleaseTag) -{ - $releaseTagParam = @{ 'ReleaseTag' = $ReleaseTag } -} - -if (-not $env:homedrive) -{ - Write-Verbose "fixing empty home paths..." -Verbose - $profileParts = $env:userprofile -split ':' - $env:homedrive = $profileParts[0]+':' - $env:homepath = $profileParts[1] -} - -if (! (Test-Path $destination)) -{ - Write-Verbose "Creating destination $destination" -Verbose - $null = New-Item -Path $destination -ItemType Directory -} - -Write-Verbose "homedrive : ${env:homedrive}" -Write-Verbose "homepath : ${env:homepath}" - -# Don't use CIM_PhysicalMemory, docker containers may cache old values -$memoryMB = (Get-CimInstance win32_computersystem).TotalPhysicalMemory /1MB -$requiredMemoryMB = 2048 -if ($memoryMB -lt $requiredMemoryMB) -{ - throw "Building powershell requires at least $requiredMemoryMB MiB of memory and only $memoryMB MiB is present." -} -Write-Verbose "Running with $memoryMB MB memory." -Verbose - -try -{ - Set-Location $location - - Import-Module "$location\build.psm1" -Force - Import-Module "$location\tools\packaging" -Force - $env:platform = $null - - Write-Verbose "Sync'ing Tags..." -Verbose - Sync-PSTags -AddRemoteIfMissing - - Write-Verbose "Bootstrapping powershell build..." -Verbose - Start-PSBootstrap -Force -Package -ErrorAction Stop - - if ($PSCmdlet.ParameterSetName -eq 'packageSigned') - { - Write-Verbose "Expanding signed build..." -Verbose - if($Runtime -like 'fxdependent*') - { - Expand-PSSignedBuild -BuildZip $BuildZip -SkipPwshExeCheck - } - else - { - Expand-PSSignedBuild -BuildZip $BuildZip - } - - Remove-Item -Path $BuildZip - } - else - { - Write-Verbose "Starting powershell build for RID: $Runtime and ReleaseTag: $ReleaseTag ..." -Verbose - $buildParams = @{ - ForMinimalSize = $ForMinimalSize - } - - if($Symbols) - { - $buildParams['NoPSModuleRestore'] = $true - } - else - { - $buildParams['PSModuleRestore'] = $true - } - - Start-PSBuild -Clean -Runtime $Runtime -Configuration Release @releaseTagParam @buildParams - } - - if ($ComponentRegistration) - { - Write-Verbose "Exporting project.assets files ..." -Verbose - - $projectAssetsCounter = 1 - $projectAssetsFolder = Join-Path -Path $destination -ChildPath 'projectAssets' - $projectAssetsZip = Join-Path -Path $destination -ChildPath 'windowsProjectAssetssymbols.zip' - Get-ChildItem $location\project.assets.json -Recurse | ForEach-Object { - $subfolder = $_.FullName.Replace($location,'') - $subfolder.Replace('project.assets.json','') - $itemDestination = Join-Path -Path $projectAssetsFolder -ChildPath $subfolder - New-Item -Path $itemDestination -ItemType Directory -Force > $null - $file = $_.FullName - Write-Verbose "Copying $file to $itemDestination" -Verbose - Copy-Item -Path $file -Destination "$itemDestination\" -Force - $projectAssetsCounter++ - } - - Compress-Archive -Path $projectAssetsFolder -DestinationPath $projectAssetsZip - Remove-Item -Path $projectAssetsFolder -Recurse -Force -ErrorAction SilentlyContinue - - return - } - - if ($Runtime -like 'fxdependent*') - { - $pspackageParams = @{'Type' = $Runtime} - } - else - { - ## Set the default package type. - $pspackageParams = @{'Type' = 'msi'; 'WindowsRuntime' = $Runtime} - if ($ForMinimalSize) - { - ## Special case for the minimal size self-contained package. - $pspackageParams['Type'] = 'min-size' - } - } - - if (!$Symbols -and $Runtime -notlike 'fxdependent*' -and !$ForMinimalSize) - { - Write-Verbose "Starting powershell packaging(msi)..." -Verbose - Start-PSPackage @pspackageParams @releaseTagParam - - $pspackageParams['Type']='msix' - Write-Verbose "Starting powershell packaging(msix)..." -Verbose - Start-PSPackage @pspackageParams @releaseTagParam - } - - if ($Runtime -like 'fxdependent*' -or $ForMinimalSize) - { - ## Add symbols for just like zip package. - $pspackageParams['IncludeSymbols']=$Symbols - Start-PSPackage @pspackageParams @releaseTagParam - - ## Copy the fxdependent Zip package to destination. - Get-ChildItem $location\PowerShell-*.zip | ForEach-Object { - $file = $_.FullName - Write-Verbose "Copying $file to $destination" -Verbose - Copy-Item -Path $file -Destination "$destination\" -Force - } - } - else - { - if (!$Symbols) { - $pspackageParams['Type'] = 'zip-pdb' - Write-Verbose "Starting powershell symbols packaging(zip)..." -Verbose - Start-PSPackage @pspackageParams @releaseTagParam - } - - $pspackageParams['Type']='zip' - $pspackageParams['IncludeSymbols']=$Symbols - Write-Verbose "Starting powershell packaging(zip)..." -Verbose - Start-PSPackage @pspackageParams @releaseTagParam - - Write-Verbose "Exporting packages ..." -Verbose - - Get-ChildItem $location\*.msi,$location\*.zip,$location\*.wixpdb,$location\*.msix,$location\*.exe | ForEach-Object { - $file = $_.FullName - Write-Verbose "Copying $file to $destination" -Verbose - Copy-Item -Path $file -Destination "$destination\" -Force - } - } -} -finally -{ - Write-Verbose "Beginning build clean-up..." -Verbose - if ($Wait) - { - $path = Join-Path $PSScriptRoot -ChildPath 'delete-to-continue.txt' - $null = New-Item -Path $path -ItemType File - Write-Verbose "Computer name: $env:COMPUTERNAME" -Verbose - Write-Verbose "Delete $path to exit." -Verbose - while(Test-Path -LiteralPath $path) - { - Start-Sleep -Seconds 60 - } - } -} diff --git a/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/dockerInstall.psm1 b/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/dockerInstall.psm1 deleted file mode 100644 index 311fed7e169..00000000000 --- a/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/dockerInstall.psm1 +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -function Install-ChocolateyPackage -{ - param( - [Parameter(Mandatory=$true)] - [string] - $PackageName, - - [Parameter(Mandatory=$false)] - [string] - $Executable, - - [string[]] - $ArgumentList, - - [switch] - $Cleanup, - - [int] - $ExecutionTimeout = 2700, - - [string] - $Version - ) - - if(-not(Get-Command -Name Choco -ErrorAction SilentlyContinue)) - { - Write-Verbose "Installing Chocolatey provider..." -Verbose - Invoke-WebRequest https://chocolatey.org/install.ps1 -UseBasicParsing | Invoke-Expression - } - - Write-Verbose "Installing $PackageName..." -Verbose - $extraCommand = @() - if($Version) - { - $extraCommand += '--version', $version - } - choco install -y $PackageName --no-progress --execution-timeout=$ExecutionTimeout $ArgumentList $extraCommands - - if($executable) - { - Write-Verbose "Verifing $Executable is in path..." -Verbose - $exeSource = $null - $exeSource = Get-ChildItem -Path "$env:ProgramFiles\$Executable" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName - if(!$exeSource) - { - Write-Verbose "Falling back to x86 program files..." -Verbose - $exeSource = Get-ChildItem -Path "${env:ProgramFiles(x86)}\$Executable" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName - } - - # Don't search the chocolatey program data until more official locations have been searched - if(!$exeSource) - { - Write-Verbose "Falling back to chocolatey..." -Verbose - $exeSource = Get-ChildItem -Path "$env:ProgramData\chocolatey\$Executable" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName - } - - # all obvious locations are exhausted, use brute force and search from the root of the filesystem - if(!$exeSource) - { - Write-Verbose "Falling back to the root of the drive..." -Verbose - $exeSource = Get-ChildItem -Path "/$Executable" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName - } - - if(!$exeSource) - { - throw "$Executable not found" - } - - $exePath = Split-Path -Path $exeSource - Append-Path -path $exePath - } - - if($Cleanup.IsPresent) - { - Remove-Folder -Folder "$env:temp\chocolatey" - } -} - -function Append-Path -{ - param - ( - $path - ) - $machinePathString = [System.Environment]::GetEnvironmentVariable('path',[System.EnvironmentVariableTarget]::Machine) - $machinePath = $machinePathString -split ';' - - if($machinePath -inotcontains $path) - { - $newPath = "$machinePathString;$path" - Write-Verbose "Adding $path to path..." -Verbose - [System.Environment]::SetEnvironmentVariable('path',$newPath,[System.EnvironmentVariableTarget]::Machine) - Write-Verbose "Added $path to path." -Verbose - } - else - { - Write-Verbose "$path already in path." -Verbose - } -} - -function Remove-Folder -{ - param( - [string] - $Folder - ) - - Write-Verbose "Cleaning up $Folder..." -Verbose - $filter = Join-Path -Path $Folder -ChildPath * - [int]$measuredCleanupMB = (Get-ChildItem $filter -Recurse | Measure-Object -Property Length -Sum).Sum / 1MB - Remove-Item -Recurse -Force $filter -ErrorAction SilentlyContinue - Write-Verbose "Cleaned up $measuredCleanupMB MB from $Folder" -Verbose -} diff --git a/tools/releaseBuild/README.md b/tools/releaseBuild/README.md deleted file mode 100644 index 9b78e742b5f..00000000000 --- a/tools/releaseBuild/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Azure Dev Ops Release Builds - -## Requirements - -Docker must be installed to run any of the release builds. - -## Running Windows Release Builds Locally - -From PowerShell on Windows, run `.\vstsbuild.ps1 -ReleaseTag -Name `. - -For the package builds, run `.\vstsbuild.ps1 -ReleaseTag -Name -BuildPath -SignedFilesPath ` - -Windows Build Names: - -* `win7-x64-symbols` - * Builds the Windows x64 Zip with symbols -* `win7-x86-symbols` - * Builds the Windows x86 Zip with symbols -* `win7-arm-symbols` - * Builds the Windows ARM Zip with symbols -* `win7-arm64-symbols` - * Builds the Windows ARM64 Zip with symbols -* `win7-fxdependent-symbols` - * Builds the Windows FxDependent Zip with symbols -* `win7-x64-package` - * Builds the Windows x64 packages -* `win7-x86-package` - * Builds the Windows x86 packages -* `win7-arm-package` - * Builds the Windows ARM packages -* `win7-arm64-package` - * Builds the Windows ARM64 packages -* `win7-fxdependent-package` - * Builds the Windows FxDependent packages - -## Running Linux Release Builds Locally - -From PowerShell on Linux or macOS, run `.\vstsbuild.ps1 -ReleaseTag -Name `. - -Linux Build Names: - -* `deb` - * Builds the Debian Packages, ARM32 and ARM64. -* `alpine` - * Builds the Alpine Package -* `rpm` - * Builds the RedHat variant Package - -## Azure Dev Ops Build - -The release build is fairly complicated. The definition is at `./azureDevOps/releaseBuild.yml`. - -Here is a diagram of the build: - -[![Release Build diagram](https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/releaseBuild/azureDevOps/diagram.svg?sanitize=true)](https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/releaseBuild/azureDevOps/diagram.svg?sanitize=true) diff --git a/tools/releaseBuild/azureDevOps/AzArtifactFeed/PSGalleryToAzArtifacts.yml b/tools/releaseBuild/azureDevOps/AzArtifactFeed/PSGalleryToAzArtifacts.yml deleted file mode 100644 index da26ea6d348..00000000000 --- a/tools/releaseBuild/azureDevOps/AzArtifactFeed/PSGalleryToAzArtifacts.yml +++ /dev/null @@ -1,33 +0,0 @@ -# Sync packages from PSGallery to Azure DevOps Artifacts feed - -resources: -- repo: self - clean: true - -pool: - name: 1es - demands: - - ImageOverride -equals PSMMS2019-Minimal - -steps: - - pwsh: | - $minVer = [version]"2.2.3" - $curVer = Get-Module PowerShellGet -ListAvailable | Select-Object -First 1 | ForEach-Object Version - if (-not $curVer -or $curVer -lt $minVer) { - Install-Module -Name PowerShellGet -MinimumVersion 2.2.3 -Force - } - displayName: Update PSGet and PackageManagement - condition: succeededOrFailed() - - - pwsh: | - Write-Verbose -Verbose "Packages to upload" - if(Test-Path $(Build.ArtifactStagingDirectory)) { Get-ChildItem "$(Build.ArtifactStagingDirectory)/*.nupkg" | ForEach-Object { $_.FullName }} - displayName: List packages to upload - condition: succeededOrFailed() - - - task: NuGetCommand@2 - displayName: 'NuGet push' - inputs: - command: push - publishVstsFeed: 'pscore-release' - publishFeedCredentials: 'AzArtifactsFeed' diff --git a/tools/releaseBuild/azureDevOps/compliance.yml b/tools/releaseBuild/azureDevOps/compliance.yml deleted file mode 100644 index 3624f1e1081..00000000000 --- a/tools/releaseBuild/azureDevOps/compliance.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Compliance-$(Build.BuildId) - -trigger: none -pr: none - -schedules: - # Chrontab format, see https://en.wikipedia.org/wiki/Cron - # this is in UTC - - cron: '0 13 * * *' - branches: - include: - - master - -resources: - repositories: - - repository: ComplianceRepo - type: github - endpoint: ComplianceGHRepo - name: PowerShell/compliance - ref: master - -parameters: -- name: InternalSDKBlobURL - displayName: URL to the blob havibg internal .NET SDK - type: string - default: ' ' - -variables: - - name: DOTNET_CLI_TELEMETRY_OPTOUT - value: 1 - - name: POWERSHELL_TELEMETRY_OPTOUT - value: 1 - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - # Defines the variables AzureFileCopySubscription, StorageAccount, StorageAccountKey, StorageResourceGroup, StorageSubscriptionName - - group: 'Azure Blob variable group' - # Defines the variables CgPat, CgOrganization, and CgProject - - group: 'ComponentGovernance' - - group: 'PoolNames' - - name: __DOTNET_RUNTIME_FEED - value: ${{ parameters.InternalSDKBlobURL }} - - -stages: - - stage: compliance - displayName: 'Compliance' - dependsOn: [] - jobs: - - template: templates/compliance/compliance.yml - parameters: - parentJobs: [] - - stage: APIScan - displayName: 'ApiScan' - dependsOn: [] - jobs: - - template: templates/compliance/apiscan.yml - parameters: - parentJobs: [] - - stage: notice - displayName: Generate Notice File - dependsOn: [] - jobs: - - template: templates/compliance/generateNotice.yml - parameters: - parentJobs: [] diff --git a/tools/releaseBuild/azureDevOps/diagram.puml b/tools/releaseBuild/azureDevOps/diagram.puml deleted file mode 100644 index ade53b11b9c..00000000000 --- a/tools/releaseBuild/azureDevOps/diagram.puml +++ /dev/null @@ -1,107 +0,0 @@ -@startuml - -folder "Linux Builds" as LinuxBuilds { - ' Define the build tasks as business processes - agent "DEB" as BuildDEB - agent "RPM" as BuildRPM - agent "Alpine" as BuildAlpine - agent "Linux-FxDependent" as BuildLinuxFx - -} - -agent "macOS Build" as BuildMac - -agent "Upload build metadata" as BuildMetadata - -folder "Windows Builds" as WinBuilds { - agent "x64" as BuildWinX64 - agent "x86" as BuildWinX86 - agent "arm32" as BuildWinArm32 - agent "arm64" as BuildWinArm64 - agent "FxDependent" as BuildWinFx -} - -agent "ComponentRegistration" as BuildCG - -folder "Linux Package Scanning and Upload" as PkgScanUploadLinux { - agent "DEB" as UploadDEB - agent "RPM" as UploadRPM - agent "Alpine" as UploadAlpine - agent "Linux-FxDependent" as UploadLinuxFx -} - -folder "Package Signing and Upload" as PkgSignUpload { - agent "macOS" as SignMac - - agent "Windows" as SignWin -} - -folder "Build Test Artifacts" as TestArtifacts { - agent "Windows" as WinTest - agent "Linux" as LinuxTest - agent "Linux-ARM" as LinuxArmTest - agent "Linux-ARM64" as LinuxArm64Test -} - -agent "Compliance" as Compliance - - -agent "Create SDK and Global Tool and Upload" as BuildNuGet - - -' Define finishing the build as a goal filled -control "Finish" as Finish -control "Start" as Start - -' map the various Upload task dependencies -BuildDEB -down-> UploadDEB -BuildRPM -down-> UploadRPM -BuildLinuxFx -down-> UploadLinuxFx -BuildAlpine -down-> UploadAlpine - -' map all of the SignMac task dependencies -BuildMac -down-> SignMac - -' map all of the SignWin task dependencies -WinBuilds -down-> SignWin -'BuildWinX64 -down-> SignWin -'BuildWinX86 -down-> SignWin -'BuildWinArm32 -down-> SignWin -'BuildWinArm64 -down-> SignWin -'BuildWinFx -down-> SignWin - -' map all of the Compliance task dependencies -BuildWinX86 -down-> Compliance -BuildWinX64 -down-> Compliance -BuildWinFx -down-> Compliance - -PkgSignUpload -down-> BuildNuGet -LinuxBuilds -down-> BuildNuGet - -' map all leafs to finish -Compliance ~~ Finish -UploadAlpine ~~ Finish -UploadDEB ~~ Finish -UploadRPM ~~ Finish -UploadLinuxFx ~~ Finish -SignMac ~~ Finish -BuildCG ~~ Finish -BuildNuGet ~~ Finish -TestArtifacts ~~ Finish -BuildMetadata ~~ Finish - -Start ~~ BuildDEB -Start ~~ BuildRPM -Start ~~ BuildAlpine -Start ~~ BuildLinuxFx -Start ~~ BuildMac -Start ~~ BuildWinX64 -Start ~~ BuildWinX86 -Start ~~ BuildWinFx -Start ~~ BuildWinArm32 -Start ~~ BuildWinArm64 -Start ~~ BuildCG -Start ~~ TestArtifacts -Start ~~ BuildMetadata - -@enduml diff --git a/tools/releaseBuild/azureDevOps/diagram.svg b/tools/releaseBuild/azureDevOps/diagram.svg deleted file mode 100644 index 024128bf988..00000000000 --- a/tools/releaseBuild/azureDevOps/diagram.svg +++ /dev/null @@ -1,108 +0,0 @@ -Linux BuildsWindows BuildsLinux Package Scanning and UploadPackage Signing and UploadBuild Test ArtifactsDEBRPMAlpineLinux-FxDependentx64x86arm32arm64FxDependentDEBRPMAlpineLinux-FxDependentmacOSWindowsWindowsLinuxLinux-ARMLinux-ARM64macOS BuildUpload build metadataComponentRegistrationComplianceCreate SDK and Global Tool and UploadFinishStart \ No newline at end of file diff --git a/tools/releaseBuild/azureDevOps/releaseBuild.yml b/tools/releaseBuild/azureDevOps/releaseBuild.yml deleted file mode 100644 index 3be90bbefbc..00000000000 --- a/tools/releaseBuild/azureDevOps/releaseBuild.yml +++ /dev/null @@ -1,379 +0,0 @@ -name: UnifiedPackageBuild-$(Build.BuildId) -trigger: - branches: - include: - - master - - release* -pr: - branches: - include: - - master - - release* - -parameters: - - name: ForceAzureBlobDelete - displayName: Delete Azure Blob - type: string - values: - - true - - false - default: false - - name: InternalSDKBlobURL - displayName: URL to the blob having internal .NET SDK - type: string - default: ' ' - -resources: - repositories: - - repository: ComplianceRepo - type: github - endpoint: ComplianceGHRepo - name: PowerShell/compliance - ref: master - -variables: - - name: PS_RELEASE_BUILD - value: 1 - - name: DOTNET_CLI_TELEMETRY_OPTOUT - value: 1 - - name: POWERSHELL_TELEMETRY_OPTOUT - value: 1 - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - # Prevents auto-injection of nuget-security-analysis@0 - - name: skipNugetSecurityAnalysis - value: true - - name: branchCounterKey - value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] - - name: branchCounter - value: $[counter(variables['branchCounterKey'], 1)] - - name: ForceAzureBlobDelete - value: ${{ parameters.ForceAzureBlobDelete }} - - name: Github_Build_Repository_Uri - value: https://github.com/powershell/powershell - - name: SBOMGenerator_Formats - value: spdx:2.2 - - name: BUILDSECMON_OPT_IN - value: true - - group: PoolNames - - name: __DOTNET_RUNTIME_FEED - value: ${{ parameters.InternalSDKBlobURL }} - -stages: - - stage: prep - jobs: - - template: templates/checkAzureContainer.yml - - - stage: macos - dependsOn: ['prep'] - jobs: - - template: templates/mac.yml - parameters: - buildArchitecture: x64 - - - template: templates/mac.yml - parameters: - buildArchitecture: arm64 - - - stage: linux - dependsOn: ['prep'] - jobs: - - template: templates/linux.yml - parameters: - buildName: deb - - - template: templates/linux.yml - parameters: - buildName: rpm - parentJob: build_deb - - - template: templates/linux.yml - parameters: - buildName: fxdependent - parentJob: build_deb - - - template: templates/linux.yml - parameters: - buildName: alpine - - - stage: windows - dependsOn: ['prep'] - jobs: - - template: templates/windows-hosted-build.yml - parameters: - Architecture: x64 - - - template: templates/windows-hosted-build.yml - parameters: - Architecture: x64 - BuildConfiguration: minSize - - - template: templates/windows-hosted-build.yml - parameters: - Architecture: x86 - - - template: templates/windows-hosted-build.yml - parameters: - Architecture: arm64 - - - template: templates/windows-hosted-build.yml - parameters: - Architecture: fxdependent - - - template: templates/windows-hosted-build.yml - parameters: - Architecture: fxdependentWinDesktop - - - stage: SignFiles - displayName: Sign files - dependsOn: ['windows', 'linux', 'macos'] - jobs: - - template: templates/mac-file-signing.yml - parameters: - buildArchitecture: x64 - - - template: templates/mac-file-signing.yml - parameters: - buildArchitecture: arm64 - - - job: SignFilesWinLinux - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - displayName: Sign files - - variables: - - group: ESRP - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: repoFolder - value: PowerShell - - name: repoRoot - value: $(Agent.BuildDirectory)\$(repoFolder) - - name: complianceRepoFolder - value: compliance - - strategy: - matrix: - linux-x64: - runtime: linux-x64 - unsignedBuildArtifactContainer: pwshLinuxBuild.tar.gz - unsignedBuildArtifactName: pwshLinuxBuild.tar.gz - signedBuildArtifactName: pwshLinuxBuild.tar.gz - signedArtifactContainer: authenticode-signed - linux-x64-Alpine: - runtime: linux-x64-Alpine - unsignedBuildArtifactContainer: pwshLinuxBuildAlpine.tar.gz - unsignedBuildArtifactName: pwshLinuxBuild.tar.gz - signedBuildArtifactName: pwshLinuxBuildAlpine.tar.gz - signedArtifactContainer: authenticode-signed - linux-x64-Alpine-Fxdependent: - runtime: linux-x64-Alpine-Fxdependent - unsignedBuildArtifactContainer: pwshAlpineFxdBuildAmd64.tar.gz - unsignedBuildArtifactName: pwshAlpineFxdBuildAmd64.tar.gz - signedBuildArtifactName: pwshAlpineFxdBuildAmd64.tar.gz - signedArtifactContainer: authenticode-signed - linux-arm32: - runtime: linux-arm32 - unsignedBuildArtifactContainer: pwshLinuxBuildArm32.tar.gz - unsignedBuildArtifactName: pwshLinuxBuildArm32.tar.gz - signedBuildArtifactName: pwshLinuxBuildArm32.tar.gz - signedArtifactContainer: authenticode-signed - linux-arm64: - runtime: linux-arm64 - unsignedBuildArtifactContainer: pwshLinuxBuildArm64.tar.gz - unsignedBuildArtifactName: pwshLinuxBuildArm64.tar.gz - signedBuildArtifactName: pwshLinuxBuildArm64.tar.gz - signedArtifactContainer: authenticode-signed - linux-fxd: - runtime: linux-fxd - unsignedBuildArtifactContainer: pwshLinuxBuildFxdependent.tar.gz - unsignedBuildArtifactName: pwshLinuxBuild.tar.gz - signedBuildArtifactName: pwshLinuxBuildFxdependent.tar.gz - signedArtifactContainer: authenticode-signed - linux-mariner: - runtime: linux-mariner - unsignedBuildArtifactContainer: pwshMarinerBuildAmd64.tar.gz - unsignedBuildArtifactName: pwshMarinerBuildAmd64.tar.gz - signedBuildArtifactName: pwshMarinerBuildAmd64.tar.gz - signedArtifactContainer: authenticode-signed - linux-arm64-mariner: - runtime: linux-arm64-mariner - unsignedBuildArtifactContainer: pwshMarinerBuildArm64.tar.gz - unsignedBuildArtifactName: pwshMarinerBuildArm64.tar.gz - signedBuildArtifactName: pwshMarinerBuildArm64.tar.gz - signedArtifactContainer: authenticode-signed - linux-minsize: - runtime: linux-minsize - unsignedBuildArtifactContainer: pwshLinuxBuildMinSize.tar.gz - unsignedBuildArtifactName: pwshLinuxBuildMinSize.tar.gz - signedBuildArtifactName: pwshLinuxBuildMinSize.tar.gz - signedArtifactContainer: authenticode-signed - win-x64: - runtime: win-x64 - unsignedBuildArtifactContainer: results - unsignedBuildArtifactName: '**/*-symbols-win-x64.zip' - signedBuildArtifactName: '-symbols-win-x64-signed.zip' - signedArtifactContainer: results - win-x86: - runtime: win-x86 - unsignedBuildArtifactContainer: results - unsignedBuildArtifactName: '**/*-symbols-win-x86.zip' - signedBuildArtifactName: '-symbols-win-x86-signed.zip' - signedArtifactContainer: results - win-arm64: - runtime: win-arm64 - unsignedBuildArtifactContainer: results - unsignedBuildArtifactName: '**/*-symbols-win-arm64.zip' - signedBuildArtifactName: '-symbols-win-arm64-signed.zip' - signedArtifactContainer: results - win-x64-gc: - runtime: win-x64-gc - unsignedBuildArtifactContainer: results - unsignedBuildArtifactName: '**/*-symbols-win-x64-gc.zip' - signedBuildArtifactName: '-symbols-win-x64-gc-signed.zip' - signedArtifactContainer: results - win-fxdependent: - runtime: win-fxdependent - unsignedBuildArtifactContainer: results - unsignedBuildArtifactName: '**/*-symbols-win-fxdependent.zip' - signedBuildArtifactName: '-symbols-win-fxdependent-signed.zip' - signedArtifactContainer: results - win-fxdependentWinDesktop: - runtime: win-fxdependentWinDesktop - unsignedBuildArtifactContainer: results - unsignedBuildArtifactName: '**/*-symbols-win-fxdependentWinDesktop.zip' - signedBuildArtifactName: '-symbols-win-fxdependentWinDesktop-signed.zip' - signedArtifactContainer: results - steps: - - template: templates/sign-build-file.yml - - - stage: mac_packaging - displayName: macOS packaging - dependsOn: ['SignFiles'] - jobs: - - template: templates/mac-package-build.yml - parameters: - buildArchitecture: x64 - - - template: templates/mac-package-build.yml - parameters: - buildArchitecture: arm64 - - - stage: linux_packaging - displayName: Linux Packaging - dependsOn: ['SignFiles'] - jobs: - - template: templates/linux-packaging.yml - parameters: - buildName: deb - - - template: templates/linux-packaging.yml - parameters: - buildName: rpm - uploadDisplayName: Upload and Sign - - - template: templates/linux-packaging.yml - parameters: - buildName: alpine - - - template: templates/linux-packaging.yml - parameters: - buildName: fxdependent - - - stage: win_packaging - displayName: Windows Packaging - dependsOn: ['SignFiles'] - jobs: - - template: templates/windows-packaging.yml - parameters: - Architecture: x64 - parentJob: build_windows_x64_release - - - template: templates/windows-packaging.yml - parameters: - Architecture: x64 - BuildConfiguration: minSize - parentJob: build_windows_x64_minSize - - - template: templates/windows-packaging.yml - parameters: - Architecture: x86 - parentJob: build_windows_x86_release - - - template: templates/windows-packaging.yml - parameters: - Architecture: arm64 - parentJob: build_windows_arm64_release - - - template: templates/windows-packaging.yml - parameters: - Architecture: fxdependent - parentJob: build_windows_fxdependent_release - - - template: templates/windows-packaging.yml - parameters: - Architecture: fxdependentWinDesktop - parentJob: build_windows_fxdependentWinDesktop_release - - - stage: package_signing - displayName: Package Signing - dependsOn: ['mac_packaging', 'linux_packaging', 'win_packaging'] - jobs: - - template: templates/windows-package-signing.yml - - - template: templates/mac-package-signing.yml - parameters: - buildArchitecture: x64 - - - template: templates/mac-package-signing.yml - parameters: - buildArchitecture: arm64 - - - stage: nuget_and_json - displayName: NuGet Packaging and Build Json - dependsOn: ['package_signing'] - jobs: - - template: templates/nuget.yml - - template: templates/json.yml - - # This is done late so that we dont use resources before the big signing and packaging tasks. - - stage: compliance - dependsOn: ['package_signing'] - jobs: - - template: templates/compliance.yml - - - stage: test_and_release_artifacts - displayName: Test and Release Artifacts - dependsOn: ['prep'] - jobs: - - template: templates/testartifacts.yml - - - job: release_json - displayName: Create and Upload release.json - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - steps: - - checkout: self - clean: true - - template: templates/SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - powershell: | - $metadata = Get-Content '$(Build.SourcesDirectory)/tools/metadata.json' -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package - @{ ReleaseVersion = "$(Version)"; LTSRelease = $LTS } | ConvertTo-Json | Out-File "$(Build.StagingDirectory)\release.json" - Get-Content "$(Build.StagingDirectory)\release.json" - Write-Host "##vso[artifact.upload containerfolder=metadata;artifactname=metadata]$(Build.StagingDirectory)\release.json" - displayName: Create and upload release.json file to build artifact - retryCountOnTaskFailure: 2 - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/releasePipeline.yml b/tools/releaseBuild/azureDevOps/releasePipeline.yml deleted file mode 100644 index e21f6d590fe..00000000000 --- a/tools/releaseBuild/azureDevOps/releasePipeline.yml +++ /dev/null @@ -1,673 +0,0 @@ -trigger: none - -# needed to disable CI trigger and allow manual trigger -# when the branch is same as pipeline source, the latest build from the source is used. -# all environment used are for manual tasks and approvals. - -parameters: - - name: skipPackagesMsftComPublish - displayName: Skip actual publishing to Packages.microsoft.com, AFTER we upload it. Used to test the publishing script. - default: false - type: boolean - - name: skipNugetPublish - displayName: Skip nuget publishing. Used in testing publishing stage. - default: false - type: boolean - -resources: - pipelines: - - pipeline: releasePipeline - source: 'Coordinated Packages' - trigger: - branches: - - release/* - - repositories: - - repository: Internal-PowerShellTeam-Tools - type: git - trigger: none - name: Internal-PowerShellTeam-Tools - ref: main-mirror - - - repository: ComplianceRepo - type: github - endpoint: ComplianceGHRepo - name: PowerShell/compliance - ref: master - -variables: - - name: runCodesignValidationInjection - value : false - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipComponentGovernanceDetection - value: true - - name: BUILDSECMON_OPT_IN - value: true - - group: ReleasePipelineSecrets - - group: PipelineExecutionPats - -stages: -- stage: MSIXBundle - displayName: Create MSIX Bundle package - dependsOn: [] - jobs: - - template: templates/release-MsixBundle.yml - -- stage: ValidateSDK - displayName: Validate SDK - dependsOn: [] - jobs: - - template: templates/release-SDKTests.yml - parameters: - jobName: WinSDK - displayName: Windows SDK Test - imageName: windows-latest - - - template: templates/release-SDKTests.yml - parameters: - jobName: LinuxSDK - displayName: Linux SDK Test - imageName: ubuntu-latest - - - template: templates/release-SDKTests.yml - parameters: - jobName: macOSSDK - displayName: macOS SDK Test - imageName: macOS-latest - -- stage: PRCreation - displayName: Create PR in GH Master - dependsOn: [] - jobs: - - deployment: CreatePRInMaster - displayName: Update README.md and metadata.json - pool: server - environment: PSReleaseCreatePR - -- stage: ValidateGlobalTool - displayName: Validate Global Tool - dependsOn: [] - jobs: - - template: templates/release-GlobalToolTest.yml - parameters: - jobName: WinGblTool - displayName: Global Tool Test Windows - imageName: windows-latest - globalToolExeName: 'pwsh.exe' - globalToolPackageName: 'PowerShell.Windows.x64' - - - template: templates/release-GlobalToolTest.yml - parameters: - jobName: LinuxWinGblTool - displayName: Global Tool Test Linux - imageName: ubuntu-latest - globalToolExeName: 'pwsh' - globalToolPackageName: 'PowerShell.Linux.x64' - -- stage: ValidateFxdPackage - displayName: Validate Fxd Package - dependsOn: [] - jobs: - - template: templates/release-ValidateFxdPackage.yml - parameters: - jobName: WinFxdPackage - displayName: Fxd Package Test Win - imageName: windows-latest - packageNamePattern: '**/*win-fxdependent.zip' - - - template: templates/release-ValidateFxdPackage.yml - parameters: - jobName: FxdPackageWindDesktop - displayName: Fxd Package Test WinDesktop - imageName: windows-latest - packageNamePattern: '**/*win-fxdependentWinDesktop.zip' - - - template: templates/release-ValidateFxdPackage.yml - parameters: - jobName: FxdPackageLinux - displayName: Fxd Package Test Linux - imageName: ubuntu-latest - packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' - - - template: templates/release-ValidateFxdPackage.yml - parameters: - jobName: FxdPackageLinuxonARM - displayName: Fxd Package Test Linux ARM64 - imageName: 'PSMMSUbuntu20.04-ARM64-secure' - packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' - use1ES: true - -- stage: StaticPkgValidation - dependsOn: [] - displayName: Static package validation - jobs: - - job: ValidatePkgNames - displayName: Validate Package Names - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - variables: - - group: 'Azure Blob variable group' - steps: - - template: templates/release-ValidatePackageNames.yml - - job: ValidatePkgBOM - displayName: Validate Package BOM - pool: - # testing - vmImage: ubuntu-latest - steps: - - template: templates/release-ValidatePackageBOM.yml - -- stage: StartDocker - dependsOn: [] - displayName: Kick Off Docker Staging build - jobs: - - deployment: PSDockerKickOff - displayName: Start Docker build - pool: server - environment: PSReleaseDockerKickOff - -- stage: ManualValidation - dependsOn: [] - displayName: Manual Validation - jobs: - - template: templates/release/approvalJob.yml - parameters: - displayName: Validate Windows Packages - jobName: ValidateWinPkg - instructions: | - Validate zip and msipackages on Windows Server 2012 R2 - - - template: templates/release/approvalJob.yml - parameters: - displayName: Validate OSX Packages - jobName: ValidateOsxPkg - instructions: | - Validate tar.gz package on osx-arm64 - -- stage: ReleaseAutomation - displayName: Release Automation - dependsOn: [] - jobs: - - job: KickOffRA - displayName: Kickoff Release Automation - timeoutInMinutes: 240 - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - checkout: Internal-PowerShellTeam-Tools - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: metadata - path: '$(Pipeline.Workspace)/releasePipeline/metadata' - - - pwsh: | - Get-ChildItem -Path $(Build.SourcesDirectory) - Import-Module $(Build.SourcesDirectory)\ReleaseTools\AzDO -Force - Set-AzDoProjectInfo -ProjectOwner PowerShell-Rel -ProjectName Release-Automation - Set-AzDoAuthToken -Token $(powershellRelExecutionPat) - $packageBuildID = $(resources.pipeline.releasePipeline.runID) - $metadata = Get-Content -Raw -Path '$(Pipeline.Workspace)/releasePipeline/metadata/release.json' | ConvertFrom-Json - $buildInvocationInfo = Start-AzDOBuild -BuildDefinitionId 10 -BuildArguments @{ POWERSHELL_PACKAGE_BUILD_BUILDID = $packageBuildID } -Tag $metadata.ReleaseVersion, 'InProgress' -PassThru - Write-Verbose -Verbose "Kicked off release automation:`n$($buildInvocationInfo | Out-String)" - $status = $buildInvocationInfo | Wait-AzDOBuildStatus -Status Completed -timeoutMinutes 240 - if ($status.result -ne 'Succeeded') { - Write-Verbose "There are errors in release automation tests. Please triage failures." - } - - - template: templates/release/approvalJob.yml - parameters: - displayName: Triage Release Automation Results - jobName: TriageRA - dependsOnJob: KickOffRA - instructions: | - Validate all the test failures and continue when signed off - - - job: MarkRASignOff - displayName: Mark release automation signoff - dependsOn: TriageRA - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - checkout: Internal-PowerShellTeam-Tools - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: metadata - path: '$(Pipeline.Workspace)/releasePipeline/metadata' - - - pwsh: | - Import-Module $(Build.SourcesDirectory)\ReleaseTools\AzDO -Force - Set-AzDoProjectInfo -ProjectOwner PowerShell-Rel -ProjectName Release-Automation - Set-AzDoAuthToken -Token $(powershellRelExecutionPat) - $metadata = Get-Content -Raw -Path '$(Pipeline.Workspace)/releasePipeline/metadata/release.json' | ConvertFrom-Json - $azDOBuild = Get-AzDOBuild -buildDefinitionId 10 -MaximumResult 100 | Where-Object { $_.tags -in $metadata.ReleaseVersion } - $azDoBuild | Remove-AzDOBuildTag -tag 'InProgress' -Pass | Add-AzDOBuildTag -tag 'SignedOff' - displayName: Signoff Release-Automation run - -- stage: UpdateChangeLog - displayName: Update the changelog - # do not include stages that are likely to fail in dependency as there is no way to force deploy. - dependsOn: - - MSIXBundle - - ValidateSDK - - PRCreation - - StaticPkgValidation - - StartDocker - - ManualValidation - - ValidateFxdPackage - - ValidateGlobalTool - - jobs: - - template: templates/release/approvalJob.yml - parameters: - displayName: Make sure the changelog is updated - jobName: MergeChangeLog - instructions: | - Update and merge the changelog for the release. - This step is required for creating GitHub draft release. - -- stage: BlobPublic - displayName: Make Blob Public - # do not include stages that are likely to fail in dependency as there is no way to force deploy. - dependsOn: UpdateChangeLog - - # The environment here is used for approval. - jobs: - - deployment: AzureBlobPublic - displayName: Make Azure Blob Public - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - variables: - - group: 'Staging_ACR' - environment: PSReleaseAzureBlobPublic - strategy: - runOnce: - deploy: - steps: - - template: templates/release-MakeContainerPublic.yml - - - template: templates/release/approvalJob.yml - parameters: - displayName: Copy Global tool packages to PSInfra storage - jobName: CopyBlobApproval - instructions: | - Approval for Copy global tool packages to PSInfra storage - - - job: PSInfraBlobPublic - displayName: Copy global tools to PSInfra storage - dependsOn: CopyBlobApproval - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - variables: - - group: 'PSInfraStorage' - - steps: - - template: templates/release-CopyGlobalTools.yml - parameters: - sourceContainerName: 'tool-private' - destinationContainerName: 'tool' - sourceStorageAccountName: '$(GlobalToolStorageAccount)' - destinationStorageAccountName: '$(PSInfraStorageAccount)' - blobPrefix: '$(Version)' - -- stage: GitHubTasks - displayName: GitHub tasks - dependsOn: BlobPublic - jobs: - - job: GitHubDraft - displayName: Create GitHub Draft release - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - variables: - - group: 'Azure Blob variable group' - - group: mscodehub-feed-read-general - - group: mscodehub-feed-read-akv - - group: ReleasePipelineSecrets - steps: - - template: templates/release-CreateGitHubDraft.yml - - - deployment: PushTag - dependsOn: GitHubDraft - displayName: Push Git Tag - pool : server - environment: PSReleasePushTag - - - deployment: MakeDraftPublic - dependsOn: PushTag - displayName: Make GitHub Draft public - pool : server - environment: PSReleaseDraftPublic - -- stage: PublishPackages - displayName: Publish packages - dependsOn: GitHubTasks - jobs: - - job: PublishNuget - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - template: templates/release-ReleaseToNuGet.yml - parameters: - skipPublish: ${{ parameters.skipNugetPublish }} - - - job: PublishPkgsMsftCom - - timeoutInMinutes: 120 - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMSUbuntu20.04-Secure - - variables: - - group: mscodehub-feed-read-general - - group: mscodehub-feed-read-akv - - group: 'packages.microsoft.com' - - group: 'mscodehub-code-read-akv' - steps: - - template: templates/release-PublishPackageMsftCom.yml - parameters: - skipPublish: ${{ parameters.skipPackagesMsftComPublish }} - -- stage: PublishSymbols - displayName: Publish symbols - dependsOn: PublishPackages - jobs: - - job: PublishSymbol - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - template: templates/release-PublishSymbols.yml - -- stage: ChangesToMaster - displayName: Ensure changes are in GH master - dependsOn: PublishPackages - jobs: - - template: templates/release/approvalJob.yml - parameters: - displayName: Make sure changes are in master - jobName: MergeToMaster - instructions: | - Make sure that changes README.md and metadata.json are merged into master on GitHub. - -- stage: ReleaseDocker - displayName: Release Docker - dependsOn: - - GitHubTasks - jobs: - - deployment: ReleaseDocker - displayName: Release Docker - pool: server - environment: PSReleaseDockerRelease - -- stage: ReleaseSnap - displayName: Release Snap - dependsOn: - - PublishPackages - - ChangesToMaster - variables: - # adds newPwshOrgName (exists in new and old org) - - group: PowerShellRelease - jobs: - - job: KickoffSnap - displayName: Kickoff Snap build - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - checkout: Internal-PowerShellTeam-Tools - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: metadata - path: '$(Pipeline.Workspace)/releasePipeline/metadata' - - pwsh: | - Import-Module $(Build.SourcesDirectory)\ReleaseTools\AzDO -Force - Set-AzDoProjectInfo -ProjectOwner PowerShell-Rel -ProjectName PowerShell - Set-AzDoAuthToken -Token $(powershellRelExecutionPat) - $metadata = Get-Content -Raw -Path '$(Pipeline.Workspace)/releasePipeline/metadata/release.json' | ConvertFrom-Json - $buildInvocationInfo = Start-AzDOBuild -BuildDefinitionId 49 -Tag $metadata.ReleaseVersion, 'InProgress' -PassThru - Write-Verbose -Verbose "Kicked off snap build: $($buildInvocationInfo.WebUrl)" - $status = $buildInvocationInfo | Wait-AzDOBuildStatus -Status Completed -timeoutMinutes 60 - if ($status.result -ne 'Succeeded') { - throw "There are errors in snap build!!" - } - - - template: templates/release/approvalJob.yml - parameters: - displayName: Approve the release - jobName: SnapEnd - dependsOnJob: KickoffSnap - instructions: | - Once the build is finished, approve the release of all channels. - - - job: MarkSnapSignOff - displayName: Mark release automation signoff - dependsOn: SnapEnd - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - checkout: Internal-PowerShellTeam-Tools - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: metadata - path: '$(Pipeline.Workspace)/releasePipeline/metadata' - - pwsh: | - Import-Module $(Build.SourcesDirectory)\ReleaseTools\AzDO -Force - Set-AzDoProjectInfo -ProjectOwner PowerShell-Rel -ProjectName PowerShell - Set-AzDoAuthToken -Token $(powershellRelExecutionPat) - $metadata = Get-Content -Raw -Path '$(Pipeline.Workspace)/releasePipeline/metadata/release.json' | ConvertFrom-Json - $azDOBuild = Get-AzDOBuild -buildDefinitionId 49 -MaximumResult 100 | Where-Object { $_.tags -in $metadata.ReleaseVersion } - $azDoBuild | Remove-AzDOBuildTag -tag 'InProgress' -Pass | Add-AzDOBuildTag -tag 'SignedOff' - displayName: Signoff Release-Automation run - -- stage: ReleaseToMU - displayName: Release to MU - dependsOn: - - PublishPackages - - ChangesToMaster - jobs: - - template: templates/release/approvalJob.yml - parameters: - displayName: Release to MU - instructions: | - Notify the PM team to start the process of releasing to MU. - -- stage: UpdateDotnetDocker - dependsOn: GitHubTasks - displayName: Update DotNet SDK Docker images - jobs: - - template: templates/release/approvalJob.yml - parameters: - displayName: Update .NET SDK docker images - jobName: DotnetDocker - instructions: | - Create PR for updating dotnet-docker images to use latest PowerShell version. - 1. Fork and clone https://github.com/dotnet/dotnet-docker.git - 2. git checkout upstream/nightly -b updatePS - 3. dotnet run --project .\eng\update-dependencies\ -- --product-version powershell= --compute-shas - 4. create PR targeting nightly branch - -- stage: UpdateWinGet - dependsOn: GitHubTasks - displayName: Add manifest entry to winget - jobs: - - template: templates/release/approvalJob.yml - parameters: - displayName: Add manifest entry to winget - jobName: UpdateWinGet - instructions: | - This is typically done by the community 1-2 days after the release. - -- stage: PublishMsix - dependsOn: GitHubTasks - displayName: Publish MSIX to store - jobs: - - template: templates/release/approvalJob.yml - parameters: - displayName: Publish the MSIX Bundle package to store - jobName: PublishMsix - instructions: | - Ask Steve to release MSIX bundle package to Store - -- stage: BuildInfoJson - dependsOn: GitHubTasks - displayName: Upload BuildInfoJson - jobs: - - deployment: UploadJson - displayName: Upload BuildInfoJson - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - variables: - - group: 'Azure Blob variable group' - environment: PSReleaseBuildInfoJson - strategy: - runOnce: - deploy: - steps: - - template: templates/release-BuildJson.yml - -- stage: ReleaseVPack - dependsOn: GitHubTasks - displayName: Release VPack - jobs: - - job: KickoffvPack - displayName: Kickoff vPack build - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - checkout: Internal-PowerShellTeam-Tools - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: metadata - path: '$(Pipeline.Workspace)/releasePipeline/metadata' - - - pwsh: | - Import-Module $(Build.SourcesDirectory)\ReleaseTools\AzDO -Force - Set-AzDoProjectInfo -ProjectOwner mscodehub -ProjectName PowerShellCore - Set-AzDoAuthToken -Token $(mscodehubBuildExecutionPat) - $metadata = Get-Content -Raw -Path '$(Pipeline.Workspace)/releasePipeline/metadata/release.json' | ConvertFrom-Json - $releaseVersion = $metadata.ReleaseVersion -replace '^v','' - $semanticVersion = [System.Management.Automation.SemanticVersion]$releaseVersion - $isPreview = $semanticVersion.PreReleaseLabel -ne $null - - if (-not $isPreview) { - $buildInvocationInfo = Start-AzDOBuild -BuildDefinitionId 1238 -Branch '$(Build.SourceBranch)' -Tag $metadata.ReleaseVersion, 'InProgress' -PassThru - Write-Verbose -Verbose "Kicked off vPack build: $($buildInvocationInfo.WebUrl)" - $status = $buildInvocationInfo | Wait-AzDOBuildStatus -Status Completed -timeoutMinutes 60 - if ($status.result -ne 'Succeeded') { - throw "There are errors in snap build!!" - } - else { - $buildInvocationInfo | Remove-AzDOBuildTag -tag 'InProgress' -Pass | Add-AzDOBuildTag -tag 'SignedOff' - } - } - else { - Write-Verbose -Verbose "This is a preview release with version: $semanticVersion skipping releasing vPack" - } - -- stage: ReleaseDeps - dependsOn: GitHubTasks - displayName: Update pwsh.deps.json links - jobs: - - template: templates/release-UpdateDepsJson.yml - -- stage: ReleaseClose - displayName: Finish Release - dependsOn: - - ReleaseVPack - - BuildInfoJson - - UpdateDotnetDocker - - ReleaseDocker - - ReleaseSnap - - ChangesToMaster - - ReleaseDeps - jobs: - - template: templates/release/approvalJob.yml - parameters: - displayName: Retain Build - jobName: RetainBuild - instructions: | - Retain the build - - - template: templates/release/approvalJob.yml - parameters: - displayName: Delete release branch - jobName: DeleteBranch - instructions: | - Delete release diff --git a/tools/releaseBuild/azureDevOps/templates/SetVersionVariables.yml b/tools/releaseBuild/azureDevOps/templates/SetVersionVariables.yml deleted file mode 100644 index dd9252a406f..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/SetVersionVariables.yml +++ /dev/null @@ -1,63 +0,0 @@ -parameters: - ReleaseTagVar: v6.2.0 - ReleaseTagVarName: ReleaseTagVar - CreateJson: 'no' - UseJson: 'yes' - -steps: -- ${{ if eq(parameters['UseJson'],'yes') }}: - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: 'BuildInfoJson' - itemPattern: '**/*.json' - downloadPath: '$(System.ArtifactsDirectory)' - displayName: Download Build Info Json - -- powershell: | - $path = "./build.psm1" - - if($env:REPOROOT){ - Write-Verbose "reporoot already set to ${env:REPOROOT}" -Verbose - exit 0 - } - - if(Test-Path -Path $path) - { - Write-Verbose "reporoot detect at: ." -Verbose - $repoRoot = '.' - } - else{ - $path = "./PowerShell/build.psm1" - if(Test-Path -Path $path) - { - Write-Verbose "reporoot detect at: ./PowerShell" -Verbose - $repoRoot = './PowerShell' - } - } - if($repoRoot) { - $vstsCommandString = "vso[task.setvariable variable=repoRoot]$repoRoot" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - } else { - Write-Verbose -Verbose "repo not found" - } - displayName: 'Set repo Root' - -- powershell: | - $createJson = ("${{ parameters.CreateJson }}" -ne "no") - $releaseTag = & "$env:REPOROOT/tools/releaseBuild/setReleaseTag.ps1" -ReleaseTag ${{ parameters.ReleaseTagVar }} -Variable "${{ parameters.ReleaseTagVarName }}" -CreateJson:$createJson - $version = $releaseTag.Substring(1) - $vstsCommandString = "vso[task.setvariable variable=Version]$version" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - $azureVersion = $releaseTag.ToLowerInvariant() -replace '\.', '-' - $vstsCommandString = "vso[task.setvariable variable=AzureVersion]$azureVersion" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: 'Set ${{ parameters.ReleaseTagVarName }} and other version Variables' - -- powershell: | - Get-ChildItem -Path env: - displayName: Capture environment - condition: succeededOrFailed() diff --git a/tools/releaseBuild/azureDevOps/templates/checkAzureContainer.yml b/tools/releaseBuild/azureDevOps/templates/checkAzureContainer.yml deleted file mode 100644 index af6451004e4..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/checkAzureContainer.yml +++ /dev/null @@ -1,51 +0,0 @@ -jobs: -- job: DeleteBlob - variables: - - name: runCodesignValidationInjection - value : false - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: Azure Blob variable group - displayName: Delete blob is exists - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - steps: - - checkout: self - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no - - - task: AzurePowerShell@4 - displayName: Check if blob exists and delete if specified - inputs: - azureSubscription: '$(AzureFileCopySubscription)' - scriptType: inlineScript - azurePowerShellVersion: latestVersion - inline: | - try { - $container = Get-AzStorageContainer -Container '$(AzureVersion)' -Context (New-AzStorageContext -StorageAccountName '$(StorageAccount)') -ErrorAction Stop - - if ($container -ne $null -and '$(ForceAzureBlobDelete)' -eq 'false') { - throw 'Azure blob container $(AzureVersion) already exists. To overwrite, use ForceAzureBlobDelete parameter' - } - elseif ($container -ne $null -and '$(ForceAzureBlobDelete)' -eq 'true') { - Write-Verbose -Verbose 'Removing container $(AzureVersion) due to ForceAzureBlobDelete parameter' - Remove-AzStorageContainer -Name '$(AzureVersion)' -Context (New-AzStorageContext -StorageAccountName '$(StorageAccount)') -Force - } - } - catch { - if ($_.FullyQualifiedErrorId -eq 'ResourceNotFoundException,Microsoft.WindowsAzure.Commands.Storage.Blob.Cmdlet.GetAzureStorageContainerCommand') { - Write-Verbose -Verbose 'Container "$(AzureVersion)" does not exists.' - } - else { - throw $_ - } - } - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/cloneToOfficialPath.yml b/tools/releaseBuild/azureDevOps/templates/cloneToOfficialPath.yml deleted file mode 100644 index 352458390f9..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/cloneToOfficialPath.yml +++ /dev/null @@ -1,19 +0,0 @@ -parameters: - nativePathRoot: '' - -steps: - - powershell: | - $dirSeparatorChar = [system.io.path]::DirectorySeparatorChar - $nativePath = "${{parameters.nativePathRoot }}${dirSeparatorChar}PowerShell" - Write-Host "##vso[task.setvariable variable=PowerShellRoot]$nativePath" - - if ((Test-Path "$nativePath")) { - Remove-Item -Path "$nativePath" -Force -Recurse -Verbose -ErrorAction ignore - } - else { - Write-Verbose -Verbose -Message "No cleanup required." - } - - git clone --quiet $env:REPOROOT $nativePath - displayName: Clone PowerShell Repo to /PowerShell - errorActionPreference: silentlycontinue diff --git a/tools/releaseBuild/azureDevOps/templates/compliance.yml b/tools/releaseBuild/azureDevOps/templates/compliance.yml deleted file mode 100644 index 0a416389bf4..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/compliance.yml +++ /dev/null @@ -1,124 +0,0 @@ -parameters: - parentJobs: [] - -jobs: -- job: compliance - variables: - - name: runCodesignValidationInjection - value : false - - name: NugetSecurityAnalysisWarningLevel - value: none - - displayName: Compliance - dependsOn: - ${{ parameters.parentJobs }} - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - checkout: self - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - task: DownloadBuildArtifacts@0 - displayName: 'Download artifacts' - inputs: - buildType: current - downloadType: single - artifactName: results - downloadPath: '$(System.ArtifactsDirectory)' - - - powershell: | - dir "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture artifacts directory' - continueOnError: true - - - template: expand-compliance.yml - parameters: - architecture: fxdependent - version: $(version) - - - template: expand-compliance.yml - parameters: - architecture: x86 - version: $(version) - - - template: expand-compliance.yml - parameters: - architecture: x64 - version: $(version) - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-antimalware.AntiMalware@3 - displayName: 'Run Defender Scan' - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-binskim.BinSkim@3 - displayName: 'Run BinSkim ' - inputs: - InputType: Basic - AnalyzeTarget: '$(CompliancePath)\*.dll;$(CompliancePath)\*.exe' - AnalyzeSymPath: 'SRV*' - AnalyzeVerbose: true - AnalyzeHashes: true - AnalyzeStatistics: true - continueOnError: true - - # add RoslynAnalyzers - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-autoapplicability.AutoApplicability@1 - displayName: 'Run AutoApplicability' - inputs: - ExternalRelease: true - IsSoftware: true - DataSensitivity: lbi - continueOnError: true - - # add codeMetrics - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-vulnerabilityassessment.VulnerabilityAssessment@0 - displayName: 'Run Vulnerability Assessment' - continueOnError: true - - # FXCop is not applicable - - # PreFASt is not applicable - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2 - displayName: 'Publish Security Analysis Logs to Build Artifacts' - continueOnError: true - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-uploadtotsa.TSAUpload@1 - displayName: 'TSA upload to Codebase: PowerShellCore_201906' - inputs: - tsaVersion: TsaV2 - codeBaseName: 'PowerShellCore_201906' - uploadAPIScan: false - uploadBinSkim: true - uploadCredScan: false - uploadFortifySCA: false - uploadFxCop: false - uploadModernCop: false - uploadPoliCheck: false - uploadPREfast: false - uploadRoslyn: false - uploadTSLint: false - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-report.SdtReport@1 - displayName: 'Create Security Analysis Report' - inputs: - TsvFile: false - APIScan: false - BinSkim: true - CredScan: true - PoliCheck: true - PoliCheckBreakOn: Severity2Above - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(Build.SourcesDirectory)\tools' - snapshotForceEnabled: true diff --git a/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml b/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml deleted file mode 100644 index 1b4f9067266..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml +++ /dev/null @@ -1,180 +0,0 @@ -jobs: - - job: APIScan - variables: - - name: runCodesignValidationInjection - value : false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: ReleaseTagVar - value: fromBranch - # Defines the variables APIScanClient, APIScanTenant and APIScanSecret - - group: PS-PS-APIScan - # PAT permissions NOTE: Declare a SymbolServerPAT variable in this group with a 'microsoft' organizanization scoped PAT with 'Symbols' Read permission. - # A PAT in the wrong org will give a single Error 203. No PAT will give a single Error 401, and individual pdbs may be missing even if permissions are correct. - - group: symbols - - name: branchCounterKey - value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] - - name: branchCounter - value: $[counter(variables['branchCounterKey'], 1)] - - group: DotNetPrivateBuildAccess - - group: Azure Blob variable group - - group: ReleasePipelineSecrets - - group: mscodehub-feed-read-general - - group: mscodehub-feed-read-akv - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - # APIScan can take a long time - timeoutInMinutes: 180 - - steps: - - template: ../SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no - - - template: ../insert-nuget-config-azfeed.yml - parameters: - repoRoot: '$(Build.SourcesDirectory)' - - - pwsh: | - Import-Module .\build.psm1 -force - Start-PSBootstrap - workingDirectory: '$(Build.SourcesDirectory)' - retryCountOnTaskFailure: 2 - displayName: 'Bootstrap' - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - Import-Module .\build.psm1 -force - Find-DotNet - dotnet tool install dotnet-symbol --tool-path $(Agent.ToolsDirectory)\tools\dotnet-symbol - $symbolToolPath = Get-ChildItem -Path $(Agent.ToolsDirectory)\tools\dotnet-symbol\dotnet-symbol.exe | Select-Object -First 1 -ExpandProperty FullName - Write-Host "##vso[task.setvariable variable=symbolToolPath]$symbolToolPath" - displayName: Install dotnet-symbol - retryCountOnTaskFailure: 2 - - - pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/build.psm1' - Install-AzCopy - displayName: Install AzCopy - retryCountOnTaskFailure: 2 - - - pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/build.psm1' - $azcopy = Find-AzCopy - Write-Verbose -Verbose "Found AzCopy: $azcopy" - - $winverifySymbolsPath = New-Item -ItemType Directory -Path '$(System.ArtifactsDirectory)/winverify-symbols' -Force - Write-Host "##vso[task.setvariable variable=winverifySymbolsPath]$winverifySymbolsPath" - - & $azcopy cp https://$(StorageAccount).blob.core.windows.net/winverify-private $winverifySymbolsPath --recursive - - Get-ChildItem $winverifySymbolsPath -Recurse | Out-String | Write-Verbose -Verbose - - displayName: Download winverify-private Artifacts - retryCountOnTaskFailure: 2 - env: - AZCOPY_AUTO_LOGIN_TYPE: MSI - - - pwsh: | - Import-Module .\build.psm1 -force - Find-DotNet - Start-PSBuild -Configuration StaticAnalysis -PSModuleRestore -Clean -Runtime fxdependent-win-desktop - - $OutputFolder = Split-Path (Get-PSOutput) - Write-Host "##vso[task.setvariable variable=BinDir]$OutputFolder" - - Write-Verbose -Verbose -Message "Deleting ref folder from output folder" - if (Test-Path $OutputFolder/ref) { - Remove-Item -Recurse -Force $OutputFolder/ref - } - workingDirectory: '$(Build.SourcesDirectory)' - displayName: 'Build PowerShell Source' - - - pwsh: | - Get-ChildItem -Path env: - displayName: Capture Environment - condition: succeededOrFailed() - - # Explicitly download symbols for the drop since the SDL image doesn't have http://SymWeb access and APIScan cannot handle https yet. - - pwsh: | - Import-Module .\build.psm1 -force - Find-DotNet - $pat = '$(SymbolServerPAT)' - if ($pat -like '*PAT*' -or $pat -eq '') - { - throw 'No PAT defined' - } - $url = 'https://microsoft.artifacts.visualstudio.com/defaultcollection/_apis/symbol/symsrv' - $(symbolToolPath) --authenticated-server-path $(SymbolServerPAT) $url --symbols -d "$env:BinDir\*" --recurse-subdirectories - displayName: 'Download Symbols for binaries' - retryCountOnTaskFailure: 2 - workingDirectory: '$(Build.SourcesDirectory)' - - - pwsh: | - Get-ChildItem '$(BinDir)' -File -Recurse | - Foreach-Object { - [pscustomobject]@{ - Path = $_.FullName - Version = $_.VersionInfo.FileVersion - Md5Hash = (Get-FileHash -Algorithm MD5 -Path $_.FullName).Hash - Sha512Hash = (Get-FileHash -Algorithm SHA512 -Path $_.FullName).Hash - } - } | Export-Csv -Path '$(Build.SourcesDirectory)/ReleaseFileHash.csv' - displayName: 'Create release file hash artifact' - - - task: PublishBuildArtifacts@1 - displayName: 'Publish Build File Hash artifact' - inputs: - pathToPublish: '$(Build.SourcesDirectory)/ReleaseFileHash.csv' - artifactName: ReleaseFilesHash - retryCountOnTaskFailure: 2 - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-apiscan.APIScan@2 - displayName: 'Run APIScan' - inputs: - softwareFolder: '$(BinDir)' - softwareName: PowerShell - softwareVersionNum: '$(ReleaseTagVar)' - isLargeApp: false - preserveTempFiles: false - verbosityLevel: standard - # write a status update every 5 minutes. Default is 1 minute - statusUpdateInterval: '00:05:00' - env: - AzureServicesAuthConnectionString: RunAs=App - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-report.SdtReport@2 - continueOnError: true - displayName: 'Guardian Export' - inputs: - GdnExportVstsConsole: true - GdnExportSarifFile: true - GdnExportHtmlFile: true - GdnExportAllTools: false - GdnExportGdnToolApiScan: true - #this didn't do anything GdnExportCustomLogsFolder: '$(Build.ArtifactStagingDirectory)/Guardian' - - - task: TSAUpload@2 - displayName: 'TSA upload' - inputs: - GdnPublishTsaOnboard: false - GdnPublishTsaConfigFile: '$(Build.SourcesDirectory)\tools\guardian\tsaconfig-APIScan.json' - - - pwsh: | - Get-ChildItem -Path env: - displayName: Capture Environment - condition: succeededOrFailed() - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@3 - displayName: 'Publish Guardian Artifacts' - inputs: - AllTools: false - APIScan: true - ArtifactName: APIScan diff --git a/tools/releaseBuild/azureDevOps/templates/compliance/compliance.yml b/tools/releaseBuild/azureDevOps/templates/compliance/compliance.yml deleted file mode 100644 index 8db52fc83f0..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/compliance/compliance.yml +++ /dev/null @@ -1,83 +0,0 @@ -parameters: - - name: parentJobs - type: jobList - -jobs: -- job: compliance - variables: - - name: runCodesignValidationInjection - value : false - - name: NugetSecurityAnalysisWarningLevel - value: none - - # Defines the variables APIScanClient, APIScanTenant and APIScanSecret - - group: PS-PS-APIScan - - displayName: Compliance - dependsOn: - ${{ parameters.parentJobs }} - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - - # APIScan can take a long time - timeoutInMinutes: 180 - - steps: - - checkout: self - clean: true - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@3 - displayName: 'Run CredScan' - inputs: - suppressionsFile: tools/credScan/suppress.json - debugMode: false - continueOnError: true - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-policheck.PoliCheck@2 - displayName: 'Run PoliCheck' - inputs: - # targetType F means file or folder and is the only applicable value and the default - targetType: F - # 1 to enable source code comment scanning, which is what we should do for open source - optionsFC: 1 - # recurse - optionsXS: 1 - # run for severity 1, 2, 3 and 4 issues - optionsPE: '1|2|3|4' - # disable history management - optionsHMENABLE: 0 - # Excluclusion access database - optionsRulesDBPath: '$(Build.SourcesDirectory)\tools\terms\PowerShell-Terms-Rules.mdb' - # Terms Exclusion xml file - optionsUEPath: $(Build.SourcesDirectory)\tools\terms\TermsExclusion.xml - continueOnError: true - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@3 - displayName: 'Publish Security Analysis Logs to Build Artifacts' - continueOnError: true - - - task: TSAUpload@2 - displayName: 'TSA upload' - inputs: - GdnPublishTsaOnboard: false - GdnPublishTsaConfigFile: '$(Build.SourcesDirectory)\tools\guardian\tsaconfig-others.json' - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-report.SdtReport@1 - displayName: 'Create Security Analysis Report' - inputs: - TsvFile: false - APIScan: false - BinSkim: false - CredScan: true - PoliCheck: true - PoliCheckBreakOn: Severity2Above - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(Build.SourcesDirectory)\tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/compliance/generateNotice.yml b/tools/releaseBuild/azureDevOps/templates/compliance/generateNotice.yml deleted file mode 100644 index 3e91b9174d2..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/compliance/generateNotice.yml +++ /dev/null @@ -1,90 +0,0 @@ -parameters: - - name: parentJobs - type: jobList - -jobs: -- job: generateNotice - variables: - - name: runCodesignValidationInjection - value : false - - name: NugetSecurityAnalysisWarningLevel - value: none - - displayName: Generate Notice - dependsOn: - ${{ parameters.parentJobs }} - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - timeoutInMinutes: 15 - - steps: - - checkout: self - clean: true - - - pwsh: | - [string]$Branch=$env:BUILD_SOURCEBRANCH - $branchOnly = $Branch -replace '^refs/heads/'; - $branchOnly = $branchOnly -replace '[_\-]' - - if ($branchOnly -eq 'master') { - $container = 'tpn' - } else { - $branchOnly = $branchOnly -replace '[\./]', '-' - $container = "tpn-$branchOnly" - } - - $vstsCommandString = "vso[task.setvariable variable=tpnContainer]$container" - Write-Verbose -Message $vstsCommandString -Verbose - Write-Host -Object "##$vstsCommandString" - displayName: Set ContainerName - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(Build.SourcesDirectory)\tools' - - - pwsh: | - ./tools/clearlyDefined/ClearlyDefined.ps1 -TestAndHarvest - displayName: Verify that packages have license data - - - task: msospo.ospo-extension.8d7f9abb-6896-461d-9e25-4f74ed65ddb2.notice@0 - displayName: 'NOTICE File Generator' - inputs: - outputfile: '$(System.ArtifactsDirectory)\ThirdPartyNotices.txt' - # output format can be html or text - outputformat: text - # this isn't working - # additionaldata: $(Build.SourcesDirectory)\assets\additionalAttributions.txt - - - - pwsh: | - Get-Content -Raw -Path $(Build.SourcesDirectory)\assets\additionalAttributions.txt | Out-File '$(System.ArtifactsDirectory)\ThirdPartyNotices.txt' -Encoding utf8NoBOM -Force -Append - Get-Content -Raw -Path '$(Build.SourcesDirectory)\assets\additionalAttributions.txt' - displayName: Append Additional Attributions - continueOnError: true - - - pwsh: | - Get-Content -Raw -Path '$(System.ArtifactsDirectory)\ThirdPartyNotices.txt' - displayName: Capture Notice - continueOnError: true - - - task: AzureFileCopy@4 - displayName: 'upload Notice' - inputs: - SourcePath: $(System.ArtifactsDirectory)\ThirdPartyNotices.txt - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: $(tpnContainer) - resourceGroup: '$(StorageResourceGroup)' - retryCountOnTaskFailure: 2 - - - task: PublishPipelineArtifact@1 - inputs: - targetPath: $(System.ArtifactsDirectory) - artifactName: notice - displayName: Publish notice artifacts - retryCountOnTaskFailure: 2 diff --git a/tools/releaseBuild/azureDevOps/templates/expand-compliance.yml b/tools/releaseBuild/azureDevOps/templates/expand-compliance.yml deleted file mode 100644 index 4cc25433262..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/expand-compliance.yml +++ /dev/null @@ -1,12 +0,0 @@ -parameters: - architecture: x86 - version: 6.2.0 - -steps: - - powershell: | - Expand-Archive -Path "$(System.ArtifactsDirectory)\results\PowerShell-${{ parameters.version }}-symbols-win-${{ parameters.architecture }}.zip" -Destination "$(Build.StagingDirectory)\symbols\${{ parameters.architecture }}" - displayName: Expand symbols zip - ${{ parameters.architecture }} - - - powershell: | - tools/releaseBuild/createComplianceFolder.ps1 -ArtifactFolder "$(Build.StagingDirectory)\symbols\${{ parameters.architecture }}" -VSTSVariableName 'CompliancePath' - displayName: Expand Compliance file - ${{ parameters.architecture }} diff --git a/tools/releaseBuild/azureDevOps/templates/global-tool-pkg-sbom.yml b/tools/releaseBuild/azureDevOps/templates/global-tool-pkg-sbom.yml deleted file mode 100644 index d7200809cca..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/global-tool-pkg-sbom.yml +++ /dev/null @@ -1,64 +0,0 @@ -parameters: - - name: PackageVersion - - name: LinuxBinPath - - name: WindowsBinPath - - name: WindowsDesktopBinPath - - name: AlpineBinPath - - name: DestinationPath - - name: ListOfPackageTypes - type: object - default: - - Unified - - PowerShell.Linux.Alpine - - PowerShell.Linux.x64 - - PowerShell.Linux.arm32 - - PowerShell.Linux.arm64 - - PowerShell.Windows.x64 - -steps: - -- pwsh: | - Write-Verbose -Verbose 'LinuxBinPath path: ${{ parameters.LinuxBinPath }}' - Write-Verbose -Verbose 'WindowsBinPath path: ${{ parameters.WindowsBinPath }}' - Write-Verbose -Verbose 'WindowsDesktopBinPath path: ${{ parameters.WindowsDesktopBinPath }}' - Write-Verbose -Verbose 'AlpineBinPath path: ${{ parameters.AlpineBinPath }}' - - Import-Module -Name $env:REPOROOT\build.psm1 - Import-Module -Name $env:REPOROOT\tools\packaging - Start-PrepForGlobalToolNupkg -LinuxBinPath '${{ parameters.LinuxBinPath }}' -WindowsBinPath '${{ parameters.WindowsBinPath }}' -WindowsDesktopBinPath '${{ parameters.WindowsDesktopBinPath }}' -AlpineBinPath '${{ parameters.AlpineBinPath }}' - displayName: 'Preparation for Global Tools package creation.' - -# NOTE: The Unified package must always be created first, and so must always be first in ListOfPackageTypes. -- ${{ each value in parameters.ListOfPackageTypes }}: - - pwsh: | - $PackageType = '${{ value }}' - - Write-Verbose -Verbose "PackageType: $PackageType" - Write-Verbose -Verbose 'Destination path: ${{ parameters.PackagePath }}' - - # Create global tool NuSpec source for package. - Import-Module -Name $env:REPOROOT\build.psm1 - Import-Module -Name $env:REPOROOT\tools\packaging - New-GlobalToolNupkgSource -PackageType $PackageType -PackageVersion '${{ parameters.PackageVersion }}' -LinuxBinPath '${{ parameters.LinuxBinPath }}' -WindowsBinPath '${{ parameters.WindowsBinPath }}' -WindowsDesktopBinPath '${{ parameters.WindowsDesktopBinPath }}' -AlpineBinPath '${{ parameters.AlpineBinPath }}' - displayName: 'Create global tool NuSpec source for package.' - - - pwsh: | - Get-ChildItem -Path env: - displayName: 'Capture environment variables after Global Tool package source is created.' - - # NOTE: The above 'New-GlobalToolNupkgSource' task function sets the 'GlobalToolNuSpecSourcePath', 'GlobalToolPkgName', - # and 'GlobalToolCGManifestPath' environment variables. - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: $(GlobalToolNuSpecSourcePath) - Build_Repository_Uri: 'https://github.com/powershell/powershell' - PackageName: $(GlobalToolPkgName) - PackageVersion: ${{ parameters.PackageVersion }} - sourceScanPath: $(GlobalToolCGManifestPath) - displayName: SBOM for Global Tool package - - - pwsh: | - Import-Module -Name $env:REPOROOT\build.psm1 - Import-Module -Name $env:REPOROOT\tools\packaging - New-GlobalToolNupkgFromSource -PackageNuSpecPath "$env:GlobalToolNuSpecSourcePath" -PackageName "$env:GlobalToolPkgName" -DestinationPath '${{ parameters.DestinationPath }}' -CGManifestPath "$env:GlobalToolCGManifestPath" - displayName: 'Create global tool NuSpec package from NuSpec source.' diff --git a/tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml b/tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml deleted file mode 100644 index 61b9df6c342..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml +++ /dev/null @@ -1,8 +0,0 @@ -parameters: -- name: "repoRoot" - default: $(REPOROOT) -steps: - - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self - parameters: - repoRoot: $(REPOROOT) - diff --git a/tools/releaseBuild/azureDevOps/templates/json.yml b/tools/releaseBuild/azureDevOps/templates/json.yml deleted file mode 100644 index 48a50e0bf14..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/json.yml +++ /dev/null @@ -1,57 +0,0 @@ -parameters: - parentJobs: [] - -jobs: -- job: json - variables: - - name: runCodesignValidationInjection - value : false - - name: NugetSecurityAnalysisWarningLevel - value: none - displayName: Create Json for Blob - dependsOn: - ${{ parameters.parentJobs }} - condition: succeeded() - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - #- task: @ - # inputs: - # - # displayName: '' - - checkout: self - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - - - task: AzureFileCopy@4 - displayName: 'upload daily-build-info JSON file to Azure - ${{ parameters.architecture }}' - inputs: - SourcePath: '$(BuildInfoPath)' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: 'BuildInfo' - condition: and(succeeded(), eq(variables['IS_DAILY'], 'true')) - - - task: AzureCLI@1 - displayName: 'Make blob public' - inputs: - azureSubscription: '$(AzureFileCopySubscription)' - scriptLocation: inlineScript - inlineScript: 'az storage container set-permission --account-name $(StorageAccount) --name $(azureVersion) --public-access blob' - condition: and(succeeded(), eq(variables['IS_DAILY'], 'true')) - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(Build.SourcesDirectory)\tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/linux-authenticode-sign.yml b/tools/releaseBuild/azureDevOps/templates/linux-authenticode-sign.yml deleted file mode 100644 index 719ba1a6c30..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/linux-authenticode-sign.yml +++ /dev/null @@ -1,184 +0,0 @@ -jobs: -- job: sign_linux_builds - displayName: Sign all linux builds - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - dependsOn: ['build_fxdependent', 'build_rpm'] - variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: ESRP - - steps: - - checkout: self - clean: true - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuild.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Download deb build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildMinSize.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Download min-size build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildArm32.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Download arm32 build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildArm64.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Download arm64 build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshMarinerBuildAmd64.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Download mariner build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshMarinerBuildArm64.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Download mariner arm64 build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildAlpine.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildAlpine.tar.gz - displayName: Download alpine build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildAlpine.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars/pwshAlpineFxdBuildAmd64.tar.gz - displayName: Download alpine fxdependent build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildFxdependent.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildFxdependent.tar.gz - displayName: Download fxdependent build - - - pwsh: | - Get-ChildItem -Path $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Capture downloaded tars - - - pwsh: | - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuild.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuild" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuild -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuild.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuild - Write-Verbose -Verbose "File permisions after expanding" - Get-ChildItem -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuild/pwsh | Select-Object -Property 'unixmode', 'size', 'name' - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildMinSize.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildMinSize.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildArm32.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildArm32.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32 - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildArm64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildArm64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64 - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshMarinerBuildAmd64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshMarinerBuildAmd64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64 - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshMarinerBuildArm64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshMarinerBuildArm64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64 - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildAlpine.tar.gz/pwshLinuxBuild.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpine" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpine -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildAlpine.tar.gz/pwshLinuxBuild.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpine - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshAlpineFxdBuildAmd64.tar.gz/pwshAlpineFxdBuildAmd64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpineFxd" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpineFxd -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshAlpineFxdBuildAmd64.tar.gz/pwshAlpineFxdBuildAmd64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpineFxd - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildFxdependent.tar.gz/pwshLinuxBuild.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildFxdependent" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildFxdependent -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildFxdependent.tar.gz/pwshLinuxBuild.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildFxdependent - displayName: Expand builds - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: cloneToOfficialPath.yml - - - template: insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(PowerShellRoot) - - - pwsh: | - Set-Location $env:POWERSHELLROOT - import-module "$env:POWERSHELLROOT/build.psm1" - Sync-PSTags -AddRemoteIfMissing - displayName: SyncTags - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - - - checkout: ComplianceRepo - clean: true - - - template: shouldSign.yml - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuild - buildPrefixName: 'PowerShell Linux' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuildMinSize - buildPrefixName: 'PowerShell Linux Minimum Size' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuildArm32 - buildPrefixName: 'PowerShell Linux Arm32' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuildArm64 - buildPrefixName: 'PowerShell Linux Arm64' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshMarinerBuildAmd64 - buildPrefixName: 'PowerShell Linux x64 (Mariner) Framework Dependent' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshMarinerBuildArm64 - buildPrefixName: 'PowerShell Linux arm64 (Mariner) Framework Dependent' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuildAlpine - buildPrefixName: 'PowerShell Linux Alpine x64' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuildAlpineFxd - buildPrefixName: 'PowerShell Linux Alpine Fxd x64' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuildFxdependent - buildPrefixName: 'PowerShell Linux Framework Dependent' diff --git a/tools/releaseBuild/azureDevOps/templates/linux-packaging.yml b/tools/releaseBuild/azureDevOps/templates/linux-packaging.yml deleted file mode 100644 index 59db37c64ac..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/linux-packaging.yml +++ /dev/null @@ -1,489 +0,0 @@ -parameters: - buildName: '' - uploadDisplayName: 'Upload' - -jobs: -- job: pkg_${{ parameters.buildName }} - displayName: Package ${{ parameters.buildName }} - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMSUbuntu20.04-Secure - variables: - - name: runCodesignValidationInjection - value: false - - name: build - value: ${{ parameters.buildName }} - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: ESRP - - group: DotNetPrivateBuildAccess - - steps: - - ${{ if or(eq(variables.build,'deb'), eq(variables.build,'rpm')) }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuild-signed - pattern: '**/pwshLinuxBuild.tar.gz' - displayName: Download deb build - - - ${{ if eq(variables.build,'deb') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize-signed - pattern: '**/pwshLinuxBuildMinSize.tar.gz' - displayName: Download min-size build - - - ${{ if eq(variables.build,'deb') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32-signed - pattern: '**/pwshLinuxBuildArm32.tar.gz' - displayName: Download arm32 build - - - ${{ if eq(variables.build,'deb') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64-signed - pattern: '**/pwshLinuxBuildArm64.tar.gz' - displayName: Download arm64 build - - - ${{ if eq(variables.build,'rpm') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64-signed - pattern: '**/pwshMarinerBuildAmd64.tar.gz' - displayName: Download mariner amd64 build - - - ${{ if eq(variables.build,'rpm') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64-signed - pattern: '**/pwshMarinerBuildArm64.tar.gz' - displayName: Download mariner arm64 build - - - ${{ if eq(variables.build,'alpine') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpine-signed - pattern: '**/pwshLinuxBuildAlpine.tar.gz' - displayName: Download alpine build - - - ${{ if eq(variables.build,'alpine') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64-signed - pattern: '**/pwshAlpineFxdBuildAmd64.tar.gz' - displayName: Download alpine framework dependent build - - - ${{ if eq(variables.build,'fxdependent') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildFxdependent-signed - pattern: '**/pwshLinuxBuildFxdependent.tar.gz' - displayName: Download fxdependent build - - - ${{ if or(eq(variables.build,'deb'), eq(variables.build,'rpm')) }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuild-meta - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuild-meta - displayName: Download deb build meta - - - ${{ if eq(variables.build,'deb') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildMinSize-meta - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize-meta - displayName: Download min-size build meta - - - ${{ if eq(variables.build,'deb') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildArm32-meta - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32-meta - displayName: Download arm32 build meta - - - ${{ if eq(variables.build,'deb') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildArm64-meta - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64-meta - displayName: Download arm64 build meta - - - ${{ if eq(variables.build,'rpm') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshMarinerBuildAmd64-meta - path: $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64-meta - displayName: Download mariner x64 build meta - - - ${{ if eq(variables.build,'rpm') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshMarinerBuildArm64-meta - path: $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64-meta - displayName: Download mariner arm64 build meta - - - ${{ if eq(variables.build,'alpine') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildAlpine-meta - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuild-meta - displayName: Download alpine build meta - - - ${{ if eq(variables.build,'alpine') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshAlpineFxdBuildAmd64-meta - path: $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64-meta - displayName: Download alpine build meta - - - ${{ if eq(variables.build,'fxdependent') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildFxdependent-meta - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuild-meta - displayName: Download fxdependent build meta - - - pwsh: | - Get-ChildItem '$(Build.ArtifactStagingDirectory)' | Select-Object -Property 'unixmode', 'size', 'name' - displayName: Capture downloads - - - pwsh: | - if ('$(build)' -eq 'deb' -or '$(build)' -eq 'rpm') { - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshLinuxBuild-signed/pwshLinuxBuild.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuild" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuild -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshLinuxBuild-signed/pwshLinuxBuild.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuild - } - - if ('$(build)' -eq 'deb') { - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize-signed/pwshLinuxBuildMinSize.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize-signed/pwshLinuxBuildMinSize.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize - - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32-signed/pwshLinuxBuildArm32.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32-signed/pwshLinuxBuildArm32.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32 - - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64-signed/pwshLinuxBuildArm64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64-signed/pwshLinuxBuildArm64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64 - } - - if ('$(build)' -eq 'rpm') { - # for mariner x64 - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64-signed/pwshMarinerBuildAmd64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64-signed/pwshMarinerBuildAmd64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64 - - # for mariner arm64 - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64-signed/pwshMarinerBuildArm64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64-signed/pwshMarinerBuildArm64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64 - } - - if ('$(build)' -eq 'alpine') { - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpine-signed/pwshLinuxBuildAlpine.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuild" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuild -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpine-signed/pwshLinuxBuildAlpine.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuild - - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64-signed/pwshAlpineFxdBuildAmd64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64-signed/pwshAlpineFxdBuildAmd64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64 - } - - if ('$(build)' -eq 'fxdependent') { - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshLinuxBuildFxdependent-signed/pwshLinuxBuildFxdependent.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuild" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuild -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshLinuxBuildFxdependent-signed/pwshLinuxBuildFxdependent.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuild - } - displayName: Expand all signed tar.gz - - - pwsh: | - Get-ChildItem '$(Build.ArtifactStagingDirectory)' | Select-Object -Property 'unixmode', 'size', 'name' - displayName: Capture expanded - - - checkout: self - clean: true - - - checkout: ComplianceRepo - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - pwsh: | - # create folder - sudo mkdir /PowerShell - - # make the current user the owner - sudo chown $env:USER /PowerShell - displayName: 'Create /PowerShell' - - - template: cloneToOfficialPath.yml - - - template: insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(PowerShellRoot) - - - powershell: | - import-module "$env:POWERSHELLROOT/build.psm1" - Sync-PSTags -AddRemoteIfMissing - displayName: SyncTags - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - - - powershell: | - Import-Module "$env:POWERSHELLROOT/build.psm1" - - Start-PSBootstrap -Package - displayName: 'Bootstrap' - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - powershell: | - try { - Import-Module "$env:POWERSHELLROOT/build.psm1" - Import-Module "$env:POWERSHELLROOT/tools/packaging" - - $metadata = Get-Content "$env:POWERSHELLROOT/tools/metadata.json" -Raw | ConvertFrom-Json - - # LTSRelease.Package indicates that the release should be packaged as an LTS - $LTS = $metadata.LTSRelease.Package - Write-Verbose -Verbose -Message "LTS is set to: $LTS" - - Invoke-AzDevOpsLinuxPackageCreation -ReleaseTag '$(ReleaseTagVar)' -BuildType '$(build)' - - if ($LTS) { - Write-Verbose -Verbose "Packaging LTS" - Invoke-AzDevOpsLinuxPackageCreation -LTS -ReleaseTag '$(ReleaseTagVar)' -BuildType '$(build)' - } - } catch { - Get-Error - throw - } - displayName: 'Package' - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - - - powershell: | - $linuxPackages = Get-ChildItem "$env:POWERSHELLROOT/powershell*" -Include *.deb,*.rpm,*.tar.gz - - $bucket = 'release' - foreach ($linuxPackage in $linuxPackages) - { - $filePath = $linuxPackage.FullName - Write-Verbose "Publishing $filePath to $bucket" -Verbose - Write-Host "##vso[artifact.upload containerfolder=$bucket;artifactname=$bucket]$filePath" - } - displayName: Publish artifacts - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - retryCountOnTaskFailure: 2 - - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml - -- job: upload_${{ parameters.buildName }} - displayName: ${{ parameters.uploadDisplayName }} ${{ parameters.buildName }} - dependsOn: pkg_${{ parameters.buildName }} - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - variables: - - name: buildName - value: ${{ parameters.buildName }} - - group: ESRP - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipComponentGovernanceDetection - value: true - - steps: - - checkout: self - clean: true - - - checkout: ComplianceRepo - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - template: shouldSign.yml - - - task: DownloadBuildArtifacts@0 - displayName: 'Download Deb Artifacts' - inputs: - downloadType: specific - itemPattern: '**/*.deb' - downloadPath: '$(System.ArtifactsDirectory)\finished' - condition: and(eq(variables['buildName'], 'DEB'), succeeded()) - - - task: DownloadBuildArtifacts@0 - displayName: 'Download tar.gz Artifacts copy' - inputs: - downloadType: specific - itemPattern: '**/*.tar.gz' - downloadPath: '$(System.ArtifactsDirectory)\finished' - - - powershell: | - Write-Host 'We handle the min-size package only when uploading for deb build.' - Write-Host '- For deb build, the min-size package is moved to a separate folder "finished\minSize",' - Write-Host ' so that the min-size package can be uploaded to a different Az Blob container.' - Write-Host '- For other builds, the min-size package is removed after being downloaded, so that it' - Write-Host ' does not get accidentally uploaded to the wrong Az Blob container.' - - $minSizePkg = '$(System.ArtifactsDirectory)\finished\release\*-gc.tar.gz' - if (Test-Path -Path $minSizePkg) - { - if ('$(buildName)' -eq 'DEB') - { - $minSizeDir = '$(System.ArtifactsDirectory)\finished\minSize' - New-Item -Path $minSizeDir -Type Directory -Force > $null - Move-Item -Path $minSizePkg -Destination $minSizeDir - - Write-Host "`nCapture the min-size package moved to the target folder." - Get-ChildItem -Path $minSizeDir - } - else - { - Write-Host '$(buildName): Remove the min-size package.' - Remove-Item -Path $minSizePkg -Force - } - } - else - { - Write-Host 'min-size package not found, so skip this step.' - } - displayName: 'Move minSize package to separate folder' - - - task: DownloadBuildArtifacts@0 - displayName: 'Download rpm Artifacts copy' - inputs: - downloadType: specific - itemPattern: '**/*.rpm' - downloadPath: '$(System.ArtifactsDirectory)\rpm' - condition: and(eq(variables['buildName'], 'RPM'), succeeded()) - - - template: EsrpScan.yml@ComplianceRepo - parameters: - scanPath: $(System.ArtifactsDirectory) - pattern: | - **\*.rpm - **\*.deb - **\*.tar.gz - - - ${{ if eq(variables['buildName'], 'RPM') }}: - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\rpm - signOutputPath: $(Build.StagingDirectory)\signedPackages - certificateId: "CP-450779-Pgp" - pattern: | - **\*.rh.*.rpm - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign RedHat RPM - OutputMode: AlwaysCopy - - - ${{ if eq(variables['buildName'], 'RPM') }}: - - template: EsrpSign.yml@ComplianceRepo - parameters: - # Sign in-place, previous task copied the files to this folder - buildOutputPath: $(Build.StagingDirectory)\signedPackages - signOutputPath: $(Build.StagingDirectory)\signedPackages - certificateId: "CP-459159-Pgp" - pattern: | - **\*.cm.*.rpm - **\*.cm?.*.rpm - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign Mariner RPM - OutputMode: NeverCopy - - # requires windows - - ${{ if ne(variables['buildName'], 'RPM') }}: - - task: AzureFileCopy@4 - displayName: 'Upload to Azure - DEB and tar.gz' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\finished\release\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - retryCountOnTaskFailure: 2 - - - template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\finished\release - - # requires windows - - task: AzureFileCopy@4 - displayName: 'Upload to Azure - min-size package for Guest Config' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\finished\minSize\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)-gc' - condition: and(eq(variables['buildName'], 'DEB'), succeeded()) - retryCountOnTaskFailure: 2 - - - template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\finished\minSize - condition: and(eq(variables['buildName'], 'DEB'), succeeded()) - - # requires windows - - task: AzureFileCopy@4 - displayName: 'Upload to Azure - RPM - Unsigned' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\rpm\release\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - condition: and(and(succeeded(), ne(variables['SHOULD_SIGN'], 'true')),eq(variables['buildName'], 'RPM')) - retryCountOnTaskFailure: 2 - - # requires windows - - task: AzureFileCopy@4 - displayName: 'Upload to Azure - RPM - Signed' - inputs: - SourcePath: '$(Build.StagingDirectory)\signedPackages\release\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - condition: and(and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')),eq(variables['buildName'], 'RPM')) - retryCountOnTaskFailure: 2 - - - template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\rpm\release - condition: and(and(succeeded(), ne(variables['SHOULD_SIGN'], 'true')),eq(variables['buildName'], 'RPM')) - - - template: upload-final-results.yml - parameters: - artifactPath: '$(Build.StagingDirectory)\signedPackages\release' - condition: and(and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')),eq(variables['buildName'], 'RPM')) - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/linux.yml b/tools/releaseBuild/azureDevOps/templates/linux.yml deleted file mode 100644 index bb343bed54e..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/linux.yml +++ /dev/null @@ -1,313 +0,0 @@ -parameters: - buildName: '' - uploadDisplayName: 'Upload' - parentJob: '' - -jobs: -- job: build_${{ parameters.buildName }} - displayName: Build ${{ parameters.buildName }} - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMSUbuntu20.04-Secure - dependsOn: ${{ parameters.parentJob }} - variables: - - name: runCodesignValidationInjection - value: false - - name: build - value: ${{ parameters.buildName }} - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: ESRP - - group: DotNetPrivateBuildAccess - - steps: - - checkout: self - clean: true - - - checkout: ComplianceRepo - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - pwsh: | - # create folder - sudo mkdir /PowerShell - - # make the current user the owner - sudo chown $env:USER /PowerShell - displayName: 'Create /PowerShell' - - - template: cloneToOfficialPath.yml - - - template: insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(PowerShellRoot) - - - powershell: | - import-module "$env:POWERSHELLROOT/build.psm1" - Sync-PSTags -AddRemoteIfMissing - displayName: SyncTags - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - - - powershell: | - Import-Module "$env:POWERSHELLROOT/build.psm1" - - Start-PSBootstrap -Package - displayName: 'Bootstrap' - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - try { - Import-Module "$env:POWERSHELLROOT/build.psm1" - Import-Module "$env:POWERSHELLROOT/tools/packaging" - - Invoke-AzDevOpsLinuxPackageBuild -ReleaseTag '$(ReleaseTagVar)' -BuildType '$(build)' - - Write-Verbose -Verbose "File permisions after building" - Get-ChildItem -Path $(System.ArtifactsDirectory)/pwshLinuxBuild/pwsh | Select-Object -Property 'unixmode', 'size', 'name' - - } catch { - Get-Error - throw - } - displayName: 'Build' - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshLinuxBuild' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: ${{ parameters.buildName }} SBOM - PackageName: PowerShell Linux - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - ${{ if eq(variables.build,'rpm') }} : - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshMarinerBuildAmd64' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: Mariner x64 SBOM - PackageName: PowerShell Linux Framework Dependent - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - ${{ if eq(variables.build,'rpm') }} : - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshMarinerBuildArm64' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: Mariner arm64 SBOM - PackageName: PowerShell Linux Framework Dependent - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - ${{ if eq(variables.build,'deb') }} : - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshLinuxBuildMinSize' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: MinSize SBOM - PackageName: PowerShell Linux Minimum Size - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - ${{ if eq(variables.build,'deb') }} : - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshLinuxBuildArm32' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: Arm32 SBOM - PackageName: PowerShell Linux Arm32 - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - ${{ if eq(variables.build,'deb') }} : - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshLinuxBuildArm64' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: Arm64 SBOM - PackageName: PowerShell Linux Arm64 - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - ${{ if eq(variables.build,'alpine') }} : - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshAlpineFxdBuildAmd64' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: Alpine FXD SBOM - PackageName: PowerShell Alpine Framework Dependent AMD64 - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - pwsh: | - Set-Location '$(System.ArtifactsDirectory)/pwshLinuxBuild' - Write-Verbose -Verbose "File permisions before compressing" - Get-ChildItem -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuild/pwsh | Select-Object -Property 'unixmode', 'size', 'name' - tar -czvf $(System.ArtifactsDirectory)/pwshLinuxBuild.tar.gz * - displayName: Compress pwshLinuxBuild - - - ${{ if eq(variables.build,'deb') }} : - - pwsh: | - Set-Location '$(System.ArtifactsDirectory)/pwshLinuxBuildMinSize' - tar -czvf $(System.ArtifactsDirectory)/pwshLinuxBuildMinSize.tar.gz * - Set-Location '$(System.ArtifactsDirectory)/pwshLinuxBuildArm32' - tar -czvf $(System.ArtifactsDirectory)/pwshLinuxBuildArm32.tar.gz * - Set-Location '$(System.ArtifactsDirectory)/pwshLinuxBuildArm64' - tar -czvf $(System.ArtifactsDirectory)/pwshLinuxBuildArm64.tar.gz * - displayName: Compress deb - - - ${{ if eq(variables.build,'rpm') }} : - - pwsh: | - Set-Location '$(System.ArtifactsDirectory)/pwshMarinerBuildAmd64' - tar -czvf $(System.ArtifactsDirectory)/pwshMarinerBuildAmd64.tar.gz * - displayName: Compress pwshMarinerBuildAmd64 - - - ${{ if eq(variables.build,'alpine') }} : - - pwsh: | - Set-Location '$(System.ArtifactsDirectory)/pwshAlpineFxdBuildAmd64' - tar -czvf $(System.ArtifactsDirectory)/pwshAlpineFxdBuildAmd64.tar.gz * - displayName: Compress pwshAlpineFxdBuildAmd64 - - - ${{ if eq(variables.build,'rpm') }} : - - pwsh: | - Set-Location '$(System.ArtifactsDirectory)/pwshMarinerBuildArm64' - tar -czvf $(System.ArtifactsDirectory)/pwshMarinerBuildArm64.tar.gz * - displayName: Compress pwshMarinerBuildArm64 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuild.tar.gz' - artifactName: pwshLinuxBuild.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuild-meta' - artifactName: pwshLinuxBuild-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuildMinSize.tar.gz' - artifactName: pwshLinuxBuildMinSize.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuildMinSize-meta' - artifactName: pwshLinuxBuildMinSize-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuildArm32.tar.gz' - artifactName: pwshLinuxBuildArm32.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuildArm32-meta' - artifactName: pwshLinuxBuildArm32-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuildArm64.tar.gz' - artifactName: pwshLinuxBuildArm64.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuildArm64-meta' - artifactName: pwshLinuxBuildArm64-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'rpm') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshMarinerBuildAmd64.tar.gz' - artifactName: pwshMarinerBuildAmd64.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'rpm') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshMarinerBuildAmd64-meta' - artifactName: pwshMarinerBuildAmd64-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'rpm') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshMarinerBuildArm64.tar.gz' - artifactName: pwshMarinerBuildArm64.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'rpm') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshMarinerBuildArm64-meta' - artifactName: pwshMarinerBuildArm64-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'alpine') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuild.tar.gz' - artifactName: pwshLinuxBuildAlpine.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'alpine') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuild-meta' - artifactName: pwshLinuxBuildAlpine-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'alpine') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshAlpineFxdBuildAmd64.tar.gz' - artifactName: pwshAlpineFxdBuildAmd64.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'alpine') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshAlpineFxdBuildAmd64-meta' - artifactName: pwshAlpineFxdBuildAmd64-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'fxdependent') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuild.tar.gz' - artifactName: pwshLinuxBuildFxdependent.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'fxdependent') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuild-meta' - artifactName: pwshLinuxBuildFxdependent-meta - retryCountOnTaskFailure: 2 diff --git a/tools/releaseBuild/azureDevOps/templates/mac-file-signing.yml b/tools/releaseBuild/azureDevOps/templates/mac-file-signing.yml deleted file mode 100644 index 8159c2bc7d9..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/mac-file-signing.yml +++ /dev/null @@ -1,121 +0,0 @@ -parameters: - buildArchitecture: 'x64' - -jobs: - - job: MacFileSigningJob_${{ parameters.buildArchitecture }} - displayName: macOS File signing ${{ parameters.buildArchitecture }} - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - variables: - - group: ESRP - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: repoFolder - value: PowerShell - - name: repoRoot - value: $(Agent.BuildDirectory)\$(repoFolder) - - name: complianceRepoFolder - value: compliance - - steps: - - checkout: self - clean: true - path: $(repoFolder) - - - checkout: ComplianceRepo - clean: true - path: $(complianceRepoFolder) - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: shouldSign.yml - - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: 'macosBinResults' - itemPattern: '**/*.zip' - downloadPath: '$(System.ArtifactsDirectory)\Symbols' - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Downloaded Artifacts' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - - - pwsh: | - $zipPath = Get-Item '$(System.ArtifactsDirectory)\Symbols\macosBinResults\*symbol*${{ parameters.buildArchitecture }}*.zip' - Write-Verbose -Verbose "Zip Path: $zipPath" - - $expandedFolder = $zipPath.BaseName - Write-Host "sending.. vso[task.setvariable variable=SymbolsFolder]$expandedFolder" - Write-Host "##vso[task.setvariable variable=SymbolsFolder]$expandedFolder" - - Expand-Archive -Path $zipPath -Destination "$(System.ArtifactsDirectory)\$expandedFolder" -Force - displayName: Expand symbols zip - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture artifacts dir Binaries' - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\$(SymbolsFolder)" -Recurse -Include pwsh, *.dylib - displayName: 'Capture Expanded Binaries' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - - - pwsh: | - $null = new-item -type directory -path "$(Build.StagingDirectory)\macos" - $zipFile = "$(Build.StagingDirectory)\macos\powershell-files-$(Version)-osx-${{ parameters.buildArchitecture }}.zip" - Get-ChildItem "$(System.ArtifactsDirectory)\$(SymbolsFolder)" -Recurse -Include pwsh, *.dylib | - Compress-Archive -Destination $zipFile - Write-Host $zipFile - displayName: 'Compress macOS binary files' - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(Build.StagingDirectory)\macos - signOutputPath: $(Build.StagingDirectory)\signedMacOSPackages - certificateId: "CP-401337-Apple" - pattern: | - **\*.zip - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign macOS Binaries - - - pwsh: | - $destination = "$(System.ArtifactsDirectory)\azureMacOs_${{ parameters.buildArchitecture }}" - New-Item -Path $destination -Type Directory - $zipPath = Get-ChildItem "$(Build.StagingDirectory)\signedMacOSPackages\powershell-*.zip" -Recurse | select-object -expandproperty fullname - foreach ($z in $zipPath) { Expand-Archive -Path $z -DestinationPath $destination } - displayName: 'Extract and copy macOS artifacts for upload' - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\azureMacOs_${{ parameters.buildArchitecture }} - artifactFilter: "*" - artifactName: signedMacOsBins_${{ parameters.buildArchitecture }} - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - ${{ if eq(variables['SHOULD_SIGN'], 'true') }}: - - template: EsrpScan.yml@ComplianceRepo - parameters: - scanPath: $(System.ArtifactsDirectory)\azureMacOs_${{ parameters.buildArchitecture }} - pattern: | - **\* - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(repoRoot)\tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/mac-package-build.yml b/tools/releaseBuild/azureDevOps/templates/mac-package-build.yml deleted file mode 100644 index c853a21ef37..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/mac-package-build.yml +++ /dev/null @@ -1,143 +0,0 @@ -parameters: - parentJob: '' - buildArchitecture: x64 - -jobs: -- job: package_macOS_${{ parameters.buildArchitecture }} - displayName: Package macOS ${{ parameters.buildArchitecture }} - condition: succeeded() - pool: - vmImage: macos-latest - variables: - # Turn off Homebrew analytics - - name: HOMEBREW_NO_ANALYTICS - value: 1 - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: DotNetPrivateBuildAccess - steps: - - checkout: self - clean: true - - - pwsh: | - # create folder - sudo mkdir "$(Agent.TempDirectory)/PowerShell" - - # make the current user the owner - sudo chown $env:USER "$(Agent.TempDirectory)/PowerShell" - displayName: 'Create $(Agent.TempDirectory)/PowerShell' - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: shouldSign.yml - - - template: cloneToOfficialPath.yml - parameters: - nativePathRoot: '$(Agent.TempDirectory)' - - - task: DownloadBuildArtifacts@0 - displayName: Download macosBinResults - inputs: - artifactName: 'macosBinResults' - itemPattern: '**/*${{ parameters.buildArchitecture }}.zip' - downloadPath: '$(System.ArtifactsDirectory)/Symbols' - - - task: DownloadBuildArtifacts@0 - displayName: Download signedMacOsBins - inputs: - artifactName: 'signedMacOsBins_${{ parameters.buildArchitecture }}' - itemPattern: '**/*' - downloadPath: '$(System.ArtifactsDirectory)/macOsBins' - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Downloaded Artifacts' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - - - pwsh: | - $zipPath = Get-Item '$(System.ArtifactsDirectory)\Symbols\macosBinResults\*symbol*${{ parameters.buildArchitecture }}.zip' - Write-Verbose -Verbose "Zip Path: $zipPath" - - $expandedFolder = $zipPath.BaseName - Write-Host "sending.. vso[task.setvariable variable=SymbolsFolder]$expandedFolder" - Write-Host "##vso[task.setvariable variable=SymbolsFolder]$expandedFolder" - - Expand-Archive -Path $zipPath -Destination "$(System.ArtifactsDirectory)\$expandedFolder" -Force - displayName: Expand symbols zip - - - pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - $signedFilesPath = '$(System.ArtifactsDirectory)/macOsBins/signedMacOsBins_${{ parameters.buildArchitecture }}/' - $BuildPath = '$(System.ArtifactsDirectory)\$(SymbolsFolder)' - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - displayName: Merge signed files with Build - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/$(SymbolsFolder)' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - PackageName: PowerShell macOS ${{ parameters.buildArchitecture }} - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - - $destFolder = '$(System.ArtifactsDirectory)\signedZip' - $BuildPath = '$(System.ArtifactsDirectory)\$(SymbolsFolder)' - - $null = New-Item -ItemType Directory -Path $destFolder -Force - - $BuildPackagePath = New-PSBuildZip -BuildPath $BuildPath -DestinationFolder $destFolder - - Write-Verbose -Verbose "New-PSSignedBuildZip returned `$BuildPackagePath as: $BuildPackagePath" - Write-Host "##vso[artifact.upload containerfolder=results;artifactname=results]$BuildPackagePath" - - $vstsCommandString = "vso[task.setvariable variable=BuildPackagePath]$BuildPackagePath" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Compress signed files - retryCountOnTaskFailure: 2 - - - - pwsh: | - try { - tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 -location $(PowerShellRoot) -BootStrap - } catch { - Get-Error - throw - } - displayName: 'Bootstrap VM' - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - # Add -SkipReleaseChecks as a mitigation to unblock release. - # macos-10.15 does not allow creating a folder under root. Hence, moving the folder. - try { - $(Build.SourcesDirectory)/tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 -ReleaseTag $(ReleaseTagVar) -Destination $(System.ArtifactsDirectory) -location $(PowerShellRoot) -ArtifactName macosPkgResults -BuildZip $(BuildPackagePath) -ExtraPackage "tar" -Runtime 'osx-${{ parameters.buildArchitecture }}' -SkipReleaseChecks - } catch { - Get-Error - throw - } - displayName: 'Package' - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(PowerShellRoot)/tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/mac-package-signing.yml b/tools/releaseBuild/azureDevOps/templates/mac-package-signing.yml deleted file mode 100644 index d4901580b0b..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/mac-package-signing.yml +++ /dev/null @@ -1,135 +0,0 @@ -parameters: - buildArchitecture: x64 - -jobs: -- job: MacPackageSigningJob_${{ parameters.buildArchitecture }} - displayName: macOS Package signing ${{ parameters.buildArchitecture }} - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - variables: - - group: ESRP - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: repoFolder - value: PowerShell - - name: repoRoot - value: $(Agent.BuildDirectory)\$(repoFolder) - - name: complianceRepoFolder - value: compliance - - steps: - - checkout: self - clean: true - path: $(repoFolder) - - - checkout: ComplianceRepo - clean: true - path: $(complianceRepoFolder) - - - template: shouldSign.yml - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: 'macosPkgResults' - itemPattern: '**/*' - downloadPath: '$(System.ArtifactsDirectory)' - - - pwsh: | - dir "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Downloaded Artifacts' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - - - pwsh: | - $null = new-item -type directory -path "$(Build.StagingDirectory)\macos" - $zipFile = "$(Build.StagingDirectory)\macos\powershell-$(Version)-osx-${{ parameters.buildArchitecture }}.zip" - Compress-Archive -Path "$(System.ArtifactsDirectory)\macosPkgResults\powershell-$(Version)-osx-${{ parameters.buildArchitecture }}.pkg" -Destination $zipFile - Write-Host $zipFile - - $ltsPkgPath = "$(System.ArtifactsDirectory)\macosPkgResults\powershell-lts-$(Version)-osx-${{ parameters.buildArchitecture }}.pkg" - - if(Test-Path $ltsPkgPath) - { - $ltsZipFile = "$(Build.StagingDirectory)\macos\powershell-lts-$(Version)-osx-${{ parameters.buildArchitecture }}.zip" - Compress-Archive -Path $ltsPkgPath -Destination $ltsZipFile - Write-Host $ltsZipFile - } - displayName: 'Compress macOS Package' - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(Build.StagingDirectory)\macos - signOutputPath: $(Build.StagingDirectory)\signedMacOSPackages - certificateId: "CP-401337-Apple" - pattern: | - **\*.zip - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign pkg - - - template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\macosPkgResults - artifactFilter: "*${{ parameters.buildArchitecture }}.tar.gz" - - - pwsh: | - $destination = "$(System.ArtifactsDirectory)\azureMacOs" - New-Item -Path $destination -Type Directory - $zipPath = dir "$(Build.StagingDirectory)\signedMacOSPackages\powershell-*.zip" -Recurse | select-object -expandproperty fullname - foreach ($z in $zipPath) { Expand-Archive -Path $z -DestinationPath $destination } - $targzPath = dir "$(System.ArtifactsDirectory)\*osx*.tar.gz" -Recurse | select-object -expandproperty fullname - Copy-Item -Path $targzPath -Destination $destination - displayName: 'Extract and copy macOS artifacts for upload' - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\azureMacOs - artifactFilter: "*.pkg" - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - pwsh: | - $null = new-item -type directory -path "$(Build.StagingDirectory)\macos-unsigned" - Copy-Item -Path "$(System.ArtifactsDirectory)\macosPkgResults\powershell-$(Version)-osx-x64.pkg" -Destination "$(Build.StagingDirectory)\macos-unsigned" - Copy-Item -Path "$(System.ArtifactsDirectory)\macosPkgResults\powershell-$(Version)-osx-x64.tar.gz" -Destination "$(Build.StagingDirectory)\macos-unsigned" - displayName: 'Create unsigned folder to upload' - condition: and(succeeded(), ne(variables['SHOULD_SIGN'], 'true')) - - - task: AzureFileCopy@4 - displayName: 'AzureBlob File Copy - unsigned' - inputs: - SourcePath: '$(Build.StagingDirectory)\macos-unsigned\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - condition: and(succeeded(), ne(variables['SHOULD_SIGN'], 'true')) - retryCountOnTaskFailure: 2 - - - task: AzureFileCopy@4 - displayName: 'AzureBlob File Copy - signed' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\azureMacOs\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - retryCountOnTaskFailure: 2 - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(repoRoot)/tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/mac.yml b/tools/releaseBuild/azureDevOps/templates/mac.yml deleted file mode 100644 index d173e900434..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/mac.yml +++ /dev/null @@ -1,68 +0,0 @@ -parameters: - buildArchitecture: 'x64' - -jobs: -- job: build_macOS_${{ parameters.buildArchitecture }} - displayName: Build macOS ${{ parameters.buildArchitecture }} - condition: succeeded() - pool: - vmImage: macos-latest - variables: - # Turn off Homebrew analytics - - name: HOMEBREW_NO_ANALYTICS - value: 1 - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: DotNetPrivateBuildAccess - steps: - #- task: @ - # inputs: - # - # displayName: '' - - checkout: self - clean: true - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - pwsh: | - # create folder - sudo mkdir "$(Agent.TempDirectory)/PowerShell" - - # make the current user the owner - sudo chown $env:USER "$(Agent.TempDirectory)/PowerShell" - displayName: 'Create $(Agent.TempDirectory)/PowerShell' - - - template: cloneToOfficialPath.yml - parameters: - nativePathRoot: '$(Agent.TempDirectory)' - - - pwsh: | - tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 -location $(PowerShellRoot) -BootStrap - displayName: 'Bootstrap VM' - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(PowerShellRoot) - - - pwsh: | - $env:AzDevOpsFeedPAT2 = '$(powershellPackageReadPat)' - # Add -SkipReleaseChecks as a mitigation to unblock release. - # macos-10.15 does not allow creating a folder under root. Hence, moving the folder. - $(Build.SourcesDirectory)/tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 -ReleaseTag $(ReleaseTagVar) -Destination $(System.ArtifactsDirectory) -Symbols -location $(PowerShellRoot) -Build -ArtifactName macosBinResults -Runtime 'osx-${{ parameters.buildArchitecture }}' -SkipReleaseChecks - $env:AzDevOpsFeedPAT2 = $null - displayName: 'Build' - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(Build.SourcesDirectory)/tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/nuget-pkg-sbom.yml b/tools/releaseBuild/azureDevOps/templates/nuget-pkg-sbom.yml deleted file mode 100644 index 0a0e3b96cc1..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/nuget-pkg-sbom.yml +++ /dev/null @@ -1,139 +0,0 @@ -parameters: - - name: PackageVersion - - name: PackagePath - - name: WinFxdPath - - name: LinuxFxdPath - - name: ListOfFiles - type: object - default: - - Microsoft.Management.Infrastructure.CimCmdlets.dll - - Microsoft.PowerShell.Commands.Diagnostics.dll - - Microsoft.PowerShell.Commands.Management.dll - - Microsoft.PowerShell.Commands.Utility.dll - - Microsoft.PowerShell.ConsoleHost.dll - - Microsoft.PowerShell.CoreCLR.Eventing.dll - - Microsoft.PowerShell.Security.dll - - Microsoft.PowerShell.SDK.dll - - Microsoft.WSMan.Management.dll - - Microsoft.WSMan.Runtime.dll - - System.Management.Automation.dll - -steps: - -- template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self - parameters: - repoRoot: $(REPOROOT) - -- pwsh: | - Import-Module "$env:REPOROOT/build.psm1" -Force - Start-PSBootstrap - - $sharedModules = @('Microsoft.PowerShell.Commands.Management', - 'Microsoft.PowerShell.Commands.Utility', - 'Microsoft.PowerShell.ConsoleHost', - 'Microsoft.PowerShell.Security', - 'System.Management.Automation' - ) - - $winOnlyModules = @('Microsoft.Management.Infrastructure.CimCmdlets', - 'Microsoft.PowerShell.Commands.Diagnostics', - 'Microsoft.PowerShell.CoreCLR.Eventing', - 'Microsoft.WSMan.Management', - 'Microsoft.WSMan.Runtime' - ) - - $refAssemblyFolder = Join-Path '$(System.ArtifactsDirectory)' 'RefAssembly' - $null = New-Item -Path $refAssemblyFolder -Force -Verbose -Type Directory - - Start-PSBuild -Clean -Runtime linux-x64 -Configuration Release - - $sharedModules | Foreach-Object { - $refFile = Get-ChildItem -Path "$env:REPOROOT\src\$_\obj\Release\net9.0\refint\$_.dll" - Write-Verbose -Verbose "RefAssembly: $refFile" - Copy-Item -Path $refFile -Destination "$refAssemblyFolder\$_.dll" -Verbose - $refDoc = "$env:REPOROOT\src\$_\bin\Release\net9.0\$_.xml" - if (-not (Test-Path $refDoc)) { - Write-Warning "$refDoc not found" - Get-ChildItem -Path "$env:REPOROOT\src\$_\bin\Release\net9.0\" | Out-String | Write-Verbose -Verbose - } - else { - Copy-Item -Path $refDoc -Destination "$refAssemblyFolder\$_.xml" -Verbose - } - } - - Start-PSBuild -Clean -Runtime win7-x64 -Configuration Release - - $winOnlyModules | Foreach-Object { - $refFile = Get-ChildItem -Path "$env:REPOROOT\src\$_\obj\Release\net9.0\refint\*.dll" - Write-Verbose -Verbose 'RefAssembly: $refFile' - Copy-Item -Path $refFile -Destination "$refAssemblyFolder\$_.dll" -Verbose - $refDoc = "$env:REPOROOT\src\$_\bin\Release\net9.0\$_.xml" - if (-not (Test-Path $refDoc)) { - Write-Warning "$refDoc not found" - Get-ChildItem -Path "$env:REPOROOT\src\$_\bin\Release\net9.0" | Out-String | Write-Verbose -Verbose - } - else { - Copy-Item -Path $refDoc -Destination "$refAssemblyFolder\$_.xml" -Verbose - } - } - - Get-ChildItem $refAssemblyFolder -Recurse | Out-String | Write-Verbose -Verbose - - # Set RefAssemblyPath path variable - $vstsCommandString = "vso[task.setvariable variable=RefAssemblyPath]${refAssemblyFolder}" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - - displayName: Build reference assemblies - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - -- ${{ each value in parameters.ListOfFiles }}: - - pwsh: | - $FileName = '${{ value }}' - $FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($FileName) - $FilePackagePath = Join-Path -Path '${{ parameters.PackagePath }}' -ChildPath $FileBaseName - $CGManifestPath = Join-Path -Path '${{ parameters.PackagePath }}' -ChildPath 'CGManifest' - Write-Verbose -Verbose "FileName to package: $FileName" - Write-Verbose -Verbose "FilePackage path: $FilePackagePath" - Write-Verbose -Verbose "CGManifest path: $CGManifestPath" - # Set SBOM package name - $vstsCommandString = "vso[task.setvariable variable=SbomFilePackageName]${FileBaseName}" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - # Set SBOM package path variable - $vstsCommandString = "vso[task.setvariable variable=SbomFilePackagePath]${FilePackagePath}" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - # Set CGManifest path variable - $vstsCommandString = "vso[task.setvariable variable=CGManifestPath]${CGManifestPath}" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - # Create Nuget package sources - Import-Module -Name $env:REPOROOT\build.psm1 - Import-Module -Name $env:REPOROOT\tools\packaging - Find-DotNet - New-ILNugetPackageSource -File $FileName -PackagePath '${{ parameters.PackagePath }}' -PackageVersion '${{ parameters.PackageVersion }}' -WinFxdBinPath '${{ parameters.WinFxdPath }}' -LinuxFxdBinPath '${{ parameters.LinuxFxdPath }}' -CGManifestPath $CGManifestPath -RefAssemblyPath $(RefAssemblyPath) - displayName: 'Create NuGet Package source for single file' - - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: $(SbomFilePackagePath) - Build_Repository_Uri: 'https://github.com/powershell/powershell' - PackageName: $(SbomFilePackageName) - PackageVersion: ${{ parameters.PackageVersion }} - sourceScanPath: $(CGManifestPath) - displayName: SBOM for NuGetPkg - - - pwsh: | - $FileName = '${{ value }}' - $FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($FileName) - $FilePackagePath = Join-Path -Path '${{ parameters.PackagePath }}' -ChildPath $FileBaseName - Write-Verbose -Verbose "FileName to package: $FileName" - Write-Verbose -Verbose "FilePackage path: $FilePackagePath" - Import-Module -Name $env:REPOROOT\build.psm1 - Import-Module -Name $env:REPOROOT\tools\packaging - Find-DotNet - New-ILNugetPackageFromSource -FileName $FileName -PackageVersion '${{ parameters.PackageVersion }}' -PackagePath '${{ parameters.PackagePath }}' - displayName: 'Create NuGet Package for single file' diff --git a/tools/releaseBuild/azureDevOps/templates/nuget.yml b/tools/releaseBuild/azureDevOps/templates/nuget.yml deleted file mode 100644 index 22f791bf0eb..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/nuget.yml +++ /dev/null @@ -1,290 +0,0 @@ -parameters: - parentJobs: [] - -jobs: -- job: build_nuget - dependsOn: - ${{ parameters.parentJobs }} - displayName: Build NuGet packages - condition: succeeded() - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - - timeoutInMinutes: 90 - - variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: build - value: ${{ parameters.buildName }} - - group: ESRP - - name: GenAPIToolPath - value: '$(System.ArtifactsDirectory)/GenAPI' - - name: PackagePath - value: '$(System.ArtifactsDirectory)/UnifiedPackagePath' - - name: winFxdPath - value: '$(System.ArtifactsDirectory)/winFxd' - - name: winFxdWinDesktopPath - value: '$(System.ArtifactsDirectory)/winFxdWinDesktop' - - name: linuxFxdPath - value: '$(System.ArtifactsDirectory)/linuxFxd' - - name: alpineFxdPath - value: '$(System.ArtifactsDirectory)/alpineFxd' - - group: DotNetPrivateBuildAccess - - steps: - - checkout: self - clean: true - - - checkout: ComplianceRepo - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - powershell: | - $content = Get-Content "$env:REPOROOT/global.json" -Raw | ConvertFrom-Json - $vstsCommandString = "vso[task.setvariable variable=SDKVersion]$($content.sdk.version)" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: 'Find SDK version from global.json' - - - pwsh: | - Import-Module "$env:REPOROOT/build.psm1" -Force - # We just need .NET but we fixed this in an urgent situation. - Start-PSBootStrap -Verbose - displayName: Bootstrap - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - task: DownloadBuildArtifacts@0 - displayName: 'Download PowerShell build artifacts - finalResults' - inputs: - buildType: current - downloadType: single - artifactName: finalResults - downloadPath: '$(System.ArtifactsDirectory)' - - - task: DownloadBuildArtifacts@0 - displayName: 'Download PowerShell build artifacts - macosPkgResults' - inputs: - buildType: current - downloadType: single - artifactName: macosPkgResults - downloadPath: '$(System.ArtifactsDirectory)' - - - powershell: 'Get-ChildItem $(System.ArtifactsDirectory) -recurse' - displayName: 'Capture downloaded artifacts' - - - powershell: | - $packagePath = (Join-Path $(System.ArtifactsDirectory) packages) - New-Item $packagePath -ItemType Directory -Force > $null - $packages = Get-ChildItem $(System.ArtifactsDirectory) -Include *.zip, *.tar.gz -Recurse - $packages | ForEach-Object { Copy-Item $_.FullName -Destination $packagePath -Verbose } - Get-ChildItem $packagePath -Recurse - displayName: 'Conflate packages to same folder' - - - task: ExtractFiles@1 - displayName: 'Extract files win-fxdependent' - inputs: - archiveFilePatterns: '$(System.ArtifactsDirectory)/packages/PowerShell-*-win-fxdependent.zip' - destinationFolder: '$(winFxdPath)' - - - task: ExtractFiles@1 - displayName: 'Extract files win-fxdependentWinDesktop' - inputs: - archiveFilePatterns: '$(System.ArtifactsDirectory)/packages/PowerShell-*-win-fxdependentWinDesktop.zip' - destinationFolder: '$(winFxdWinDesktopPath)' - - - task: ExtractFiles@1 - displayName: 'Extract files linux-fxdependent' - inputs: - archiveFilePatterns: '$(System.ArtifactsDirectory)/packages/powershell-*-linux-x64-fxdependent.tar.gz' - destinationFolder: '$(linuxFxdPath)' - - - task: ExtractFiles@1 - displayName: 'Extract files alpine-fxdependent' - inputs: - archiveFilePatterns: '$(System.ArtifactsDirectory)/packages/powershell-*-linux-x64-musl-noopt-fxdependent.tar.gz' - destinationFolder: '$(alpineFxdPath)' - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: shouldSign.yml - - - task: NuGetToolInstaller@1 - displayName: 'Install NuGet.exe' - - # Create nuget packages along with SBOM manifests. - - template: nuget-pkg-sbom.yml - parameters: - PackageVersion: $(Version) - PackagePath: $(PackagePath) - WinFxdPath: $(winFxdPath) - LinuxFxdPath: $(linuxFxdPath) - - - pwsh: | - Get-ChildItem $(linuxFxdPath) - Get-ChildItem $(winFxdPath) - Get-ChildItem $(winFxdWinDesktopPath) - Get-ChildItem $(alpineFxdPath) - displayName: Capture fxd folders - - # Create Global Tool packages along with SBOM manifests - - template: global-tool-pkg-sbom.yml - parameters: - PackageVersion: $(Version) - LinuxBinPath: $(linuxFxdPath) - WindowsBinPath: $(winFxdPath) - WindowsDesktopBinPath: $(winFxdWinDesktopPath) - AlpineBinPath: $(alpineFxdPath) - DestinationPath: $(PackagePath)\globaltool - - - pwsh: | - Get-ChildItem "$(PackagePath)" -Recurse - displayName: Capture generated packages - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(PackagePath) - signOutputPath: $(System.ArtifactsDirectory)\signed - certificateId: "CP-401405" - pattern: | - **\*.nupkg - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign NuPkg - - - pwsh: | - if (-not (Test-Path '$(System.ArtifactsDirectory)\signed\')) { $null = New-Item -ItemType Directory -Path '$(System.ArtifactsDirectory)\signed\' } - Copy-Item -Path '$(PackagePath)\*.nupkg' -Destination '$(System.ArtifactsDirectory)\signed\' -Verbose -Force - Copy-Item -Path '$(PackagePath)\globaltool\*.nupkg' -Destination '$(System.ArtifactsDirectory)\signed\' -Verbose -Force - displayName: Fake copy when not signing - condition: eq(variables['SHOULD_SIGN'], 'false') - - - pwsh: | - Import-Module "${env:REPOROOT}\build.psm1" -Force - Get-ChildItem -Recurse "$(System.ArtifactsDirectory)\signed\*.nupkg" -Verbose | ForEach-Object { Start-NativeExecution -sb { nuget.exe verify -All $_.FullName } } - displayName: Verify all packages are signed - condition: eq(variables['SHOULD_SIGN'], 'true') - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-antimalware.AntiMalware@3 - displayName: 'Run MpCmdRun.exe' - inputs: - FileDirPath: '$(PackagePath)' - TreatStaleSignatureAs: Warning - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2 - displayName: 'Publish Security Analysis Logs' - - - template: upload-final-results.yml - parameters: - artifactPath: '$(System.ArtifactsDirectory)\signed' - - - pwsh: | - if (-not (Test-Path "$(System.ArtifactsDirectory)\signed\globaltool")) - { - $null = New-Item -Path "$(System.ArtifactsDirectory)\signed\globaltool" -ItemType Directory -Force - } - - Move-Item -Path "$(System.ArtifactsDirectory)\signed\PowerShell.*" -Destination "$(System.ArtifactsDirectory)\signed\globaltool" -Force - Get-ChildItem "$(System.ArtifactsDirectory)\signed\globaltool" -Recurse - displayName: Move global tool packages to subfolder and capture - - - pwsh: | - $packagePath = (Join-Path $(System.ArtifactsDirectory) checksum) - New-Item $packagePath -ItemType Directory -Force > $null - $srcPaths = @("$(System.ArtifactsDirectory)\finalResults", "$(System.ArtifactsDirectory)\macosPkgResults", "$(System.ArtifactsDirectory)\signed") - - $packages = Get-ChildItem -Path $srcPaths -Include *.zip, *.tar.gz, *.msi*, *.pkg, *.deb, *.rpm -Exclude "PowerShell-Symbols*" -Recurse - $packages | ForEach-Object { Copy-Item $_.FullName -Destination $packagePath -Verbose } - - $packagePathList = Get-ChildItem $packagePath -Recurse | Select-Object -ExpandProperty FullName | Out-String - Write-Verbose -Verbose $packagePathList - - $checksums = Get-ChildItem -Path $packagePath -Exclude "SHA512SUMS" | - ForEach-Object { - Write-Verbose -Verbose "Generating checksum file for $($_.FullName)" - $packageName = $_.Name - $hash = (Get-FileHash -Path $_.FullName -Algorithm SHA512).Hash.ToLower() - - # the '*' before the packagename signifies it is a binary - "$hash *$packageName" - } - - $checksums | Out-File -FilePath "$packagePath\SHA512SUMS" -Force - - - $fileContent = Get-Content -Path "$packagePath\SHA512SUMS" -Raw | Out-String - Write-Verbose -Verbose -Message $fileContent - - Copy-Item -Path "$packagePath\SHA512SUMS" -Destination '$(System.ArtifactsDirectory)\signed\' -verbose - displayName: Generate checksum file for packages - - - pwsh: | - $packagePath = (Join-Path $(System.ArtifactsDirectory) checksum_gbltool) - New-Item $packagePath -ItemType Directory -Force > $null - $srcPaths = @("$(System.ArtifactsDirectory)\signed\globaltool") - $packages = Get-ChildItem -Path $srcPaths -Include *.nupkg -Recurse - $packages | ForEach-Object { Copy-Item $_.FullName -Destination $packagePath -Verbose } - - $packagePathList = Get-ChildItem $packagePath -Recurse | Select-Object -ExpandProperty FullName | Out-String - Write-Verbose -Verbose $packagePathList - - $checksums = Get-ChildItem -Path $packagePath -Exclude "SHA512SUMS" | - ForEach-Object { - Write-Verbose -Verbose "Generating checksum file for $($_.FullName)" - $packageName = $_.Name - $hash = (Get-FileHash -Path $_.FullName -Algorithm SHA512).Hash.ToLower() - - # the '*' before the packagename signifies it is a binary - "$hash *$packageName" - } - - $checksums | Out-File -FilePath "$packagePath\SHA512SUMS" -Force - - $fileContent = Get-Content -Path "$packagePath\SHA512SUMS" -Raw | Out-String - Write-Verbose -Verbose -Message $fileContent - - Copy-Item -Path "$packagePath\SHA512SUMS" -Destination '$(System.ArtifactsDirectory)\signed\globaltool\' -verbose - displayName: Generate checksum for global tools - - - template: upload-final-results.yml - parameters: - artifactPath: '$(System.ArtifactsDirectory)\checksum' - artifactFilter: SHA512SUMS - - - task: AzureFileCopy@4 - displayName: 'Upload NuGet packages to Azure' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\signed\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)-nuget' - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - retryCountOnTaskFailure: 2 - - - task: AzureFileCopy@4 - displayName: 'Upload global tool packages to Azure' - inputs: - sourcePath: '$(System.ArtifactsDirectory)\signed\globaltool\*' - azureSubscription: '$(GlobalToolSubscription)' - Destination: AzureBlob - storage: '$(GlobalToolStorageAccount)' - ContainerName: 'tool-private' - blobPrefix: '$(Version)' - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - retryCountOnTaskFailure: 2 - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(PackagePath)' diff --git a/tools/releaseBuild/azureDevOps/templates/release-BuildJson.yml b/tools/releaseBuild/azureDevOps/templates/release-BuildJson.yml deleted file mode 100644 index d183601a06c..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-BuildJson.yml +++ /dev/null @@ -1,102 +0,0 @@ -steps: -- checkout: self - clean: true - -- task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: BuildInfoJson - path: '$(Pipeline.Workspace)/releasePipeline/BuildInfoJson' - -- pwsh: | - Import-Module '$(Build.SourcesDirectory)/tools/ci.psm1' - $jsonFile = Get-Item "$ENV:PIPELINE_WORKSPACE/releasePipeline/BuildInfoJson/*.json" - $fileName = Split-Path $jsonFile -Leaf - - $dateTime = [datetime]::UtcNow - $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) - - $metadata = Get-Content ./tools/metadata.json | ConvertFrom-Json - $stableRelease = $metadata.StableRelease.Latest - $ltsRelease = $metadata.LTSRelease.Latest - - Write-Verbose -Verbose "Writing $jsonFile contents:" - $buildInfoJsonContent = Get-Content $jsonFile -Encoding UTF8NoBom -Raw - Write-Verbose -Verbose $buildInfoJsonContent - - $buildInfo = $buildInfoJsonContent | ConvertFrom-Json - $buildInfo.ReleaseDate = $dateTime - - $targetFile = "$ENV:PIPELINE_WORKSPACE/$fileName" - ConvertTo-Json -InputObject $buildInfo | Out-File $targetFile -Encoding ascii - - if ($stableRelease -or $fileName -eq "preview.json") { - Set-BuildVariable -Name CopyMainBuildInfo -Value YES - } else { - Set-BuildVariable -Name CopyMainBuildInfo -Value NO - } - - Set-BuildVariable -Name BuildInfoJsonFile -Value $targetFile - - ## Create 'lts.json' if it's the latest stable and also a LTS release. - - if ($fileName -eq "stable.json") { - if ($ltsRelease) { - $ltsFile = "$ENV:PIPELINE_WORKSPACE/lts.json" - Copy-Item -Path $targetFile -Destination $ltsFile -Force - Set-BuildVariable -Name LtsBuildInfoJsonFile -Value $ltsFile - Set-BuildVariable -Name CopyLTSBuildInfo -Value YES - } else { - Set-BuildVariable -Name CopyLTSBuildInfo -Value NO - } - - $releaseTag = $buildInfo.ReleaseTag - $version = $releaseTag -replace '^v' - $semVersion = [System.Management.Automation.SemanticVersion] $version - - $versionFile = "$ENV:PIPELINE_WORKSPACE/$($semVersion.Major)-$($semVersion.Minor).json" - Copy-Item -Path $targetFile -Destination $versionFile -Force - Set-BuildVariable -Name VersionBuildInfoJsonFile -Value $versionFile - Set-BuildVariable -Name CopyVersionBuildInfo -Value YES - } else { - Set-BuildVariable -Name CopyVersionBuildInfo -Value NO - } - displayName: Download and Capture NuPkgs - -- task: AzureFileCopy@4 - displayName: 'AzureBlob build info JSON file Copy' - inputs: - SourcePath: '$(BuildInfoJsonFile)' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: BuildInfo - condition: and(succeeded(), eq(variables['CopyMainBuildInfo'], 'YES')) - retryCountOnTaskFailure: 2 - -- task: AzureFileCopy@4 - displayName: 'AzureBlob build info ''lts.json'' Copy when needed' - inputs: - SourcePath: '$(LtsBuildInfoJsonFile)' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: BuildInfo - condition: and(succeeded(), eq(variables['CopyLTSBuildInfo'], 'YES')) - retryCountOnTaskFailure: 2 - -- task: AzureFileCopy@4 - displayName: 'AzureBlob build info ''Major-Minor.json'' Copy when needed' - inputs: - SourcePath: '$(VersionBuildInfoJsonFile)' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: BuildInfo - condition: and(succeeded(), eq(variables['CopyVersionBuildInfo'], 'YES')) - retryCountOnTaskFailure: 2 diff --git a/tools/releaseBuild/azureDevOps/templates/release-CopyGlobalTools.yml b/tools/releaseBuild/azureDevOps/templates/release-CopyGlobalTools.yml deleted file mode 100644 index 7c9306496ed..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-CopyGlobalTools.yml +++ /dev/null @@ -1,56 +0,0 @@ -parameters: -- name: sourceContainerName - type: string - default: 'source-container' - -- name: destinationContainerName - type: string - default: 'destination-container' - -- name: sourceStorageAccountName - type: string - default: 'source-storage-account' - -- name: destinationStorageAccountName - type: string - default: 'destination-storage-account' - -- name: blobPrefix - type: string - default: '$(Version)' - -steps: -- template: release-SetReleaseTagAndContainerName.yml - -- pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/build.psm1' - Install-AzCopy - displayName: Install AzCopy - retryCountOnTaskFailure: 2 - -- pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/build.psm1' - $azcopy = Find-AzCopy - Write-Verbose -Verbose "Found AzCopy: $azcopy" - - $sourceContainerName = "${{ parameters.sourceContainerName }}" - $destinationContainerName = "${{ parameters.destinationContainerName }}" - $sourceStorageAccountName = "${{ parameters.sourceStorageAccountName }}" - $destinationStorageAccountName = "${{ parameters.destinationStorageAccountName }}" - $blobPrefix = "${{ parameters.blobPrefix }}" - - $sourceBlobUrl = "https://${sourceStorageAccountName}.blob.core.windows.net/${sourceContainerName}/${blobPrefix}" - Write-Verbose -Verbose "Source blob url: $sourceBlobUrl" - $destinationBlobUrl = "https://${destinationStorageAccountName}.blob.core.windows.net/${destinationContainerName}" - Write-Verbose -Verbose "Destination blob url: $destinationBlobUrl" - - & $azcopy cp $sourceBlobUrl $destinationBlobUrl --recursive - - $packagesPath = Get-ChildItem -Path $(System.ArtifactsDirectory)\*.deb -Recurse -File | Select-Object -First 1 -ExpandProperty DirectoryName - Write-Host "sending -- vso[task.setvariable variable=PackagesRoot]$packagesPath" - Write-Host "##vso[task.setvariable variable=PackagesRoot]$packagesPath" - - displayName: Copy blobs - retryCountOnTaskFailure: 2 - env: - AZCOPY_AUTO_LOGIN_TYPE: MSI diff --git a/tools/releaseBuild/azureDevOps/templates/release-CreateGitHubDraft.yml b/tools/releaseBuild/azureDevOps/templates/release-CreateGitHubDraft.yml deleted file mode 100644 index 64c4d1b6a24..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-CreateGitHubDraft.yml +++ /dev/null @@ -1,110 +0,0 @@ -steps: -- checkout: self - clean: true - -- download: none - -- template: release-SetReleaseTagAndContainerName.yml - -- pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/PowerShell/build.psm1' - Install-AzCopy - displayName: Install AzCopy - retryCountOnTaskFailure: 2 - -- pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/PowerShell/build.psm1' - $azcopy = Find-AzCopy - Write-Verbose -Verbose "Found AzCopy: $azcopy" - - & $azcopy cp https://$(StorageAccount).blob.core.windows.net/$(AzureVersion) $(System.ArtifactsDirectory) --recursive - - $packagesPath = Get-ChildItem -Path $(System.ArtifactsDirectory)\*.deb -Recurse -File | Select-Object -First 1 -ExpandProperty DirectoryName - Write-Host "sending -- vso[task.setvariable variable=PackagesRoot]$packagesPath" - Write-Host "##vso[task.setvariable variable=PackagesRoot]$packagesPath" - - displayName: Download Azure Artifacts - retryCountOnTaskFailure: 2 - env: - AZCOPY_AUTO_LOGIN_TYPE: MSI - -- pwsh: | - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty FullName - displayName: Capture downloaded artifacts - -- pwsh: | - git clone https://$(AzureDevOpsPat)@mscodehub.visualstudio.com/PowerShellCore/_git/Internal-PowerShellTeam-Tools '$(Pipeline.Workspace)/tools' - displayName: Clone Internal-Tools repository - -- pwsh: | - $Path = "$(PackagesRoot)" - $OutputPath = Join-Path $Path ‘hashes.sha256’ - $srcPaths = @($Path) - $packages = Get-ChildItem -Path $srcPaths -Include * -Recurse -File - $checksums = $packages | - ForEach-Object { - Write-Verbose -Verbose "Generating checksum file for $($_.FullName)" - $packageName = $_.Name - $hash = (Get-FileHash -Path $_.FullName -Algorithm SHA256).Hash.ToLower() - # the '*' before the packagename signifies it is a binary - "$hash *$packageName" - } - $checksums | Out-File -FilePath $OutputPath -Force - $fileContent = Get-Content -Path $OutputPath -Raw | Out-String - Write-Verbose -Verbose -Message $fileContent - displayName: Add sha256 hashes - -- checkout: ComplianceRepo - -- pwsh: | - $releaseVersion = '$(ReleaseTag)' -replace '^v','' - $vstsCommandString = "vso[task.setvariable variable=ReleaseVersion]$releaseVersion" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: 'Set release version' - -- template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(PackagesRoot)' - Build_Repository_Uri: 'https://github.com/powershell/powershell.git' - displayName: PowerShell Hashes SBOM - packageName: PowerShell Artifact Hashes - packageVersion: $(ReleaseVersion) - sourceScanPath: '$(PackagesRoot)' - -- pwsh: | - Import-module '$(Pipeline.Workspace)/tools/Scripts/GitHubRelease.psm1' - $releaseVersion = '$(ReleaseTag)' -replace '^v','' - $semanticVersion = [System.Management.Automation.SemanticVersion]$releaseVersion - - $isPreview = $semanticVersion.PreReleaseLabel -ne $null - - $fileName = if ($isPreview) { - "preview.md" - } - else { - $semanticVersion.Major.ToString() + "." + $semanticVersion.Minor.ToString() + ".md" - } - - $filePath = "$env:BUILD_SOURCESDIRECTORY/PowerShell/CHANGELOG/$fileName" - Write-Verbose -Verbose "Selected Log file: $filePath" - - if (-not (Test-Path $filePath)) { - throw "$filePath not found" - } - - $changelog = Get-Content -Path $filePath - - $startPattern = "^## \[" + ([regex]::Escape($releaseVersion)) + "\]" - $endPattern = "^## \[{0}\.{1}\.{2}*" -f $semanticVersion.Major, $semanticVersion.Minor, $semanticVersion.Patch - - $clContent = $changelog | ForEach-Object { - if ($_ -match $startPattern) { $outputLine = $true } - elseif ($_ -match $endPattern) { $outputLine = $false } - if ($outputLine) { $_} - } | Out-String - - Write-Verbose -Verbose "Selected content: `n$clContent" - - Publish-ReleaseDraft -Tag '$(ReleaseTag)' -Name '$(ReleaseTag) Release of PowerShell' -Description $clContent -User PowerShell -Repository PowerShell -PackageFolder $(PackagesRoot) -Token $(GitHubReleasePat) - displayName: Publish Release Draft diff --git a/tools/releaseBuild/azureDevOps/templates/release-GlobalToolTest.yml b/tools/releaseBuild/azureDevOps/templates/release-GlobalToolTest.yml deleted file mode 100644 index 8591791de0e..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-GlobalToolTest.yml +++ /dev/null @@ -1,149 +0,0 @@ -parameters: - jobName: "" - displayName: "" - imageName: "" - globalToolExeName: 'pwsh.exe' - globalToolPackageName: 'PowerShell.Windows.x64' - - -jobs: -- job: ${{ parameters.jobName }} - displayName: ${{ parameters.displayName }} - pool: - # test - vmImage: ${{ parameters.imageName }} - variables: - - group: DotNetPrivateBuildAccess - - steps: - - checkout: self - clean: true - - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - patterns: '**/*.nupkg' - path: '$(Pipeline.Workspace)/releasePipeline/finalResults' - - - pwsh: | - $dotnetMetadataPath = "$(Build.SourcesDirectory)/DotnetRuntimeMetadata.json" - $dotnetMetadataJson = Get-Content $dotnetMetadataPath -Raw | ConvertFrom-Json - - # Channel is like: $Channel = "5.0.1xx-preview2" - $Channel = $dotnetMetadataJson.sdk.channel - - $sdkVersion = (Get-Content "$(Build.SourcesDirectory)/global.json" -Raw | ConvertFrom-Json).sdk.version - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - - Find-Dotnet - - if(-not (Get-PackageSource -Name 'dotnet' -ErrorAction SilentlyContinue)) - { - $nugetFeed = ([xml](Get-Content $(Build.SourcesDirectory)/nuget.config -Raw)).Configuration.packagesources.add | Where-Object { $_.Key -eq 'dotnet' } | Select-Object -ExpandProperty Value - if ($nugetFeed) { - Register-PackageSource -Name 'dotnet' -Location $nugetFeed -ProviderName NuGet - Write-Verbose -Message "Register new package source 'dotnet'" -verbose - } - } - - ## Install latest version from the channel - - #Install-Dotnet -Channel "$Channel" -Version $sdkVersion - Start-PSBootstrap - - Write-Verbose -Message "Installing .NET SDK completed." -Verbose - - displayName: Install .NET - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - $branch = $ENV:BUILD_SOURCEBRANCH - $version = $branch -replace '^.*(release[-/])v' - $vstsCommandString = "vso[task.setvariable variable=PowerShellVersion]$version" - Write-Verbose -Message "Version is $version" -Verbose - Write-Host -Object "##$vstsCommandString" - displayName: Set PowerShell Version - - - pwsh: | - $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - Start-PSBootstrap - - $toolPath = New-Item -ItemType Directory "$(System.DefaultWorkingDirectory)/toolPath" | Select-Object -ExpandProperty FullName - - dotnet tool install --add-source "$ENV:PIPELINE_WORKSPACE/releasePipeline/finalResults" --tool-path $toolPath --version '$(PowerShellVersion)' '${{ parameters.globalToolPackageName }}' - - Get-ChildItem -Path $toolPath - - displayName: Install global tool - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - $toolPath = "$(System.DefaultWorkingDirectory)/toolPath/${{ parameters.globalToolExeName }}" - - if (-not (Test-Path $toolPath)) - { - throw "Tool is not installed at $toolPath" - } - else - { - Write-Verbose -Verbose "Tool found at: $toolPath" - } - displayName: Validate tool is installed - - - pwsh: | - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - Start-PSBootstrap - - $exeName = if ($IsWindows) { "pwsh.exe" } else { "pwsh" } - - $toolPath = "$(System.DefaultWorkingDirectory)/toolPath/${{ parameters.globalToolExeName }}" - - $source = (get-command -Type Application -Name dotnet | Select-Object -First 1 -ExpandProperty source) - $target = (Get-ChildItem $source).target - - # If we find a symbolic link for dotnet, then we need to split the filename off the target. - if ($target) { - Write-Verbose -Verbose "Splitting target: $target" - $target = Split-Path $target - } - - Write-Verbose -Verbose "target is set as $target" - - $env:DOTNET_ROOT = (resolve-path -Path (Join-Path (split-path $source) $target)).ProviderPath - - Write-Verbose -Verbose "DOTNET_ROOT: $env:DOTNET_ROOT" - Get-ChildItem $env:DOTNET_ROOT - - $versionFound = & $toolPath -c '$PSVersionTable.PSVersion.ToString()' - - if ( '$(PowerShellVersion)' -ne $versionFound) - { - throw "Expected version of global tool not found. Installed version is $versionFound" - } - else - { - write-verbose -verbose "Found expected version: $versionFound" - } - - $dateYear = & $toolPath -c '(Get-Date).Year' - - if ( $dateYear -ne [DateTime]::Now.Year) - { - throw "Get-Date returned incorrect year: $dateYear" - } - else - { - write-verbose -verbose "Got expected year: $dateYear" - } - displayName: Basic validation - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) diff --git a/tools/releaseBuild/azureDevOps/templates/release-MakeContainerPublic.yml b/tools/releaseBuild/azureDevOps/templates/release-MakeContainerPublic.yml deleted file mode 100644 index 65d5ea50191..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-MakeContainerPublic.yml +++ /dev/null @@ -1,20 +0,0 @@ -steps: -- download: none - -- template: release-SetReleaseTagAndContainerName.yml - -- pwsh: | - az login --service-principal -u $(az_url) -p $(az_key) --tenant $(az_name) - displayName: az login - -- pwsh: | - az storage container set-permission --account-name $(StorageAccount) --name $(azureVersion) --public-access blob - displayName: Make container public - -- pwsh: | - az storage container set-permission --account-name $(StorageAccount) --name $(azureVersion)-gc --public-access blob - displayName: Make guest configuration miminal package container public - -- pwsh: | - az logout - displayName: az logout diff --git a/tools/releaseBuild/azureDevOps/templates/release-MsixBundle.yml b/tools/releaseBuild/azureDevOps/templates/release-MsixBundle.yml deleted file mode 100644 index a9591b2d251..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-MsixBundle.yml +++ /dev/null @@ -1,81 +0,0 @@ -jobs: -- job: CreateMSIXBundle - displayName: Create .msixbundle file - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - variables: - - group: msixTools - - group: 'Azure Blob variable group' - - steps: - - template: release-SetReleaseTagAndContainerName.yml - - - task: DownloadPipelineArtifact@2 - retryCountOnTaskFailure: 2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - patterns: '**/*.msix' - path: '$(Pipeline.Workspace)\releasePipeline\msix' - - - pwsh: | - $cmd = Get-Command makeappx.exe -ErrorAction Ignore - if ($cmd) { - Write-Verbose -Verbose 'makeappx available in PATH' - $exePath = $cmd.Source - } else { - $toolsDir = '$(Pipeline.Workspace)\releasePipeline\tools' - New-Item $toolsDir -Type Directory -Force > $null - Invoke-RestMethod -Uri '$(makeappUrl)' -OutFile "$toolsDir\makeappx.zip" - Expand-Archive "$toolsDir\makeappx.zip" -DestinationPath "$toolsDir\makeappx" -Force - $exePath = "$toolsDir\makeappx\makeappx.exe" - - Write-Verbose -Verbose 'makeappx was installed:' - Get-ChildItem -Path $toolsDir -Recurse - } - - $vstsCommandString = "vso[task.setvariable variable=MakeAppxPath]$exePath" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Install makeappx tool - retryCountOnTaskFailure: 1 - - - pwsh: | - $sourceDir = '$(Pipeline.Workspace)\releasePipeline\msix' - $file = Get-ChildItem $sourceDir | Select-Object -First 1 - $prefix = ($file.BaseName -split "-win")[0] - $pkgName = "$prefix.msixbundle" - Write-Verbose -Verbose "Creating $pkgName" - - $makeappx = '$(MakeAppxPath)' - $outputDir = "$sourceDir\output" - New-Item $outputDir -Type Directory -Force > $null - & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" - - Get-ChildItem -Path $sourceDir -Recurse - $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Create MsixBundle - retryCountOnTaskFailure: 1 - - - task: AzureFileCopy@4 - displayName: 'Upload MSIX Bundle package to Az Blob' - retryCountOnTaskFailure: 2 - inputs: - SourcePath: '$(BundleDir)/*.msixbundle' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)-private' - resourceGroup: '$(StorageResourceGroup)' - condition: succeeded() diff --git a/tools/releaseBuild/azureDevOps/templates/release-PublishPackageMsftCom.yml b/tools/releaseBuild/azureDevOps/templates/release-PublishPackageMsftCom.yml deleted file mode 100644 index 861cf48c35a..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-PublishPackageMsftCom.yml +++ /dev/null @@ -1,57 +0,0 @@ -parameters: - - name: skipPublish - default: false - type: boolean - -steps: -- template: release-SetReleaseTagAndContainerName.yml - -- pwsh: | - $packageVersion = '$(ReleaseTag)'.ToLowerInvariant() -replace '^v','' - $vstsCommandString = "vso[task.setvariable variable=packageVersion]$packageVersion" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Set Package version - -- pwsh: | - $branch = 'main-mirror' - $gitArgs = "clone", - "--verbose", - "--branch", - "$branch", - "https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/Internal-PowerShellTeam-Tools", - '$(Pipeline.Workspace)/tools' - $gitArgs | Write-Verbose -Verbose - git $gitArgs - displayName: Clone Internal-PowerShellTeam-Tools from MSCodeHub - -- task: PipAuthenticate@1 - inputs: - artifactFeeds: 'pmc' - pythonDownloadServiceConnections: pmcDownload - -- pwsh: | - pip install pmc-cli - - $newPath = (resolve-path '~/.local/bin').providerpath - $vstsCommandString = "vso[task.setvariable variable=PATH]${env:PATH}:$newPath" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Install pmc cli - -- pwsh: | - $metadata = Get-Content -Path "$(Build.SourcesDirectory)/tools/metadata.json" -Raw | ConvertFrom-Json - $params = @{ - ReleaseTag = "$(ReleaseTag)" - AadClientId = "$(PmcCliClientID)" - BlobFolderName = "$(AzureVersion)" - LTS = $metadata.LTSRelease.Latest - ForProduction = $true - SkipPublish = $${{ parameters.skipPublish }} - MappingFilePath = '$(System.DefaultWorkingDirectory)/tools/packages.microsoft.com/mapping.json' - } - - $params | Out-String -width 9999 -Stream | write-Verbose -Verbose - - & '$(Pipeline.Workspace)/tools/packages.microsoft.com-v4/releaseLinuxPackages.ps1' @params - displayName: Run release script diff --git a/tools/releaseBuild/azureDevOps/templates/release-PublishSymbols.yml b/tools/releaseBuild/azureDevOps/templates/release-PublishSymbols.yml deleted file mode 100644 index db2cc86e259..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-PublishSymbols.yml +++ /dev/null @@ -1,51 +0,0 @@ -steps: -- task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: results - path: '$(Pipeline.Workspace)\results' - itemPattern: | - **/* - !**/*signed.zip - -- pwsh: | - Write-Verbose -Verbose "Enumerating $(Pipeline.Workspace)\results" - $downloadedArtifacts = Get-ChildItem -Recurse "$(Pipeline.Workspace)\results" - $downloadedArtifacts - $expandedRoot = New-Item -Path "$(Pipeline.Workspace)/expanded" -ItemType Directory -Verbose - $symbolsRoot = New-Item -Path "$(Pipeline.Workspace)/symbols" -ItemType Directory -Verbose - - $downloadedArtifacts | ForEach-Object { - $destFolder = New-Item -Path "$expandedRoot/$($_.BaseName)/" -ItemType Directory -Verbose - Expand-Archive -Path $_.FullName -DestinationPath $destFolder -Force - - $symbolsZipFile = Join-Path -Path $destFolder -ChildPath "symbols.zip" - $symbolZipFileContents = New-Item -Path "$destFolder/Symbols-$($_.BaseName)" -ItemType Directory -Verbose - Expand-Archive -Path $symbolsZipFile -DestinationPath $symbolZipFileContents -Force - - $symbolsToPublish = New-Item -Path "$symbolsRoot/$($_.BaseName)" -ItemType Directory -Verbose - - Get-ChildItem -Path $symbolZipFileContents -Recurse -Filter '*.pdb' | ForEach-Object { - Copy-Item -Path $_.FullName -Destination $symbolsToPublish -Verbose - } - } - - Write-Verbose -Verbose "Enumerating $symbolsRoot" - Get-ChildItem -Path $symbolsRoot -Recurse - $vstsCommandString = "vso[task.setvariable variable=SymbolsPath]$symbolsRoot" - Write-Verbose -Message "$vstsCommandString" -Verbose - Write-Host -Object "##$vstsCommandString" - displayName: Expand and capture symbols folders -- task: PublishSymbols@2 - inputs: - symbolsFolder: '$(SymbolsPath)' - searchPattern: '**/*.pdb' - indexSources: false - publishSymbols: true - symbolServerType: teamServices - detailedLog: true diff --git a/tools/releaseBuild/azureDevOps/templates/release-ReleaseToNuGet.yml b/tools/releaseBuild/azureDevOps/templates/release-ReleaseToNuGet.yml deleted file mode 100644 index 33a72f56bbb..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-ReleaseToNuGet.yml +++ /dev/null @@ -1,56 +0,0 @@ -parameters: - - name: skipPublish - default: false - type: boolean - -steps: -- task: DownloadPipelineArtifact@2 - condition: and(eq('${{ parameters.skipPublish }}', 'false'), succeeded()) - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - patterns: '**/*.nupkg' - path: '$(Pipeline.Workspace)/releasePipeline/finalResults' - -- task: DownloadPipelineArtifact@2 - condition: and(eq('${{ parameters.skipPublish }}', 'false'), succeeded()) - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: metadata - path: '$(Pipeline.Workspace)/releasePipeline/metadata' - -- pwsh: | - #Exclude all global tool packages. Their names start with 'PowerShell.' - $null = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/release" - Copy-Item "$ENV:PIPELINE_WORKSPACE/releasePipeline/finalResults/*.nupkg" -Destination "$(Pipeline.Workspace)/release" -Exclude "PowerShell.*.nupkg" -Force -Verbose - - $releaseVersion = Get-Content "$ENV:PIPELINE_WORKSPACE/releasePipeline/metadata/release.json" | ConvertFrom-Json | Select-Object -ExpandProperty 'ReleaseVersion' - $globalToolPath = "$ENV:PIPELINE_WORKSPACE/releasePipeline/finalResults/PowerShell.$releaseVersion.nupkg" - - if ($releaseVersion -notlike '*-*') { - # Copy the global tool package for stable releases - Copy-Item $globalToolPath -Destination "$(Pipeline.Workspace)/release" - } - - Get-ChildItem "$(Pipeline.Workspace)/release" -recurse - displayName: Download and capture nupkgs - condition: and(eq('${{ parameters.skipPublish }}', 'false'), succeeded()) - -- task: NuGetCommand@2 - displayName: 'NuGet push' - condition: and(eq('${{ parameters.skipPublish }}', 'false'), succeeded()) - inputs: - command: push - packagesToPush: '$(Pipeline.Workspace)/release/*.nupkg' - nuGetFeedType: external - publishFeedCredentials: PowerShellNuGetOrgPush diff --git a/tools/releaseBuild/azureDevOps/templates/release-SDKTests.yml b/tools/releaseBuild/azureDevOps/templates/release-SDKTests.yml deleted file mode 100644 index 93fb0bf07cb..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-SDKTests.yml +++ /dev/null @@ -1,148 +0,0 @@ -parameters: - jobName: "" - displayName: "" - imageName: "" - -jobs: -- job: ${{ parameters.jobName }} - displayName: ${{ parameters.displayName }} - pool: - # testing - vmImage: ${{ parameters.imageName }} - variables: - - group: mscodehub-feed-read-general - - group: mscodehub-feed-read-akv - - group: DotNetPrivateBuildAccess - steps: - - checkout: self - clean: true - - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - patterns: '**/*.nupkg' - path: '$(Pipeline.Workspace)/releasePipeline/finalResults' - - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: metadata - path: '$(Pipeline.Workspace)/releasePipeline/metadata' - - - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self - parameters: - repoRoot: $(Build.SourcesDirectory) - - - pwsh: | - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - - Write-Verbose -Verbose "Capture hosting folder files" - Get-ChildItem '$(Build.SourcesDirectory)/test/hosting' - - # The above cmdlet creates a lower-case nuget.config. There also exists a NuGet.config which we needed to replace. - # Hence the following workaround - - if (-not $IsWindows) { - Move-Item -Path '$(Build.SourcesDirectory)/test/hosting/nuget.config' -Destination '$(Build.SourcesDirectory)/test/hosting/NuGet.Config' -Force -ErrorAction Continue - Write-Verbose -Verbose "Capture hosting folder files after Move-Item" - Get-ChildItem '$(Build.SourcesDirectory)/test/hosting' - } - - if(-not (Test-Path "$(Build.SourcesDirectory)/test/hosting/NuGet.Config")) - { - throw "NuGet.Config is not created" - } - else - { - Write-Verbose -Verbose "Capture NuGet.Config contents" - Get-Content "$(Build.SourcesDirectory)/test/hosting/NuGet.Config" -Raw - } - displayName: Insert internal nuget feed - - - pwsh: | - $dotnetMetadataPath = "$(Build.SourcesDirectory)/DotnetRuntimeMetadata.json" - $dotnetMetadataJson = Get-Content $dotnetMetadataPath -Raw | ConvertFrom-Json - - # Channel is like: $Channel = "5.0.1xx-preview2" - $Channel = $dotnetMetadataJson.sdk.channel - - $sdkVersion = (Get-Content "$(Build.SourcesDirectory)/global.json" -Raw | ConvertFrom-Json).sdk.version - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - - Find-Dotnet - - if(-not (Get-PackageSource -Name 'dotnet' -ErrorAction SilentlyContinue)) - { - $nugetFeed = ([xml](Get-Content $(Build.SourcesDirectory)/nuget.config -Raw)).Configuration.packagesources.add | Where-Object { $_.Key -eq 'dotnet' } | Select-Object -ExpandProperty Value - - if ($nugetFeed) { - Register-PackageSource -Name 'dotnet' -Location $nugetFeed -ProviderName NuGet - Write-Verbose -Message "Register new package source 'dotnet'" -verbose - } - } - - ## Install latest version from the channel - #Install-Dotnet -Channel "$Channel" -Version $sdkVersion - - Start-PSBootstrap - - Write-Verbose -Message "Installing .NET SDK completed." -Verbose - - displayName: Install .NET - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - Start-PSBootstrap - - $localLocation = "$(Pipeline.Workspace)/releasePipeline/finalResults" - $xmlElement = @" - - - - "@ - - $releaseVersion = Get-Content "$(Pipeline.Workspace)/releasePipeline/metadata/release.json" | ConvertFrom-Json | Select-Object -ExpandProperty 'ReleaseVersion' - - Set-Location -Path $(Build.SourcesDirectory)/test/hosting - - Get-ChildItem - - ## register the packages download directory in the nuget file - $nugetConfigContent = Get-Content ./NuGet.Config -Raw - $updateNugetContent = $nugetConfigContent.Replace("", $xmlElement) - - $updateNugetContent | Out-File ./NuGet.Config -Encoding ascii - - Get-Content ./NuGet.Config - - # Add workaround to unblock xUnit testing see issue: https://github.com/dotnet/sdk/issues/26462 - $dotnetPath = if ($IsWindows) { "$env:LocalAppData\Microsoft\dotnet" } else { "$env:HOME/.dotnet" } - $env:DOTNET_ROOT = $dotnetPath - - dotnet --info - dotnet restore - dotnet test /property:RELEASE_VERSION=$releaseVersion --test-adapter-path:. "--logger:xunit;LogFilePath=$(System.DefaultWorkingDirectory)/test-hosting.xml" - - displayName: Restore and execute tests - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - task: PublishTestResults@2 - displayName: 'Publish Test Results **\test-hosting.xml' - inputs: - testResultsFormat: XUnit - testResultsFiles: '**\test-hosting.xml' diff --git a/tools/releaseBuild/azureDevOps/templates/release-SetReleaseTagAndContainerName.yml b/tools/releaseBuild/azureDevOps/templates/release-SetReleaseTagAndContainerName.yml deleted file mode 100644 index 7e88624b45c..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-SetReleaseTagAndContainerName.yml +++ /dev/null @@ -1,26 +0,0 @@ -steps: -- pwsh: | - $variable = 'releaseTag' - $branch = $ENV:BUILD_SOURCEBRANCH - if($branch -notmatch '^.*((release/|rebuild/.*rebuild))') - { - throw "Branch name is not in release format: '$branch'" - } - - $releaseTag = $Branch -replace '^.*((release|rebuild)/)' - $vstsCommandString = "vso[task.setvariable variable=$Variable]$releaseTag" - Write-Verbose -Message "setting $Variable to $releaseTag" -Verbose - Write-Host -Object "##$vstsCommandString" - displayName: Set Release Tag - -- pwsh: | - $azureVersion = '$(ReleaseTag)'.ToLowerInvariant() -replace '\.', '-' - $vstsCommandString = "vso[task.setvariable variable=AzureVersion]$azureVersion" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - - $version = '$(ReleaseTag)'.ToLowerInvariant().Substring(1) - $vstsCommandString = "vso[task.setvariable variable=Version]$version" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Set container name diff --git a/tools/releaseBuild/azureDevOps/templates/release-UpdateDepsJson.yml b/tools/releaseBuild/azureDevOps/templates/release-UpdateDepsJson.yml deleted file mode 100644 index fa42064602e..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-UpdateDepsJson.yml +++ /dev/null @@ -1,71 +0,0 @@ -jobs: -- job: UpdateDepsFiles - displayName: Update deps files - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - variables: - - group: 'Azure Blob variable group' - steps: - - checkout: self - clean: true - - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - patterns: '**/PowerShell*-win-x64.zip' - path: '$(Pipeline.Workspace)/releasePipeline/finalResults' - - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: BuildInfoJson - path: '$(Pipeline.Workspace)/releasePipeline/BuildInfoJson' - - - pwsh: | - $fileName = (Get-Item "$ENV:PIPELINE_WORKSPACE/releasePipeline/BuildInfoJson/*.json").BaseName - if ($fileName -notin 'stable','preview') - { - throw "Unexpected fileName: $fileName" - } - - $vstsCommand = "vso[task.setvariable variable=BlobPrefix]$fileName" - Write-Verbose -Verbose $vstsCommand - Write-Host "##$vstsCommand" - displayName: Determine container name - - - pwsh: | - $zipFile = Get-Item "$ENV:PIPELINE_WORKSPACE/releasePipeline/finalResults/PowerShell*-win-x64.zip" -Exclude *-symbols-* - Write-Verbose -Verbose "zipFile: $zipFile" - Expand-Archive -Path $zipFile -Destination "$ENV:PIPELINE_WORKSPACE/expanded" - - $pwshDepsFile = Get-Item "$ENV:PIPELINE_WORKSPACE/expanded/pwsh.deps.json" - $vstsCommand = "vso[task.setvariable variable=FileToUpload]$pwshDepsFile" - Write-Verbose -Verbose $vstsCommand - Write-Host "##$vstsCommand" - displayName: Determine file to upload - - - task: AzureFileCopy@4 - displayName: 'AzureBlob pwsh.deps.json file Copy' - inputs: - SourcePath: '$(FileToUpload)' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: ps-deps-json - blobPrefix: '$(BlobPrefix)' - retryCountOnTaskFailure: 2 diff --git a/tools/releaseBuild/azureDevOps/templates/release-ValidateFxdPackage.yml b/tools/releaseBuild/azureDevOps/templates/release-ValidateFxdPackage.yml deleted file mode 100644 index 7f2c816a20f..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-ValidateFxdPackage.yml +++ /dev/null @@ -1,92 +0,0 @@ -parameters: - jobName: "" - displayName: "" - imageName: "" - packageNamePattern: "" - use1ES: false - -jobs: -- job: ${{ parameters.jobName }} - displayName: ${{ parameters.displayName }} - variables: - - group: DotNetPrivateBuildAccess - pool: - ${{ if eq(parameters.use1ES, 'false') }}: - vmImage: ${{ parameters.imageName }} - ${{ else }}: - name: 'PS-MSCodeHub-ARM' # add ImageOverride to select image - steps: - - checkout: self - clean: true - - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - patterns: '${{ parameters.packageNamePattern }}' - path: '$(Pipeline.Workspace)/releasePipeline/finalResults' - - - pwsh: | - $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - Start-PSBootstrap - Write-Verbose -Message "Installing .NET SDK completed." -Verbose - displayName: Install .NET - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - Get-ChildItem -Path '$(Pipeline.Workspace)/releasePipeline/finalResults' -Recurse - displayName: Capture downloaded package - - - pwsh: | - $destPath = New-Item '$(Pipeline.Workspace)/releasePipeline/finalResults/fxd' -ItemType Directory - $packageNameFilter = '${{ parameters.packageNamePattern }}' - - if ($packageNameFilter.EndsWith('tar.gz')) { - $package = @(Get-ChildItem -Path '$(Pipeline.Workspace)/releasePipeline/finalResults/*.tar.gz') - Write-Verbose -Verbose "Package: $package" - if ($package.Count -ne 1) { - throw 'Only 1 package was expected.' - } - tar -xvf $package.FullName -C $destPath - } - else { - $package = @(Get-ChildItem -Path '$(Pipeline.Workspace)/releasePipeline/finalResults/*.zip') - Write-Verbose -Verbose "Package: $package" - if ($package.Count -ne 1) { - throw 'Only 1 package was expected.' - } - Expand-Archive -Path $package.FullName -Destination "$destPath" -Verbose - } - displayName: Expand fxd package - - - pwsh: | - $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - Find-Dotnet -SetDotnetRoot - Write-Verbose -Verbose "DOTNET_ROOT: $env:DOTNET_ROOT" - Write-Verbose -Verbose "Check dotnet install" - dotnet --info - Write-Verbose -Verbose "Start test" - $packageNameFilter = '${{ parameters.packageNamePattern }}' - $pwshExeName = if ($packageNameFilter.EndsWith('tar.gz')) { 'pwsh' } else { 'pwsh.exe' } - $pwshPath = Join-Path '$(Pipeline.Workspace)/releasePipeline/finalResults/fxd' $pwshExeName - - if ($IsLinux) { - chmod u+x $pwshPath - } - - $pwshDllPath = Join-Path '$(Pipeline.Workspace)/releasePipeline/finalResults/fxd' 'pwsh.dll' - - $actualOutput = & dotnet $pwshDllPath -c 'Start-ThreadJob -ScriptBlock { "1" } | Wait-Job | Receive-Job' - Write-Verbose -Verbose "Actual output: $actualOutput" - if ($actualOutput -ne 1) { - throw "Actual output is not as expected" - } - displayName: Test package diff --git a/tools/releaseBuild/azureDevOps/templates/release-ValidatePackageBOM.yml b/tools/releaseBuild/azureDevOps/templates/release-ValidatePackageBOM.yml deleted file mode 100644 index 3fd560cbd00..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-ValidatePackageBOM.yml +++ /dev/null @@ -1,49 +0,0 @@ -steps: -- checkout: self - clean: true - -- pwsh: | - Get-ChildItem ENV: - displayName: Capture environment - -- template: release-SetReleaseTagAndContainerName.yml - -- pwsh: | - $name = "{0}_{1:x}" -f '$(releaseTag)', (Get-Date).Ticks - Write-Host $name - Write-Host "##vso[build.updatebuildnumber]$name" - displayName: Set Release Name - -- task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - path: $(System.ArtifactsDirectory) - - -- pwsh: | - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty Name - displayName: Capture Artifact Listing - -- pwsh: | - Install-module Pester -Scope CurrentUser -Force -MaximumVersion 4.99 - displayName: Install Pester - condition: succeededOrFailed() - -- pwsh: | - Import-module './build.psm1' - Import-module './tools/packaging' - $env:PACKAGE_FOLDER = '$(System.ArtifactsDirectory)' - $path = Join-Path -Path $pwd -ChildPath './packageReleaseTests.xml' - $results = invoke-pester -Script './tools/packaging/releaseTests' -OutputFile $path -OutputFormat NUnitXml -PassThru - Write-Host "##vso[results.publish type=NUnit;mergeResults=true;runTitle=Package Release Tests;publishRunAttachments=true;resultFiles=$path;]" - if($results.TotalCount -eq 0 -or $results.FailedCount -gt 0) - { - throw "Package Release Tests failed" - } - displayName: Run packaging release tests diff --git a/tools/releaseBuild/azureDevOps/templates/release-ValidatePackageNames.yml b/tools/releaseBuild/azureDevOps/templates/release-ValidatePackageNames.yml deleted file mode 100644 index 8e41fbc4a55..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-ValidatePackageNames.yml +++ /dev/null @@ -1,93 +0,0 @@ -steps: -- pwsh: | - Get-ChildItem ENV: - displayName: Capture environment - -- template: release-SetReleaseTagAndContainerName.yml - -- pwsh: | - $name = "{0}_{1:x}" -f '$(releaseTag)', (Get-Date).Ticks - Write-Host $name - Write-Host "##vso[build.updatebuildnumber]$name" - displayName: Set Release Name - -- pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/build.psm1' - $azcopy = Find-AzCopy - Write-Verbose -Verbose "Found AzCopy: $azcopy" - - & $azcopy cp https://$(StorageAccount).blob.core.windows.net/$(AzureVersion)/* $(System.ArtifactsDirectory) --recursive - - displayName: Download Azure Artifacts - env: - AZCOPY_AUTO_LOGIN_TYPE: MSI - -- pwsh: | - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty Name - displayName: Capture Artifact Listing - -- pwsh: | - $message = @() - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.rpm | ForEach-Object { - if($_.Name -notmatch 'powershell\-(preview-|lts-)?\d+\.\d+\.\d+(_[a-z]*\.\d+)?-1.(rh|cm).(x86_64|aarch64)\.rpm') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } - } - if($message.count -gt 0){throw ($message | out-string)} - displayName: Validate RPM package names - -- pwsh: | - $message = @() - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.tar.gz | ForEach-Object { - if($_.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?(linux|osx|linux-musl)+\-(x64\-fxdependent|x64|arm32|arm64|x64\-musl-noopt\-fxdependent)\.(tar\.gz)') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } - } - if($message.count -gt 0){throw ($message | out-string)} - displayName: Validate Tar.Gz Package Names - -- pwsh: | - $message = @() - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.pkg | ForEach-Object { - if($_.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?osx(\.10\.12)?\-(x64|arm64)\.pkg') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } - } - if($message.count -gt 0){throw ($message | out-string)} - displayName: Validate PKG Package Names - -- pwsh: | - $message = @() - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -include *.zip, *.msi | ForEach-Object { - if($_.Name -notmatch 'PowerShell-\d+\.\d+\.\d+\-([a-z]*.\d+\-)?win\-(fxdependent|x64|arm64|x86|fxdependentWinDesktop)\.(msi|zip){1}') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } - } - - if($message.count -gt 0){throw ($message | out-string)} - displayName: Validate Zip and MSI Package Names - -- pwsh: | - $message = @() - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.deb | ForEach-Object { - if($_.Name -notmatch 'powershell(-preview|-lts)?_\d+\.\d+\.\d+([\-~][a-z]*.\d+)?-\d\.deb_amd64\.deb') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } - } - if($message.count -gt 0){throw ($message | out-string)} - displayName: Validate Deb Package Names diff --git a/tools/releaseBuild/azureDevOps/templates/release/approvalJob.yml b/tools/releaseBuild/azureDevOps/templates/release/approvalJob.yml deleted file mode 100644 index b34cc4c75b6..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release/approvalJob.yml +++ /dev/null @@ -1,35 +0,0 @@ -parameters: - - name: displayName - type: string - - name: instructions - type: string - - name: jobName - type: string - default: approval - - name: timeoutInMinutes - type: number - # 2 days - default: 2880 - - name: onTimeout - type: string - default: 'reject' - values: - - resume - - reject - - name: dependsOnJob - type: string - default: '' - -jobs: - - job: ${{ parameters.jobName }} - dependsOn: ${{ parameters.dependsOnJob }} - displayName: ${{ parameters.displayName }} - pool: server - timeoutInMinutes: 4320 # job times out in 3 days - steps: - - task: ManualValidation@0 - displayName: ${{ parameters.displayName }} - timeoutInMinutes: ${{ parameters.timeoutInMinutes }} - inputs: - instructions: ${{ parameters.instructions }} - onTimeout: ${{ parameters.onTimeout }} diff --git a/tools/releaseBuild/azureDevOps/templates/shouldSign.yml b/tools/releaseBuild/azureDevOps/templates/shouldSign.yml deleted file mode 100644 index e3c38cb29d5..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/shouldSign.yml +++ /dev/null @@ -1,29 +0,0 @@ -steps: -- powershell: | - $shouldSign = $true - $authenticodeCert = 'CP-230012' - $msixCert = 'CP-230012' - - if($env:IS_DAILY -eq 'true') - { - $authenticodeCert = 'CP-460906' - } - - if($env:SKIP_SIGNING -eq 'Yes') - { - $shouldSign = $false - } - - $vstsCommandString = "vso[task.setvariable variable=SHOULD_SIGN]$($shouldSign.ToString().ToLowerInvariant())" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - - $vstsCommandString = "vso[task.setvariable variable=MSIX_CERT]$($msixCert)" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - - $vstsCommandString = "vso[task.setvariable variable=AUTHENTICODE_CERT]$($authenticodeCert)" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - - displayName: 'Set SHOULD_SIGN Variable' diff --git a/tools/releaseBuild/azureDevOps/templates/sign-build-file.yml b/tools/releaseBuild/azureDevOps/templates/sign-build-file.yml deleted file mode 100644 index a584e15e27c..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/sign-build-file.yml +++ /dev/null @@ -1,328 +0,0 @@ -steps: -- pwsh: | - $platform = '$(runtime)' -match '^linux' ? 'linux' : 'windows' - $vstsCommandString = "vso[task.setvariable variable=ArtifactPlatform]$platform" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Set artifact platform - -- task: DownloadPipelineArtifact@2 - inputs: - artifactName: '$(unsignedBuildArtifactContainer)' - itemPattern: '$(unsignedBuildArtifactName)' - -- pwsh: | - Get-ChildItem "$(Pipeline.Workspace)\*" -Recurse - displayName: 'Capture Downloaded Artifacts' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - -- checkout: self - clean: true - path: $(repoFolder) - -- template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - -- template: cloneToOfficialPath.yml - -- pwsh: | - $zipFileFilter = '$(unsignedBuildArtifactName)' - $zipFileFilter = $zipFileFilter.Replace('**/', '') - - Write-Verbose -Verbose -Message "zipFileFilter = $zipFileFilter" - - Write-Verbose -Verbose -Message "Looking for $(Pipeline.Workspace)\$(unsignedBuildArtifactName)" - - $zipFilePath = Get-ChildItem -Path '$(Pipeline.Workspace)\$(unsignedBuildArtifactName)' -recurse - - if (-not (Test-Path $zipFilePath)) - { - throw "zip file not found: $zipfilePath" - } - - if ($zipFilePath.Count -ne 1) { - Write-Verbose "zip filename" -verbose - $zipFilePath | Out-String | Write-Verbose -Verbose - throw 'multiple zip files found when 1 was expected' - } - - $expandedFolderName = [System.io.path]::GetFileNameWithoutExtension($zipfilePath) - $expandedFolderPath = Join-Path '$(Pipeline.Workspace)' 'expanded' $expandedFolderName - - Write-Verbose -Verbose -Message "Expaning $zipFilePath to $expandedFolderPath" - - New-Item -Path $expandedFolderPath -ItemType Directory - Expand-Archive -Path $zipFilePath -DestinationPath $expandedFolderPath - - if (-not (Test-Path $expandedFolderPath\pwsh.exe) ) { - throw 'zip did not expand as expected' - } - else { - $vstsCommandString = "vso[task.setvariable variable=BinPath]$expandedFolderPath" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - } - - displayName: Expand zip packages - condition: eq(variables['ArtifactPlatform'], 'windows') - -- pwsh: | - $tarPackageName = '$(unsignedBuildArtifactName)' - - Write-Verbose -Verbose -Message "tarPackageName = $tarPackageName" - - $tarPackagePath = Join-Path '$(Pipeline.Workspace)' $tarPackageName - - Write-Verbose -Verbose -Message "Looking for: $tarPackagePath" - - $expandedPathFolderName = $tarPackageName -replace '.tar.gz', '' - $expandedFolderPath = Join-Path '$(Pipeline.Workspace)' 'expanded' $expandedPathFolderName - - if (-not (Test-Path $tarPackagePath)) - { - throw "tar file not found: $tarPackagePath" - } - - Write-Verbose -Verbose -Message "Expanding $tarPackagePath to $expandedFolderPath" - - New-Item -Path $expandedFolderPath -ItemType Directory - tar -xf $tarPackagePath -C $expandedFolderPath - - if (-not (Test-Path $expandedFolderPath/pwsh) ) { - throw 'tar.gz did not expand as expected' - } - else { - $vstsCommandString = "vso[task.setvariable variable=BinPath]$expandedFolderPath" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - } - - Write-Verbose -Verbose "File permisions after expanding" - Get-ChildItem -Path "$expandedFolderPath/pwsh" | Select-Object -Property 'unixmode', 'size', 'name' - displayName: Expand tar.gz packages - condition: eq(variables['ArtifactPlatform'], 'linux') - -- template: insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(PowerShellRoot) - -- pwsh: | - Set-Location $env:POWERSHELLROOT - import-module "$env:POWERSHELLROOT/build.psm1" - Sync-PSTags -AddRemoteIfMissing - displayName: SyncTags - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - -- checkout: ComplianceRepo - clean: true - path: $(complianceRepoFolder) - -- template: shouldSign.yml - -- pwsh: | - $fullSymbolsFolder = '$(BinPath)' - Write-Verbose -Verbose "fullSymbolsFolder == $fullSymbolsFolder" - - Get-ChildItem -Recurse $fullSymbolsFolder | out-string | Write-Verbose -Verbose - - $filesToSignDirectory = "$(System.ArtifactsDirectory)\toBeSigned" - - if ((Test-Path -Path $filesToSignDirectory)) { - Remove-Item -Path $filesToSignDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force - - $signedFilesDirectory = "$(System.ArtifactsDirectory)\signed" - - if ((Test-Path -Path $signedFilesDirectory)) { - Remove-Item -Path $signedFilesDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $signedFilesDirectory -Force - - $itemsToCopyWithRecurse = @( - "$($fullSymbolsFolder)\*.ps1" - "$($fullSymbolsFolder)\Microsoft.PowerShell*.dll" - ) - - $itemsToCopy = @{ - "$($fullSymbolsFolder)\*.ps1" = "" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Host\Microsoft.PowerShell.Host.psd1" = "Modules\Microsoft.PowerShell.Host" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Management\Microsoft.PowerShell.Management.psd1" = "Modules\Microsoft.PowerShell.Management" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Security\Microsoft.PowerShell.Security.psd1" = "Modules\Microsoft.PowerShell.Security" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psd1" = "Modules\Microsoft.PowerShell.Utility" - "$($fullSymbolsFolder)\pwsh.dll" = "" - "$($fullSymbolsFolder)\System.Management.Automation.dll" = "" - } - - ## Windows only modules - - if('$(ArtifactPlatform)' -eq 'windows') { - $itemsToCopy += @{ - "$($fullSymbolsFolder)\pwsh.exe" = "" - "$($fullSymbolsFolder)\Microsoft.Management.Infrastructure.CimCmdlets.dll" = "" - "$($fullSymbolsFolder)\Microsoft.WSMan.*.dll" = "" - "$($fullSymbolsFolder)\Modules\CimCmdlets\CimCmdlets.psd1" = "Modules\CimCmdlets" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Diagnostics.format.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Event.format.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\GetEvent.types.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Security\Security.types.ps1xml" = "Modules\Microsoft.PowerShell.Security" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Microsoft.PowerShell.Diagnostics.psd1" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.WSMan.Management\Microsoft.WSMan.Management.psd1" = "Modules\Microsoft.WSMan.Management" - "$($fullSymbolsFolder)\Modules\Microsoft.WSMan.Management\WSMan.format.ps1xml" = "Modules\Microsoft.WSMan.Management" - "$($fullSymbolsFolder)\Modules\PSDiagnostics\PSDiagnostics.ps?1" = "Modules\PSDiagnostics" - } - } - else { - $itemsToCopy += @{ - "$($fullSymbolsFolder)\pwsh" = "" - } - } - - $itemsToExclude = @( - # This package is retrieved from https://www.github.com/powershell/MarkdownRender - "$($fullSymbolsFolder)\Microsoft.PowerShell.MarkdownRender.dll" - ) - - Write-Verbose -verbose "recusively copying $($itemsToCopyWithRecurse | out-string) to $filesToSignDirectory" - Copy-Item -Path $itemsToCopyWithRecurse -Destination $filesToSignDirectory -Recurse -verbose -exclude $itemsToExclude - - foreach($pattern in $itemsToCopy.Keys) { - $destinationFolder = Join-Path $filesToSignDirectory -ChildPath $itemsToCopy.$pattern - $null = New-Item -ItemType Directory -Path $destinationFolder -Force - Write-Verbose -verbose "copying $pattern to $destinationFolder" - Copy-Item -Path $pattern -Destination $destinationFolder -Recurse -verbose - } - displayName: 'Prepare files to be signed' - -- template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\toBeSigned - signOutputPath: $(System.ArtifactsDirectory)\signed - certificateId: "$(AUTHENTICODE_CERT)" - pattern: | - **\*.dll - **\*.psd1 - **\*.psm1 - **\*.ps1xml - **\*.ps1 - **\*.exe - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Authenticode sign our binaries - -- pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - $signedFilesPath = '$(System.ArtifactsDirectory)\signed\' - $BuildPath = '$(BinPath)' - Write-Verbose -Verbose -Message "BuildPath: $BuildPath" - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - $dlls = Get-ChildItem $BuildPath\*.dll, $BuildPath\*.exe -Recurse - $signatures = $dlls | Get-AuthenticodeSignature - $missingSignatures = $signatures | Where-Object { $_.status -eq 'notsigned' -or $_.SignerCertificate.Issuer -notmatch '^CN=Microsoft.*'}| select-object -ExpandProperty Path - - Write-Verbose -verbose "to be signed:`r`n $($missingSignatures | Out-String)" - - $filesToSignDirectory = "$(System.ArtifactsDirectory)\thirdPartyToBeSigned" - if (Test-Path $filesToSignDirectory) { - Remove-Item -Path $filesToSignDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force -Verbose - - $signedFilesDirectory = "$(System.ArtifactsDirectory)\thirdPartySigned" - if (Test-Path $signedFilesDirectory) { - Remove-Item -Path $signedFilesDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $signedFilesDirectory -Force -Verbose - - $missingSignatures | ForEach-Object { - $pathWithoutLeaf = Split-Path $_ - $relativePath = $pathWithoutLeaf.replace($BuildPath,'') - Write-Verbose -Verbose -Message "relativePath: $relativePath" - $targetDirectory = Join-Path -Path $filesToSignDirectory -ChildPath $relativePath - Write-Verbose -Verbose -Message "targetDirectory: $targetDirectory" - if(!(Test-Path $targetDirectory)) - { - $null = New-Item -ItemType Directory -Path $targetDirectory -Force -Verbose - } - Copy-Item -Path $_ -Destination $targetDirectory - } - - displayName: Create ThirdParty Signing Folder - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - -- template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\thirdPartyToBeSigned - signOutputPath: $(System.ArtifactsDirectory)\thirdPartySigned - certificateId: "CP-231522" - pattern: | - **\*.dll - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign ThirdParty binaries - -- pwsh: | - Get-ChildItem '$(System.ArtifactsDirectory)\thirdPartySigned\*' - displayName: Capture ThirdParty Signed files - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - -- pwsh: | - Import-Module '$(PowerShellRoot)/build.psm1' -Force - Import-Module '$(PowerShellRoot)/tools/packaging' -Force - $signedFilesPath = '$(System.ArtifactsDirectory)\thirdPartySigned' - $BuildPath = '$(BinPath)' - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - if ($env:BuildConfiguration -eq 'minSize') { - ## Remove XML files when making a min-size package. - Remove-Item "$BuildPath/*.xml" -Force - } - displayName: Merge ThirdParty signed files with Build - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - -- pwsh: | - $uploadFolder = '$(BinPath)' - $containerName = '$(signedArtifactContainer)' - - Write-Verbose -Verbose "File permissions after signing" - Get-ChildItem $uploadFolder\pwsh | Select-Object -Property 'unixmode', 'size', 'name' - - $uploadTarFilePath = Join-Path '$(System.ArtifactsDirectory)' '$(signedBuildArtifactName)' - Write-Verbose -Verbose -Message "Creating tar.gz - $uploadTarFilePath" - tar -czvf $uploadTarFilePath -C $uploadFolder * - - Get-ChildItem '$(System.ArtifactsDirectory)' | Out-String | Write-Verbose -Verbose - - Write-Host "##vso[artifact.upload containerfolder=$containerName;artifactname=$containerName]$uploadTarFilePath" - displayName: Upload signed tar.gz files to artifacts - condition: eq(variables['ArtifactPlatform'], 'linux') - retryCountOnTaskFailure: 2 - - -- pwsh: | - $uploadFolder = '$(BinPath)' - $containerName = '$(signedArtifactContainer)' - - Get-ChildItem $uploadFolder -Recurse | Out-String | Write-Verbose -Verbose - - $uploadZipFilePath = Join-Path '$(System.ArtifactsDirectory)' 'PowerShell-$(Version)$(signedBuildArtifactName)' - Write-Verbose -Verbose -Message "Creating zip - $uploadZipFilePath" - Compress-Archive -Path $uploadFolder/* -DestinationPath $uploadZipFilePath -Verbose - - Get-ChildItem '$(System.ArtifactsDirectory)' | Out-String | Write-Verbose -Verbose - - Write-Host "##vso[artifact.upload containerfolder=$containerName;artifactname=$containerName]$uploadZipFilePath" - displayName: Upload signed zip files to artifacts - condition: eq(variables['ArtifactPlatform'], 'windows') - retryCountOnTaskFailure: 2 - - -- template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/signBuildFiles.yml b/tools/releaseBuild/azureDevOps/templates/signBuildFiles.yml deleted file mode 100644 index a7c7c640ce7..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/signBuildFiles.yml +++ /dev/null @@ -1,189 +0,0 @@ -parameters: - binLocation: '' - buildPrefixName: '' - addWindowsModules: 'false' - -steps: -- pwsh: | - $fullSymbolsFolder = Join-Path $(System.ArtifactsDirectory) "${{ parameters.binLocation }}" - - Write-Verbose -Verbose "fullSymbolsFolder == $fullSymbolsFolder" - - Get-ChildItem -Recurse $fullSymbolsFolder | out-string | Write-Verbose -Verbose - - $filesToSignDirectory = "$(System.ArtifactsDirectory)\toBeSigned" - - if ((Test-Path -Path $filesToSignDirectory)) { - Remove-Item -Path $filesToSignDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force - - $signedFilesDirectory = "$(System.ArtifactsDirectory)\signed" - - if ((Test-Path -Path $signedFilesDirectory)) { - Remove-Item -Path $signedFilesDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $signedFilesDirectory -Force - - $itemsToCopyWithRecurse = @( - "$($fullSymbolsFolder)\*.ps1" - "$($fullSymbolsFolder)\Microsoft.PowerShell*.dll" - ) - - $itemsToCopy = @{ - "$($fullSymbolsFolder)\*.ps1" = "" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Host\Microsoft.PowerShell.Host.psd1" = "Modules\Microsoft.PowerShell.Host" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Management\Microsoft.PowerShell.Management.psd1" = "Modules\Microsoft.PowerShell.Management" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Security\Microsoft.PowerShell.Security.psd1" = "Modules\Microsoft.PowerShell.Security" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psd1" = "Modules\Microsoft.PowerShell.Utility" - "$($fullSymbolsFolder)\pwsh.dll" = "" - "$($fullSymbolsFolder)\System.Management.Automation.dll" = "" - } - - ## Windows only modules - - if('${{ parameters.addWindowsModules }}' -ne 'false') { - $itemsToCopy += @{ - "$($fullSymbolsFolder)\pwsh.exe" = "" - "$($fullSymbolsFolder)\Microsoft.Management.Infrastructure.CimCmdlets.dll" = "" - "$($fullSymbolsFolder)\Microsoft.WSMan.*.dll" = "" - "$($fullSymbolsFolder)\Modules\CimCmdlets\CimCmdlets.psd1" = "Modules\CimCmdlets" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Diagnostics.format.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Event.format.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\GetEvent.types.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Security\Security.types.ps1xml" = "Modules\Microsoft.PowerShell.Security" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Microsoft.PowerShell.Diagnostics.psd1" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.WSMan.Management\Microsoft.WSMan.Management.psd1" = "Modules\Microsoft.WSMan.Management" - "$($fullSymbolsFolder)\Modules\Microsoft.WSMan.Management\WSMan.format.ps1xml" = "Modules\Microsoft.WSMan.Management" - "$($fullSymbolsFolder)\Modules\PSDiagnostics\PSDiagnostics.ps?1" = "Modules\PSDiagnostics" - } - } - else { - $itemsToCopy += @{ - "$($fullSymbolsFolder)\pwsh" = "" - } - } - - $itemsToExclude = @( - # This package is retrieved from https://www.github.com/powershell/MarkdownRender - "$($fullSymbolsFolder)\Microsoft.PowerShell.MarkdownRender.dll" - ) - - Write-Verbose -verbose "recusively copying $($itemsToCopyWithRecurse | out-string) to $filesToSignDirectory" - Copy-Item -Path $itemsToCopyWithRecurse -Destination $filesToSignDirectory -Recurse -verbose -exclude $itemsToExclude - - foreach($pattern in $itemsToCopy.Keys) { - $destinationFolder = Join-Path $filesToSignDirectory -ChildPath $itemsToCopy.$pattern - $null = New-Item -ItemType Directory -Path $destinationFolder -Force - Write-Verbose -verbose "copying $pattern to $destinationFolder" - Copy-Item -Path $pattern -Destination $destinationFolder -Recurse -verbose - } - displayName: '${{ parameters.buildPrefixName }} - Prepare files to be signed' - -- template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\toBeSigned - signOutputPath: $(System.ArtifactsDirectory)\signed - certificateId: "$(AUTHENTICODE_CERT)" - pattern: | - **\*.dll - **\*.psd1 - **\*.psm1 - **\*.ps1xml - **\*.ps1 - **\*.exe - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: ${{ parameters.buildPrefixName }} - Authenticode - -- pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - $signedFilesPath = '$(System.ArtifactsDirectory)\signed\' - $BuildPath = Join-Path $(System.ArtifactsDirectory) '${{ parameters.binLocation }}' - Write-Verbose -Verbose -Message "BuildPath: $BuildPath" - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - $dlls = Get-ChildItem $BuildPath\*.dll, $BuildPath\*.exe -Recurse - $signatures = $dlls | Get-AuthenticodeSignature - $missingSignatures = $signatures | Where-Object { $_.status -eq 'notsigned' -or $_.SignerCertificate.Issuer -notmatch '^CN=Microsoft.*'}| select-object -ExpandProperty Path - - Write-Verbose -verbose "to be signed:`r`n $($missingSignatures | Out-String)" - - $filesToSignDirectory = "$(System.ArtifactsDirectory)\thirdPartyToBeSigned" - if (Test-Path $filesToSignDirectory) { - Remove-Item -Path $filesToSignDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force -Verbose - - $signedFilesDirectory = "$(System.ArtifactsDirectory)\thirdPartySigned" - if (Test-Path $signedFilesDirectory) { - Remove-Item -Path $signedFilesDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $signedFilesDirectory -Force -Verbose - - $missingSignatures | ForEach-Object { - $pathWithoutLeaf = Split-Path $_ - $relativePath = $pathWithoutLeaf.replace($BuildPath,'') - Write-Verbose -Verbose -Message "relativePath: $relativePath" - $targetDirectory = Join-Path -Path $filesToSignDirectory -ChildPath $relativePath - Write-Verbose -Verbose -Message "targetDirectory: $targetDirectory" - if(!(Test-Path $targetDirectory)) - { - $null = New-Item -ItemType Directory -Path $targetDirectory -Force -Verbose - } - Copy-Item -Path $_ -Destination $targetDirectory - } - - displayName: ${{ parameters.buildPrefixName }} - Create ThirdParty Signing Folder - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - -- template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\thirdPartyToBeSigned - signOutputPath: $(System.ArtifactsDirectory)\thirdPartySigned - certificateId: "CP-231522" - pattern: | - **\*.dll - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign ThirdParty binaries - -- pwsh: | - Get-ChildItem '$(System.ArtifactsDirectory)\thirdPartySigned\*' - displayName: ${{ parameters.buildPrefixName }} - Capture ThirdParty Signed files - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - -- pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - $signedFilesPath = '$(System.ArtifactsDirectory)\thirdPartySigned' - $BuildPath = Join-Path $(System.ArtifactsDirectory) '${{ parameters.binLocation }}' - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - if ($env:BuildConfiguration -eq 'minSize') { - ## Remove XML files when making a min-size package. - Remove-Item "$BuildPath/*.xml" -Force - } - displayName: ${{ parameters.buildPrefixName }} - Merge ThirdParty signed files with Build - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - -- pwsh: | - $uploadFolder = '$(System.ArtifactsDirectory)/${{ parameters.binLocation }}' - $containerName = 'authenticode-signed' - - Write-Verbose -Verbose "File permissions after signing" - Get-ChildItem $uploadFolder\pwsh | Select-Object -Property 'unixmode', 'size', 'name' - - $uploadTarFilePath = '$(System.ArtifactsDirectory)/${{ parameters.binLocation }}.tar.gz' - Write-Verbose -Verbose -Message "Creating tar.gz - $uploadTarFilePath" - tar -czvf $uploadTarFilePath -C $uploadFolder * - - Write-Host "##vso[artifact.upload containerfolder=$containerName;artifactname=$containerName]$uploadTarFilePath" - displayName: ${{ parameters.buildPrefixName }} - Upload signed files to artifacts - retryCountOnTaskFailure: 2 - diff --git a/tools/releaseBuild/azureDevOps/templates/step/finalize.yml b/tools/releaseBuild/azureDevOps/templates/step/finalize.yml deleted file mode 100644 index 72a677fec9a..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/step/finalize.yml +++ /dev/null @@ -1,5 +0,0 @@ -steps: - - pwsh: | - throw "Jobs with an Issue will not work for release. Please fix the issue and try again." - displayName: Check for SucceededWithIssues - condition: eq(variables['Agent.JobStatus'],'SucceededWithIssues') diff --git a/tools/releaseBuild/azureDevOps/templates/testartifacts.yml b/tools/releaseBuild/azureDevOps/templates/testartifacts.yml deleted file mode 100644 index 43c09236da9..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/testartifacts.yml +++ /dev/null @@ -1,126 +0,0 @@ -jobs: -- job: build_testartifacts_win - variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: DotNetPrivateBuildAccess - displayName: Build windows test artifacts - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - steps: - - checkout: self - clean: true - - - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(Build.SourcesDirectory) - - - pwsh: | - Import-Module ./build.psm1 - Start-PSBootstrap - displayName: Bootstrap - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - Import-Module ./build.psm1 - - function BuildTestPackage([string] $runtime) - { - Write-Verbose -Verbose "Starting to build package for $runtime" - - New-TestPackage -Destination $(System.ArtifactsDirectory) -Runtime $runtime - - if (-not (Test-Path $(System.ArtifactsDirectory)/TestPackage.zip)) - { - throw "Test Package was not found at: $(System.ArtifactsDirectory)" - } - - switch ($runtime) - { - win7-x64 { $packageName = "TestPackage-win-x64.zip" } - win7-x86 { $packageName = "TestPackage-win-x86.zip" } - win-arm64 { $packageName = "TestPackage-win-arm64.zip" } - } - - Rename-Item $(System.ArtifactsDirectory)/TestPackage.zip $packageName - Write-Host "##vso[artifact.upload containerfolder=testArtifacts;artifactname=testArtifacts]$(System.ArtifactsDirectory)/$packageName" - } - - BuildTestPackage -runtime win7-x64 - BuildTestPackage -runtime win7-x86 - BuildTestPackage -runtime win-arm64 - - displayName: Build test package and upload - retryCountOnTaskFailure: 1 - -- job: build_testartifacts_nonwin - variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: DotNetPrivateBuildAccess - displayName: Build non-windows test artifacts - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMSUbuntu20.04-Secure - steps: - - checkout: self - clean: true - - - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(Build.SourcesDirectory) - - - pwsh: | - Import-Module ./build.psm1 - Start-PSBootstrap - displayName: Bootstrap - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - Import-Module ./build.psm1 - - function BuildTestPackage([string] $runtime) - { - Write-Verbose -Verbose "Starting to build package for $runtime" - - New-TestPackage -Destination $(System.ArtifactsDirectory) -Runtime $runtime - - if (-not (Test-Path $(System.ArtifactsDirectory)/TestPackage.zip)) - { - throw "Test Package was not found at: $(System.ArtifactsDirectory)" - } - - switch ($runtime) - { - linux-x64 { $packageName = "TestPackage-linux-x64.zip" } - linux-arm { $packageName = "TestPackage-linux-arm.zip" } - linux-arm64 { $packageName = "TestPackage-linux-arm64.zip" } - osx-x64 { $packageName = "TestPackage-macOS.zip" } - linux-musl-x64 { $packageName = "TestPackage-alpine-x64.zip"} - } - - Rename-Item $(System.ArtifactsDirectory)/TestPackage.zip $packageName - Write-Host "##vso[artifact.upload containerfolder=testArtifacts;artifactname=testArtifacts]$(System.ArtifactsDirectory)/$packageName" - } - - BuildTestPackage -runtime linux-x64 - BuildTestPackage -runtime linux-arm - BuildTestPackage -runtime linux-arm64 - BuildTestPackage -runtime osx-x64 - BuildTestPackage -runtime linux-musl-x64 - - displayName: Build test package and upload - retryCountOnTaskFailure: 1 - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/upload-final-results.yml b/tools/releaseBuild/azureDevOps/templates/upload-final-results.yml deleted file mode 100644 index 596b61fb6ed..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/upload-final-results.yml +++ /dev/null @@ -1,17 +0,0 @@ -parameters: - artifactPath: - artifactFilter: '*' - condition: succeeded() - artifactName: finalResults - -steps: - - powershell: | - Get-ChildItem -Path '${{ parameters.artifactPath }}' -Recurse -File -filter '${{ parameters.artifactFilter }}' -ErrorAction SilentlyContinue | - Select-Object -ExpandProperty FullName | - ForEach-Object { - Write-Host "##vso[artifact.upload containerfolder=${{ parameters.artifactName }};artifactname=${{ parameters.artifactName }}]$_" - } - displayName: Upload ${{ parameters.artifactName }} Artifacts ${{ parameters.artifactFilter }} from ${{ parameters.artifactPath }} - condition: ${{ parameters.condition }} - retryCountOnTaskFailure: 2 - diff --git a/tools/releaseBuild/azureDevOps/templates/upload.yml b/tools/releaseBuild/azureDevOps/templates/upload.yml deleted file mode 100644 index c745a02c2a4..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/upload.yml +++ /dev/null @@ -1,83 +0,0 @@ -parameters: - architecture: x86 - version: 6.2.0 - msi: yes - msix: yes - pdb: no - -steps: -- template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\signed - artifactFilter: PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}*.zip - -- task: AzureFileCopy@4 - displayName: 'upload signed zip to Azure - ${{ parameters.architecture }}' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\signed\PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}.zip' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - resourceGroup: '$(StorageResourceGroup)' - condition: succeeded() - retryCountOnTaskFailure: 2 - -- task: AzureFileCopy@4 - displayName: 'upload signed min-size package (for Guest Config) to Azure - ${{ parameters.architecture }}' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\signed\PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}-gc.zip' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)-gc' - resourceGroup: '$(StorageResourceGroup)' - condition: and(eq('${{ parameters.architecture }}', 'x64'), succeeded()) - retryCountOnTaskFailure: 2 - -- template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\signedPackages - artifactFilter: PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}.exe - condition: and(succeeded(), eq('${{ parameters.msi }}', 'yes')) - -- task: AzureFileCopy@4 - displayName: 'upload signed exe to Azure - ${{ parameters.architecture }}' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\signedPackages\PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}.exe' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)-private' - resourceGroup: '$(StorageResourceGroup)' - condition: and(succeeded(), eq('${{ parameters.msi }}', 'yes')) - retryCountOnTaskFailure: 2 - -# Disable upload task as the symbols package is not currently used and we want to avoid publishing this in releases -#- task: AzureFileCopy@4 -# displayName: 'upload pbd zip to Azure - ${{ parameters.architecture }}' -# inputs: -# SourcePath: '$(System.ArtifactsDirectory)\signed\PowerShell-Symbols-${{ parameters.version }}-win-${{ parameters.architecture }}.zip' -# azureSubscription: '$(AzureFileCopySubscription)' -# Destination: AzureBlob -# storage: '$(StorageAccount)' -# ContainerName: '$(AzureVersion)' -# condition: and(succeeded(), eq('${{ parameters.pdb }}', 'yes')) - -- template: upload-final-results.yml - parameters: - artifactPath: $(Build.StagingDirectory)\signedPackages - artifactFilter: PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}.msix - condition: and(succeeded(), eq('${{ parameters.msix }}', 'yes')) - -- task: AzureFileCopy@4 - displayName: 'upload signed msix to Azure - ${{ parameters.architecture }}' - inputs: - SourcePath: '$(Build.StagingDirectory)\signedPackages\PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}.msix' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)-private' - resourceGroup: '$(StorageResourceGroup)' - condition: and(succeeded(), eq('${{ parameters.msix }}', 'yes'), eq(variables['SHOULD_SIGN'], 'true')) - retryCountOnTaskFailure: 2 diff --git a/tools/releaseBuild/azureDevOps/templates/vpackReleaseJob.yml b/tools/releaseBuild/azureDevOps/templates/vpackReleaseJob.yml deleted file mode 100644 index 83779c75aa0..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/vpackReleaseJob.yml +++ /dev/null @@ -1,113 +0,0 @@ -parameters: - architecture: x64 - -jobs: -- job: vpack_${{ parameters.architecture }} - variables: - - group: vPack - - group: ReleasePipelineSecrets - - displayName: Build and Publish VPack - ${{ parameters.architecture }} - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - steps: - - checkout: self - clean: true - - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - packageType: sdk - version: 3.1.x - installationPath: $(Agent.ToolsDirectory)/dotnet - - - template: ./SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/build.psm1' - Install-AzCopy - displayName: Install AzCopy - retryCountOnTaskFailure: 2 - - - pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/build.psm1' - $azcopy = Find-AzCopy - Write-Verbose -Verbose "Found AzCopy: $azcopy" - - Write-Host "running: $azcopy cp https://$(StorageAccount).blob.core.windows.net/$(AzureVersion)/PowerShell-$(Version)-win-${{ parameters.architecture }}.zip $(System.ArtifactsDirectory)" - - & $azcopy cp https://$(StorageAccount).blob.core.windows.net/$(AzureVersion)/PowerShell-$(Version)-win-${{ parameters.architecture }}.zip $(System.ArtifactsDirectory) - displayName: 'Download Azure Artifacts' - retryCountOnTaskFailure: 2 - env: - AZCOPY_AUTO_LOGIN_TYPE: MSI - - - pwsh: 'Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty Name' - displayName: 'Capture Artifact Listing' - - - pwsh: | - $message = @() - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -include *.zip, *.msi | ForEach-Object { - if($_.Name -notmatch 'PowerShell-\d+\.\d+\.\d+\-([a-z]*.\d+\-)?win\-(fxdependent|x64|arm64|x86|fxdependentWinDesktop)\.(msi|zip){1}') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } - } - - if($message.count -gt 0){throw ($message | out-string)} - displayName: 'Validate Zip and MSI Package Names' - - - pwsh: | - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -include *.zip, *.msi | ForEach-Object { - if($_.Name -match 'PowerShell-\d+\.\d+\.\d+\-([a-z]*.\d+\-)?win\-(${{ parameters.architecture }})\.(zip){1}') - { - $destDir = "$(System.ArtifactsDirectory)\vpack${{ parameters.architecture }}" - $null = new-item -ItemType Directory -Path $destDir - Expand-Archive -Path $_.FullName -DestinationPath $destDir - $vstsCommandString = "vso[task.setvariable variable=vpackDir]$destDir" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - } - } - displayName: 'Extract Zip' - - - pwsh: | - $vpackVersion = '$(version)' - - if('$(VPackPublishOverride)' -ne '' -and '$(VPackPublishOverride)' -ne 'None' ) - { - Write-Host "Using VPackPublishOverride varabile" - $vpackVersion = '$(VPackPublishOverride)' - } - - $vstsCommandString = "vso[task.setvariable variable=vpackVersion]$vpackVersion" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: 'Set vpackVersion' - - - pwsh: | - Get-ChildItem -Path env: - displayName: Capture Environment - condition: succeededOrFailed() - - - task: PkgESVPack@12 - displayName: 'Package ES - VPack ' - inputs: - sourceDirectory: '$(vpackDir)' - description: PowerShell ${{ parameters.architecture }} $(version) - pushPkgName: 'PowerShell.${{ parameters.architecture }}' - configurations: Release - platforms: x64 - target: '$(System.ArtifactsDirectory)' - owner: tplunk - provData: true - version: '$(vpackVersion)' - vpackToken: $(vPackPat) - condition: and(succeeded(), eq(variables['Build.Reason'], 'Manual')) diff --git a/tools/releaseBuild/azureDevOps/templates/windows-component-governance.yml b/tools/releaseBuild/azureDevOps/templates/windows-component-governance.yml deleted file mode 100644 index 53947655d90..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/windows-component-governance.yml +++ /dev/null @@ -1,71 +0,0 @@ - -jobs: -- job: ComponentRegistrationJob - variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - displayName: Component Registration - condition: succeeded() - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - checkout: self - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - powershell: | - docker container prune --force - docker container ls --all --format '{{ json .ID }}' | ConvertFrom-Json | ForEach-Object {docker container rm --force --volumes $_} - displayName: 'Remove all containers' - # Cleanup is not critical it passes every time it runs - continueOnError: true - - - powershell: | - docker image ls --format '{{ json .}}'|ConvertFrom-Json| ForEach-Object { - if($_.tag -eq '') - { - $formatString = 'yyyy-MM-dd HH:mm:ss zz00' - $createdAtString = $_.CreatedAt.substring(0,$_.CreatedAt.Length -4) - $createdAt = [DateTime]::ParseExact($createdAtString, $formatString,[System.Globalization.CultureInfo]::InvariantCulture) - if($createdAt -lt (Get-Date).adddays(-1)) - { - docker image rm $_.ID - } - } - } - exit 0 - displayName: 'Remove old images' - # Cleanup is not critical it passes every time it runs - continueOnError: true - - - powershell: | - Write-verbose "--docker info---" -verbose - docker info - Write-verbose "--docker image ls---" -verbose - docker image ls - Write-verbose "--docker container ls --all---" -verbose - docker container ls --all - displayName: 'Capture Docker Info' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - - - template: insert-nuget-config-azfeed.yml - - - powershell: | - ./tools/releaseBuild/vstsbuild.ps1 -ReleaseTag $(ReleaseTagVar) -Name win-x64-component-registration - displayName: 'Build Windows Universal - Component Registration' - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(componentregistration)' - snapshotForceEnabled: true diff --git a/tools/releaseBuild/azureDevOps/templates/windows-hosted-build.yml b/tools/releaseBuild/azureDevOps/templates/windows-hosted-build.yml deleted file mode 100644 index 4b36f6f396e..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/windows-hosted-build.yml +++ /dev/null @@ -1,84 +0,0 @@ -parameters: - - name: BuildConfiguration - default: release - - name: BuildPlatform - default: any cpu - - name: Architecture - default: x64 - - name: parentJob - default: '' - -jobs: -- job: build_windows_${{ parameters.Architecture }}_${{ parameters.BuildConfiguration }} - displayName: Build Windows - ${{ parameters.Architecture }} ${{ parameters.BuildConfiguration }} - condition: succeeded() - dependsOn: ${{ parameters.parentJob }} - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: BuildConfiguration - value: ${{ parameters.BuildConfiguration }} - - name: BuildPlatform - value: ${{ parameters.BuildPlatform }} - - name: Architecture - value: ${{ parameters.Architecture }} - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE - value: 1 - - group: DotNetPrivateBuildAccess - - steps: - - - checkout: self - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: cloneToOfficialPath.yml - - - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(PowerShellRoot) - - - pwsh: | - - $runtime = switch ($env:Architecture) - { - "x64" { "win7-x64" } - "x86" { "win7-x86" } - "arm64" { "win-arm64" } - "fxdependent" { "fxdependent" } - "fxdependentWinDesktop" { "fxdependent-win-desktop" } - } - - $params = @{} - if ($env:BuildConfiguration -eq 'minSize') { - $params['ForMinimalSize'] = $true - } - - tools/releaseBuild/Images/microsoft_powershell_windowsservercore/PowerShellPackage.ps1 -location '$(PowerShellRoot)' -destination '$(Build.ArtifactStagingDirectory)/Symbols_$(Architecture)' -Runtime $runtime -ReleaseTag '$(ReleaseTagVar)' -Symbols @params - displayName: 'Build Windows Universal - $(Architecture)-$(BuildConfiguration) Symbols zip' - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - $packageName = (Get-ChildItem '$(Build.ArtifactStagingDirectory)\Symbols_$(Architecture)').FullName - $vstsCommandString = "vso[artifact.upload containerfolder=results;artifactname=results]$packageName" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Upload symbols package - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(PowerShellRoot)\tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/windows-package-signing.yml b/tools/releaseBuild/azureDevOps/templates/windows-package-signing.yml deleted file mode 100644 index 75153ce0592..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/windows-package-signing.yml +++ /dev/null @@ -1,132 +0,0 @@ -parameters: - parentJobs: [] - -jobs: -- job: WinPackageSigningJob - displayName: Windows Package signing and upload - dependsOn: - ${{ parameters.parentJobs }} - condition: succeeded() - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - variables: - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE - value: 1 - - group: ESRP - - name: repoFolder - value: PowerShell - - name: repoRoot - value: $(Agent.BuildDirectory)\$(repoFolder) - - name: complianceRepoFolder - value: compliance - - steps: - - checkout: self - clean: true - path: $(repoFolder) - - - checkout: ComplianceRepo - clean: true - path: $(complianceRepoFolder) - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: shouldSign.yml - - - task: DownloadBuildArtifacts@0 - displayName: 'Download artifacts' - inputs: - buildType: current - downloadType: single - artifactName: signed - downloadPath: '$(System.ArtifactsDirectory)' - - - powershell: | - dir "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Downloaded Artifacts' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\signed - signOutputPath: $(Build.StagingDirectory)\signedPackages - certificateId: $(MSIX_CERT) - pattern: | - **\*.msix - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign msix - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\signed - signOutputPath: $(Build.StagingDirectory)\signedPackages - certificateId: $(AUTHENTICODE_CERT) - pattern: | - **\*.exe - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign exe - - - powershell: | - new-item -itemtype Directory -path '$(Build.StagingDirectory)\signedPackages' - Get-ChildItem "$(System.ArtifactsDirectory)\signed\PowerShell-$(Version)-win-*.msi*" | copy-item -Destination '$(Build.StagingDirectory)\signedPackages' - displayName: 'Fake msi* Signing' - condition: and(succeeded(), ne(variables['SHOULD_SIGN'], 'true')) - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\signed\PowerShell-$(Version)-win-*.exe" | copy-item -Destination '$(Build.StagingDirectory)\signedPackages' - displayName: 'Fake exe Signing' - condition: and(succeeded(), ne(variables['SHOULD_SIGN'], 'true')) - - - template: upload.yml - parameters: - architecture: x86 - version: $(version) - - - template: upload.yml - parameters: - architecture: x64 - version: $(version) - pdb: yes - - - template: upload.yml - parameters: - architecture: arm64 - version: $(version) - msi: yes - - - template: upload.yml - parameters: - architecture: fxdependent - version: $(version) - msi: no - msix: no - - - template: upload.yml - parameters: - architecture: fxdependentWinDesktop - version: $(version) - msi: no - msix: no - - - template: EsrpScan.yml@ComplianceRepo - parameters: - scanPath: $(Build.StagingDirectory) - pattern: | - **\*.msix - **\*.msi - **\*.zip - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(repoRoot)\tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/windows-packaging.yml b/tools/releaseBuild/azureDevOps/templates/windows-packaging.yml deleted file mode 100644 index 915db9301ac..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/windows-packaging.yml +++ /dev/null @@ -1,369 +0,0 @@ -parameters: - - name: BuildConfiguration - default: release - - name: BuildPlatform - default: any cpu - - name: Architecture - default: x64 - - name: parentJob - default: '' - -jobs: -- job: sign_windows_${{ parameters.Architecture }}_${{ parameters.BuildConfiguration }} - displayName: Package Windows - ${{ parameters.Architecture }} ${{ parameters.BuildConfiguration }} - condition: succeeded() - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - variables: - - name: BuildConfiguration - value: ${{ parameters.BuildConfiguration }} - - name: BuildPlatform - value: ${{ parameters.BuildPlatform }} - - name: Architecture - value: ${{ parameters.Architecture }} - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE - value: 1 - - group: ESRP - - group: DotNetPrivateBuildAccess - - steps: - - - checkout: self - clean: true - - - checkout: ComplianceRepo - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: shouldSign.yml - - - pwsh: | - $pkgFilter = '$(Architecture)' - if ($env:BuildConfiguration -eq 'minSize') { $pkgFilter += '-gc' } - - $vstsCommandString = "vso[task.setvariable variable=PkgFilter]$pkgFilter" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Set packageName variable - - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: 'results' - itemPattern: '**/*$(PkgFilter).zip' - downloadPath: '$(System.ArtifactsDirectory)\Symbols' - - - template: cloneToOfficialPath.yml - - - pwsh: | - $zipPathString = '$(System.ArtifactsDirectory)\Symbols\results\*$(PkgFilter).zip' - Write-Verbose -Verbose "Zip Path: $zipPathString" - $zipPath = Get-Item $zipPathString - if(@($zipPath).Count -eq 0) { - throw "No files found at '$zipPathString'" - } - elseif(@($zipPath).Count -ne 1) { - $names = $zipPath.Name -join "', '" - throw "multiple files '${names}' found with '${zipPathString}'" - } - - $expandedFolder = $zipPath.BaseName - Write-Host "sending.. vso[task.setvariable variable=SymbolsFolder]$expandedFolder" - Write-Host "##vso[task.setvariable variable=SymbolsFolder]$expandedFolder" - - Expand-Archive -Path $zipPath -Destination "$(System.ArtifactsDirectory)\$expandedFolder" -Force - displayName: Expand symbols zip - - - pwsh: | - $fullSymbolsFolder = "$(System.ArtifactsDirectory)\$($env:SYMBOLSFOLDER)" - - $filesToSignDirectory = "$(System.ArtifactsDirectory)\toBeSigned" - $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force - - $signedFilesDirectory = "$(System.ArtifactsDirectory)\signed" - $null = New-Item -ItemType Directory -Path $signedFilesDirectory -Force - - $itemsToCopyWithRecurse = @( - "$($fullSymbolsFolder)\*.ps1" - "$($fullSymbolsFolder)\Microsoft.PowerShell*.dll" - ) - - $itemsToCopy = @{ - "$($fullSymbolsFolder)\*.ps1" = "" - "$($fullSymbolsFolder)\Microsoft.Management.Infrastructure.CimCmdlets.dll" = "" - "$($fullSymbolsFolder)\Microsoft.WSMan.*.dll" = "" - "$($fullSymbolsFolder)\Modules\CimCmdlets\CimCmdlets.psd1" = "Modules\CimCmdlets" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Diagnostics.format.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Event.format.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\GetEvent.types.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Microsoft.PowerShell.Diagnostics.psd1" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Host\Microsoft.PowerShell.Host.psd1" = "Modules\Microsoft.PowerShell.Host" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Management\Microsoft.PowerShell.Management.psd1" = "Modules\Microsoft.PowerShell.Management" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Security\Microsoft.PowerShell.Security.psd1" = "Modules\Microsoft.PowerShell.Security" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Security\Security.types.ps1xml" = "Modules\Microsoft.PowerShell.Security" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psd1" = "Modules\Microsoft.PowerShell.Utility" - "$($fullSymbolsFolder)\Modules\Microsoft.WSMan.Management\Microsoft.WSMan.Management.psd1" = "Modules\Microsoft.WSMan.Management" - "$($fullSymbolsFolder)\Modules\Microsoft.WSMan.Management\WSMan.format.ps1xml" = "Modules\Microsoft.WSMan.Management" - "$($fullSymbolsFolder)\Modules\PSDiagnostics\PSDiagnostics.ps?1" = "Modules\PSDiagnostics" - "$($fullSymbolsFolder)\pwsh.dll" = "" - "$($fullSymbolsFolder)\System.Management.Automation.dll" = "" - "$($fullSymbolsFolder)\pwsh.exe" = "" - } - - $itemsToExclude = @( - # This package is retrieved from https://www.github.com/powershell/MarkdownRender - "$($fullSymbolsFolder)\Microsoft.PowerShell.MarkdownRender.dll" - ) - - Write-Verbose -verbose "recusively copying $($itemsToCopyWithRecurse | out-string) to $filesToSignDirectory" - Copy-Item -Path $itemsToCopyWithRecurse -Destination $filesToSignDirectory -Recurse -verbose -exclude $itemsToExclude - - foreach($pattern in $itemsToCopy.Keys) { - $destinationFolder = Join-Path $filesToSignDirectory -ChildPath $itemsToCopy.$pattern - $null = New-Item -ItemType Directory -Path $destinationFolder -Force - Write-Verbose -verbose "copying $pattern to $destinationFolder" - Copy-Item -Path $pattern -Destination $destinationFolder -Recurse -verbose - } - displayName: 'Prepare files to be signed' - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\toBeSigned - signOutputPath: $(System.ArtifactsDirectory)\signed - certificateId: "$(AUTHENTICODE_CERT)" - pattern: | - **\*.dll - **\*.psd1 - **\*.psm1 - **\*.ps1xml - **\*.ps1 - **\*.exe - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign our binaries - - - pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - $signedFilesPath = '$(System.ArtifactsDirectory)\signed\' - $BuildPath = '$(System.ArtifactsDirectory)\$(SymbolsFolder)' - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - $dlls = Get-ChildItem $BuildPath\*.dll, $BuildPath\*.exe -Recurse - $signatures = $dlls | Get-AuthenticodeSignature - $missingSignatures = $signatures | Where-Object { $_.status -eq 'notsigned' -or $_.SignerCertificate.Issuer -notmatch '^CN=Microsoft.*'}| select-object -ExpandProperty Path - - Write-Verbose -verbose "to be signed:`r`n $($missingSignatures | Out-String)" - - $filesToSignDirectory = "$(System.ArtifactsDirectory)\thirdPartyToBeSigned" - $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force - - $signedFilesDirectory = "$(System.ArtifactsDirectory)\thirdPartySigned" - $null = New-Item -ItemType Directory -Path $signedFilesDirectory -Force - - $missingSignatures | ForEach-Object { - $pathWithoutLeaf = Split-Path $_ - $relativePath = $pathWithoutLeaf.replace($BuildPath,'') - $targetDirectory = Join-Path -Path $filesToSignDirectory -ChildPath $relativePath - if(!(Test-Path $targetDirectory)) - { - $null = New-Item -ItemType Directory -Path $targetDirectory -Force - } - Copy-Item -Path $_ -Destination $targetDirectory - } - - displayName: Create ThirdParty Signing Folder - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\thirdPartyToBeSigned - signOutputPath: $(System.ArtifactsDirectory)\thirdPartySigned - certificateId: "CP-231522" - pattern: | - **\*.dll - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign ThirdParty binaries - - - pwsh: | - Get-ChildItem '$(System.ArtifactsDirectory)\thirdPartySigned\*' - displayName: Capture ThirdParty Signed files - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - $signedFilesPath = '$(System.ArtifactsDirectory)\thirdPartySigned' - $BuildPath = '$(System.ArtifactsDirectory)\$(SymbolsFolder)' - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - if ($env:BuildConfiguration -eq 'minSize') { - ## Remove XML files when making a min-size package. - Remove-Item "$BuildPath/*.xml" -Force - } - displayName: Merge ThirdParty signed files with Build - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)\$(SymbolsFolder)' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - PackageName: PowerShell Windows ${{ parameters.Architecture }} ${{ parameters.BuildConfiguration }} - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)\tools' - - - pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - - $destFolder = '$(System.ArtifactsDirectory)\signedZip' - $BuildPath = '$(System.ArtifactsDirectory)\$(SymbolsFolder)' - - New-Item -ItemType Directory -Path $destFolder -Force - - $BuildPackagePath = New-PSBuildZip -BuildPath $BuildPath -DestinationFolder $destFolder - - Write-Verbose -Verbose "New-PSSignedBuildZip returned `$BuildPackagePath as: $BuildPackagePath" - Write-Host "##vso[artifact.upload containerfolder=results;artifactname=results]$BuildPackagePath" - - $vstsCommandString = "vso[task.setvariable variable=BuildPackagePath]$BuildPackagePath" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Compress signed files - retryCountOnTaskFailure: 2 - - - - pwsh: | - $runtime = switch ($env:Architecture) - { - "x64" { "win7-x64" } - "x86" { "win7-x86" } - "arm64" { "win-arm64" } - "fxdependent" { "fxdependent" } - "fxdependentWinDesktop" { "fxdependent-win-desktop" } - } - - $signedPkg = "$(BuildPackagePath)" - Write-Verbose -Verbose -Message "signedPkg = $signedPkg" - - $params = @{} - if ($env:BuildConfiguration -eq 'minSize') { - $params['ForMinimalSize'] = $true - } - - $(PowerShellRoot)/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/PowerShellPackage.ps1 -BuildZip $signedPkg -location '$(PowerShellRoot)' -destination '$(System.ArtifactsDirectory)\pkgSigned' -Runtime $runtime -ReleaseTag '$(ReleaseTagVar)' @params - displayName: 'Build Windows Universal - $(Architecture) Package' - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - Get-ChildItem '$(System.ArtifactsDirectory)\pkgSigned' | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=signed;artifactname=signed]$packagePath" - } - displayName: Upload unsigned packages - retryCountOnTaskFailure: 2 - - - ${{ if and(ne(variables['BuildConfiguration'],'minSize'), in(variables['Architecture'], 'x64', 'x86', 'arm64')) }}: - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\pkgSigned - signOutputPath: $(Build.StagingDirectory)\signedPackages - certificateId: "$(AUTHENTICODE_CERT)" - pattern: | - **\*.msi - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign MSI - alwaysCopy: true - - - pwsh: | - Get-ChildItem '$(System.ArtifactsDirectory)\signedPackages' | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=finalResults;artifactname=finalResults]$packagePath" - } - displayName: Upload signed MSI to finalResults - retryCountOnTaskFailure: 2 - - - task: AzureFileCopy@4 - displayName: 'upload signed msi to Azure - ${{ parameters.architecture }}' - inputs: - SourcePath: '$(Build.StagingDirectory)\signedPackages\PowerShell-$(version)-win-${{ parameters.architecture }}.msi' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - resourceGroup: '$(StorageResourceGroup)' - retryCountOnTaskFailure: 2 - - - pwsh: | - cd $(PowerShellRoot) - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - - $msiPath = '$(Build.StagingDirectory)\signedPackages\PowerShell-$(version)-win-${{ parameters.architecture }}.msi' - - New-ExePackage -ProductVersion '$(version)' -MsiLocationPath $msiPath -ProductTargetArchitecture ${{ parameters.architecture }} - $exePath = Get-ChildItem '.\PowerShell-*.exe' | Select-Object -First 1 -ExpandProperty fullname - $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe - # Expand Burn Engine so we can sign it. - Expand-ExePackageEngine -ExePath $exePath -EnginePath $enginePath - displayName: Create exe wrapper - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\unsignedEngine - signOutputPath: $(System.ArtifactsDirectory)\signedEngine - certificateId: "$(AUTHENTICODE_CERT)" - pattern: | - **\*.exe - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign Burn Engine - alwaysCopy: true - - - pwsh: | - cd '$(PowerShellRoot)' - Import-Module '$(PowerShellRoot)/build.psm1' -Force - Import-Module '$(PowerShellRoot)/tools/packaging' -Force - - $exePath = Get-ChildItem '.\PowerShell-*.exe' | Select-Object -First 1 -ExpandProperty fullname - $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\signedEngine' -ChildPath engine.exe - $enginePath | Get-AuthenticodeSignature | out-string | Write-Verbose -verbose - Compress-ExePackageEngine -ExePath $exePath -EnginePath $enginePath - displayName: Re-attach the signed Burn engine in exe wrapper - - - pwsh: | - cd '$(PowerShellRoot)' - Get-ChildItem '.\PowerShell-*.exe' | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=signed;artifactname=signed]$packagePath" - } - displayName: Upload unsigned exe - retryCountOnTaskFailure: 2 - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(PowerShellRoot)\tools' - snapshotForceEnabled: true - - - pwsh: | - if ((Test-Path "\PowerShell")) { - Remove-Item -Path "\PowerShell" -Force -Recurse -Verbose - } - else { - Write-Verbose -Verbose -Message "No cleanup required." - } - displayName: Clean up local Clone - condition: always() - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/vpackRelease.yml b/tools/releaseBuild/azureDevOps/vpackRelease.yml deleted file mode 100644 index 14368ffb8f8..00000000000 --- a/tools/releaseBuild/azureDevOps/vpackRelease.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: vpack-$(Build.BuildId) -trigger: - branches: - include: - - master - - release* -pr: - branches: - include: - - master - - release* - -variables: - - name: DOTNET_CLI_TELEMETRY_OPTOUT - value: 1 - - name: POWERSHELL_TELEMETRY_OPTOUT - value: 1 - - name: nugetMultiFeedWarnLevel - value: none - - - group: Azure Blob variable group - # adds the pat to publish the vPack - # instructions to create are in the description of the library - - group: vPack - -stages: -- stage: prep - displayName: Create buildInfo and name the Pipeline - jobs: - - job: rename - displayName: Name the build - condition: succeeded() - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - checkout: self - clean: true - - - template: ./templates/SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no - - - powershell: | - if($env:RELEASETAGVAR -match '-') { - throw "Don't release a preview build without coordinating with Windows Engineering Build Tools Team" - } - displayName: Stop any preview release - - - powershell: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhss"))" - displayName: Set Build Name for Non-PR - condition: ne(variables['Build.Reason'], 'PullRequest') - -- stage: release - displayName: Release - jobs: - - template: ./templates/vpackReleaseJob.yml - parameters: - architecture: x64 - - - template: ./templates/vpackReleaseJob.yml - parameters: - architecture: x86 - - - template: ./templates/vpackReleaseJob.yml - parameters: - architecture: arm64 diff --git a/tools/releaseBuild/build.json b/tools/releaseBuild/build.json deleted file mode 100644 index fe2f9d96f17..00000000000 --- a/tools/releaseBuild/build.json +++ /dev/null @@ -1,336 +0,0 @@ -{ - "Windows": [ - { - "Name": "win7-x64", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x64 -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\DockerFile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "release", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win7-x86", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x86 -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "release", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-x64-component-registration", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x64 -ReleaseTag _ReleaseTag_ -ComponentRegistration", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "componentregistration", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-x64-symbols", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x64 -ReleaseTag _ReleaseTag_ -Symbols", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "Symbols_x64", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-x86-symbols", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x86 -ReleaseTag _ReleaseTag_ -Symbols", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "Symbols_x86", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-arm-symbols", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win-arm -ReleaseTag _ReleaseTag_ -Symbols", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "Symbols_arm", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-arm64-symbols", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win-arm64 -ReleaseTag _ReleaseTag_ -Symbols", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "Symbols_arm64", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-x64-package", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -BuildZip _RepoDestinationPath_\\_BuildPackageName_ -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x64 -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "signed", - "ArtifactsExpected": 4, - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-x86-package", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -BuildZip _RepoDestinationPath_\\_BuildPackageName_ -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x86 -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "signed", - "ArtifactsExpected": 4, - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-arm-package", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -BuildZip _RepoDestinationPath_\\_BuildPackageName_ -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win-arm -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "signed", - "ArtifactsExpected": 2, - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-arm64-package", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -BuildZip _RepoDestinationPath_\\_BuildPackageName_ -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win-arm64 -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "signed", - "ArtifactsExpected": 2, - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-fxdependent-symbols", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime fxdependent -ReleaseTag _ReleaseTag_ -Symbols", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "Symbols_fxdependent", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-fxdependent-package", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -BuildZip _RepoDestinationPath_\\_BuildPackageName_ -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime fxdependent -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "signed", - "ArtifactsExpected": 1, - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-fxdependentWinDesktop-symbols", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime fxdependent-win-desktop -ReleaseTag _ReleaseTag_ -Symbols", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "Symbols_fxdependentWinDesktop", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-fxdependentWinDesktop-package", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -BuildZip _RepoDestinationPath_\\_BuildPackageName_ -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime fxdependent-win-desktop -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "signed", - "ArtifactsExpected": 1, - "EnableFeature": [ "ArtifactAsFolder" ] - } - ], - "Linux": [ - { - "Name": "deb", - "RepoDestinationPath": "/PowerShell", - "BuildCommand": "/PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -ReleaseTag _ReleaseTag_ -TarX64 -TarArm -TarArm64 -TarMinSize", - "DockerFile": "./tools/releaseBuild/Images/microsoft_powershell_ubuntu18.04/Dockerfile", - "AdditionalContextFiles" :[ "./tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1"], - "DockerImageName": "ps-ubunutu-18-04", - "BinaryBucket": "release", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "rpm", - "RepoDestinationPath": "/PowerShell", - "BuildCommand": "/PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -ReleaseTag _ReleaseTag_", - "AdditionalContextFiles" :[ "./tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1"], - "DockerFile": "./tools/releaseBuild/Images/microsoft_powershell_centos7/Dockerfile", - "DockerImageName": "ps-centos-7", - "BinaryBucket": "release", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "alpine", - "RepoDestinationPath": "/PowerShell", - "BuildCommand": "/PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -ReleaseTag _ReleaseTag_ -Alpine", - "AdditionalContextFiles" :[ "./tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1"], - "DockerFile": "./tools/releaseBuild/Images/microsoft_powershell_alpine3/Dockerfile", - "DockerImageName": "ps-alpine-3", - "BinaryBucket": "release", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "fxdependent", - "RepoDestinationPath": "/PowerShell", - "BuildCommand": "/PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -ReleaseTag _ReleaseTag_ -FxDependent", - "AdditionalContextFiles" :[ "./tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1"], - "DockerFile": "./tools/releaseBuild/Images/microsoft_powershell_centos7/Dockerfile", - "DockerImageName": "ps-centos-7", - "BinaryBucket": "release", - "EnableFeature": [ "ArtifactAsFolder" ] - } - ] -} diff --git a/tools/releaseBuild/createComplianceFolder.ps1 b/tools/releaseBuild/createComplianceFolder.ps1 deleted file mode 100644 index c462a09ebdb..00000000000 --- a/tools/releaseBuild/createComplianceFolder.ps1 +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -param( - [Parameter(HelpMessage="Artifact folder to find compliance files in.")] - [string[]] - $ArtifactFolder, - [Parameter(HelpMessage="VSTS Variable to set path to complinance Files.")] - [string] - $VSTSVariableName -) - -$compliancePath = $null -foreach($folder in $ArtifactFolder) -{ - # Find Symbols zip which contains compliance files - Write-Host "ArtifactFolder: $folder" - $filename = Join-Path -Path $folder -ChildPath 'symbols.zip' - - $parentName = Split-Path -Path $folder -Leaf - - # Use simplified names because some of the compliance tools didn't like the full names - # decided not to use hashes because the names need to be consistent otherwise the tool also has issues - # which is another problem with the full name, it includes version. - if ($parentName -match 'x64' -or $parentName -match 'amd64') - { - $name = 'x64' - } - elseif ($parentName -match 'x86') { - $name = 'x86' - } - elseif ($parentName -match 'fxdependent') { - $name = 'fxd' - } - else - { - throw "$parentName could not be classified as x86 or x64" - } - - # Throw is compliance zip does not exist - if (!(Test-Path $filename)) - { - throw "symbols.zip for $VSTSVariableName does not exist" - } - - # make sure we have a single parent for everything - if (!$compliancePath) - { - $parent = Split-Path -Path $folder - $compliancePath = Join-Path -Path $parent -ChildPath 'compliance' - } - - # Extract complance files to individual folder to avoid overwriting files. - $unzipPath = Join-Path -Path $compliancePath -ChildPath $name - Write-Host "Symbols-zip: $filename ; unzipPath: $unzipPath" - Expand-Archive -Path $fileName -DestinationPath $unzipPath -} - -# set VSTS variable with path to compliance files -Write-Host "##vso[task.setvariable variable=$VSTSVariableName]$unzipPath" diff --git a/tools/releaseBuild/generatePackgeSigning.ps1 b/tools/releaseBuild/generatePackgeSigning.ps1 deleted file mode 100644 index ff848892097..00000000000 --- a/tools/releaseBuild/generatePackgeSigning.ps1 +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -param( - [Parameter(Mandatory)] - [string] $Path, - [string[]] $AuthenticodeDualFiles, - [string[]] $AuthenticodeFiles, - [string[]] $NuPkgFiles, - [string[]] $MacDeveloperFiles, - [string[]] $LinuxFiles, - [string[]] $ThirdPartyFiles, - [string[]] $MsixFiles, - [ValidateSet('release','preview')] - [string] $MsixCertType = 'preview' -) - -if ((!$AuthenticodeDualFiles -or $AuthenticodeDualFiles.Count -eq 0) -and - (!$AuthenticodeFiles -or $AuthenticodeFiles.Count -eq 0) -and - (!$NuPkgFiles -or $NuPkgFiles.Count -eq 0) -and - (!$MacDeveloperFiles -or $MacDeveloperFiles.Count -eq 0) -and - (!$LinuxFiles -or $LinuxFiles.Count -eq 0) -and - (!$MsixFiles -or $MsixFiles.Count -eq 0) -and - (!$ThirdPartyFiles -or $ThirdPartyFiles.Count -eq 0)) -{ - throw "At least one file must be specified" -} - -function New-Attribute -{ - param( - [Parameter(Mandatory)] - [string]$Name, - [Parameter(Mandatory)] - [object]$Value, - [Parameter(Mandatory)] - [System.Xml.XmlElement]$Element - ) - - $attribute = $signingXml.CreateAttribute($Name) - $attribute.Value = $value - $null = $fileElement.Attributes.Append($attribute) -} - -function New-FileElement -{ - param( - [Parameter(Mandatory)] - [string]$File, - [Parameter(Mandatory)] - [string]$SignType, - [Parameter(Mandatory)] - [System.Xml.XmlDocument]$XmlDoc, - [Parameter(Mandatory)] - [System.Xml.XmlElement]$Job - ) - - if(Test-Path -Path $file) - { - $name = Split-Path -Leaf -Path $File - $fileElement = $XmlDoc.CreateElement("file") - New-Attribute -Name 'src' -value $file -Element $fileElement - New-Attribute -Name 'signType' -value $SignType -Element $fileElement - New-Attribute -Name 'dest' -value "__OUTPATHROOT__\$name" -Element $fileElement - $null = $job.AppendChild($fileElement) - } - else - { - Write-Warning -Message "Skipping $SignType; $File because it does not exist" - } -} - -[xml]$signingXml = Get-Content (Join-Path -Path $PSScriptRoot -ChildPath 'packagesigning.xml') -$job = $signingXml.SignConfigXML.job - -foreach($file in $AuthenticodeDualFiles) -{ - New-FileElement -File $file -SignType 'AuthenticodeDual' -XmlDoc $signingXml -Job $job -} - -foreach($file in $AuthenticodeFiles) -{ - New-FileElement -File $file -SignType 'AuthenticodeFormer' -XmlDoc $signingXml -Job $job -} - -foreach($file in $NuPkgFiles) -{ - New-FileElement -File $file -SignType 'NuGet' -XmlDoc $signingXml -Job $job -} - -foreach ($file in $MacDeveloperFiles) { - New-FileElement -File $file -SignType 'MacDeveloper' -XmlDoc $signingXml -Job $job -} - -foreach ($file in $LinuxFiles) { - New-FileElement -File $file -SignType 'LinuxPack' -XmlDoc $signingXml -Job $job -} - -foreach ($file in $ThirdPartyFiles) { - New-FileElement -File $file -SignType 'ThirdParty' -XmlDoc $signingXml -Job $job -} - -foreach ($file in $MsixFiles) { - # 'CP-459155' is supposed to work for the store - # AuthenticodeFormer works for sideloading and via a workaround, through the store - # ---------------------------------------------- - # update releasePublisher in packaging.psm1 when this is changed - New-FileElement -File $file -SignType 'AuthenticodeFormer' -XmlDoc $signingXml -Job $job -} - -$signingXml.Save($path) -$updateScriptPath = Join-Path -Path $PSScriptRoot -ChildPath 'updateSigning.ps1' -& $updateScriptPath -SigningXmlPath $path diff --git a/tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 b/tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 deleted file mode 100644 index acedbdd3388..00000000000 --- a/tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# PowerShell Script to build and package PowerShell from specified form and branch -# Script is intented to use in Docker containers -# Ensure PowerShell is available in the provided image - -param ( - # Set default location to where VSTS cloned the repository locally. - [string] $location = $env:BUILD_REPOSITORY_LOCALPATH, - - # Destination location of the package on docker host - [Parameter(Mandatory, ParameterSetName = 'packageSigned')] - [Parameter(Mandatory, ParameterSetName = 'IncludeSymbols')] - [Parameter(Mandatory, ParameterSetName = 'Build')] - [string] $destination = '/mnt', - - [Parameter(Mandatory, ParameterSetName = 'packageSigned')] - [Parameter(Mandatory, ParameterSetName = 'IncludeSymbols')] - [Parameter(Mandatory, ParameterSetName = 'Build')] - [ValidatePattern("^v\d+\.\d+\.\d+(-\w+(\.\d{1,2})?)?$")] - [ValidateNotNullOrEmpty()] - [string]$ReleaseTag, - - [Parameter(ParameterSetName = 'packageSigned')] - [Parameter(ParameterSetName = 'IncludeSymbols')] - [Parameter(ParameterSetName = 'Build')] - [ValidateSet("zip", "tar")] - [string[]]$ExtraPackage, - - [Parameter(Mandatory, ParameterSetName = 'Bootstrap')] - [switch] $BootStrap, - - [Parameter(Mandatory, ParameterSetName = 'IncludeSymbols')] - [Parameter(Mandatory, ParameterSetName = 'Build')] - [switch] $Build, - - [Parameter(Mandatory, ParameterSetName = 'IncludeSymbols')] - [switch] $Symbols, - - [Parameter(Mandatory, ParameterSetName = 'packageSigned')] - [ValidatePattern("-signed.zip$")] - [string]$BuildZip, - - [Parameter(Mandatory, ParameterSetName = 'packageSigned')] - [Parameter(Mandatory, ParameterSetName = 'IncludeSymbols')] - [Parameter(Mandatory, ParameterSetName = 'Build')] - [ValidateSet('osx-x64', 'osx-arm64')] - [string]$Runtime, - - [string]$ArtifactName = 'result', - - [switch]$SkipReleaseChecks -) - -$repoRoot = $location - -if ($Build -or $PSCmdlet.ParameterSetName -eq 'packageSigned') { - $releaseTagParam = @{} - if ($ReleaseTag) { - $releaseTagParam['ReleaseTag'] = $ReleaseTag - - #Remove the initial 'v' from the ReleaseTag - $version = $ReleaseTag -replace '^v' - $semVersion = [System.Management.Automation.SemanticVersion] $version - - $metadata = Get-Content "$location/tools/metadata.json" -Raw | ConvertFrom-Json - - $LTS = $metadata.LTSRelease.Package - - Write-Verbose -Verbose -Message "LTS is set to: $LTS" - } -} - -Push-Location -try { - $pspackageParams = @{ SkipReleaseChecks = $SkipReleaseChecks; MacOSRuntime = $Runtime } - Write-Verbose -Message "Init..." -Verbose - Set-Location $repoRoot - Import-Module "$repoRoot/build.psm1" - Import-Module "$repoRoot/tools/packaging" - Sync-PSTags -AddRemoteIfMissing - - if ($BootStrap) { - Start-PSBootstrap -Package - } - - if ($PSCmdlet.ParameterSetName -eq 'packageSigned') { - Write-Verbose "Expanding signed build $BuildZip ..." -Verbose - Expand-PSSignedBuild -BuildZip $BuildZip - - Remove-Item -Path $BuildZip - - Start-PSPackage @pspackageParams @releaseTagParam - switch ($ExtraPackage) { - "tar" { Start-PSPackage -Type tar @pspackageParams @releaseTagParam } - } - - if ($LTS) { - Start-PSPackage @pspackageParams @releaseTagParam -LTS - switch ($ExtraPackage) { - "tar" { Start-PSPackage -Type tar @pspackageParams @releaseTagParam -LTS } - } - } - } - - if ($Build) { - if ($Symbols) { - Start-PSBuild -Clean -Configuration 'Release' -NoPSModuleRestore @releaseTagParam -Runtime $Runtime - $pspackageParams['Type']='zip' - $pspackageParams['IncludeSymbols']=$Symbols.IsPresent - Write-Verbose "Starting powershell packaging(zip)..." -Verbose - Start-PSPackage @pspackageParams @releaseTagParam - } else { - Start-PSBuild -Configuration 'Release' -PSModuleRestore @releaseTagParam -Runtime $Runtime - Start-PSPackage @pspackageParams @releaseTagParam - switch ($ExtraPackage) { - "tar" { Start-PSPackage -Type tar @pspackageParams @releaseTagParam } - } - - if ($LTS) { - Start-PSPackage @releaseTagParam -LTS - switch ($ExtraPackage) { - "tar" { Start-PSPackage -Type tar @pspackageParams @releaseTagParam -LTS } - } - } - } - } -} finally { - Pop-Location -} - -if ($Build -or $PSCmdlet.ParameterSetName -eq 'packageSigned') { - $macPackages = Get-ChildItem "$repoRoot/powershell*" -Include *.pkg, *.tar.gz, *.zip - foreach ($macPackage in $macPackages) { - $filePath = $macPackage.FullName - $extension = (Split-Path -Extension -Path $filePath).Replace('.', '') - Write-Verbose "Copying $filePath to $destination" -Verbose - Write-Host "##vso[artifact.upload containerfolder=$ArtifactName;artifactname=$ArtifactName]$filePath" - Write-Host "##vso[task.setvariable variable=Package-$extension]$filePath" - Copy-Item -Path $filePath -Destination $destination -Force - } -} diff --git a/tools/releaseBuild/macOS/PowerShellPackageVsts.sh b/tools/releaseBuild/macOS/PowerShellPackageVsts.sh deleted file mode 100644 index b7bfa7315d8..00000000000 --- a/tools/releaseBuild/macOS/PowerShellPackageVsts.sh +++ /dev/null @@ -1 +0,0 @@ -pwsh -command ".\PowerShellPackageVsts.ps1 $*" diff --git a/tools/releaseBuild/macOS/createPowerShell.sh b/tools/releaseBuild/macOS/createPowerShell.sh deleted file mode 100644 index 5b0b681716c..00000000000 --- a/tools/releaseBuild/macOS/createPowerShell.sh +++ /dev/null @@ -1,8 +0,0 @@ -# print version for diags -sw_vers -productVersion - -# create folder -sudo mkdir /PowerShell - -# make the current user the owner -sudo chown $USER /PowerShell diff --git a/tools/releaseBuild/packagesigning.xml b/tools/releaseBuild/packagesigning.xml deleted file mode 100644 index a243e5fbd98..00000000000 --- a/tools/releaseBuild/packagesigning.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/tools/releaseBuild/setReleaseTag.ps1 b/tools/releaseBuild/setReleaseTag.ps1 deleted file mode 100644 index c5f2f016554..00000000000 --- a/tools/releaseBuild/setReleaseTag.ps1 +++ /dev/null @@ -1,161 +0,0 @@ -param( - [Parameter(HelpMessage='ReleaseTag from the job. Set to "fromBranch" or $null to update using the branch name')] - [string]$ReleaseTag, - - [Parameter(HelpMessage='The branch name used to update the release tag.')] - [string]$Branch=$env:BUILD_SOURCEBRANCH, - - [Parameter(HelpMessage='The variable name to put the new release tagin.')] - [string]$Variable='ReleaseTag', - - [switch]$CreateJson -) - -function New-BuildInfoJson { - param( - [parameter(Mandatory = $true)] - [string] - $ReleaseTag, - [switch] $IsDaily - ) - - $blobName = $ReleaseTag -replace '\.', '-' - - $isPreview = $ReleaseTag -like '*-*' - - $filename = 'stable.json' - if($isPreview) - { - $filename = 'preview.json' - } - if($IsDaily.IsPresent) - { - $filename = 'daily.json' - } - - ## Get the UTC time and round up to the second. - $dateTime = [datetime]::UtcNow - $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) - - @{ - ReleaseTag = $ReleaseTag - ReleaseDate = $dateTime - BlobName = $blobName - BaseUrl = 'https://powershellinfraartifacts-gkhedzdeaghdezhr.z01.azurefd.net/install' - } | ConvertTo-Json | Out-File -Encoding ascii -Force -FilePath $filename - - $resolvedPath = (Resolve-Path -Path $filename).ProviderPath - $vstsCommandString = "vso[task.setvariable variable=BuildInfoPath]$resolvedPath" - Write-Verbose -Message "$vstsCommandString" -Verbose - Write-Host -Object "##$vstsCommandString" - - # Upload for ADO pipelines - Write-Host "##vso[artifact.upload containerfolder=BuildInfoJson;artifactname=BuildInfoJson]$resolvedPath" - - # Copy to location where OneBranch Pipelines uploads from - - # if the environment variable does not exist, we are not in OneBranch. So just return. - if (-not $env:ob_outputDirectory) { - return - } - - if (-not (Test-Path $env:ob_outputDirectory)) { - $null = New-Item -Path $env:ob_outputDirectory -ItemType Directory -Force -Verbose - } - - Copy-Item $resolvedPath -Destination $env:ob_outputDirectory -Force -Verbose -} - -# Script to set the release tag based on the branch name if it is not set or it is "fromBranch" -# the branch name is expected to be release- or -# VSTS passes it as 'refs/heads/release-v6.0.2' - -$branchOnly = $Branch -replace '^refs/heads/'; -$branchOnly = $branchOnly -replace '[_\-]' - -$msixType = 'preview' - -$isDaily = $false - -if($ReleaseTag -eq 'fromBranch' -or !$ReleaseTag) -{ - # Branch is named release- - $releaseBranchRegex = '^.*((release/|rebuild/.*rebuild))' - if($Branch -match $releaseBranchRegex) - { - $msixType = 'release' - Write-Verbose "release branch:" -Verbose - $releaseTag = $Branch -replace '^.*((release|rebuild)/)' - $vstsCommandString = "vso[task.setvariable variable=$Variable]$releaseTag" - Write-Verbose -Message "setting $Variable to $releaseTag" -Verbose - Write-Host -Object "##$vstsCommandString" - - if ($CreateJson.IsPresent) - { - New-BuildInfoJson -ReleaseTag $releaseTag - } - } - elseif(($branchOnly -eq 'master' -and $env:BUILD_REASON -ne 'Manual') -or $branchOnly -like '*dailytest*') - { - $isDaily = $true - Write-Verbose "daily build" -Verbose - $jsonPath = "${env:SYSTEM_ARTIFACTSDIRECTORY}\BuildInfoJson\daily.json" - if (test-path -Path $jsonPath) { - Write-Verbose "restoring from buildinfo json..." -Verbose - $buildInfo = Get-Content -Path $jsonPath | ConvertFrom-Json - $releaseTag = $buildInfo.ReleaseTag - } else { - Write-Verbose "creating from branch counter and metadata.json..." -Verbose - $metaDataJsonPath = Join-Path $PSScriptRoot -ChildPath '..\metadata.json' - $metadata = Get-Content $metaDataJsonPath | ConvertFrom-Json - $versionPart = $metadata.PreviewReleaseTag - if ($versionPart -match '-.*$') { - $versionPart = $versionPart -replace '-.*$' - } - - $releaseTag = "$versionPart-daily$((Get-Date).ToString('yyyyMMdd')).$($env:BRANCHCOUNTER)" - } - - $vstsCommandString = "vso[task.setvariable variable=$Variable]$releaseTag" - Write-Verbose -Message "setting $Variable to $releaseTag" -Verbose - Write-Host -Object "##$vstsCommandString" - - if ($CreateJson.IsPresent) - { - New-BuildInfoJson -ReleaseTag $releaseTag -IsDaily - } - } - else - { - Write-Verbose "non-release branch" -Verbose - # Branch is named - # Get version from metadata and append - - $metaDataJsonPath = Join-Path $PSScriptRoot -ChildPath '..\metadata.json' - $metadata = Get-Content $metaDataJsonPath | ConvertFrom-Json - $versionPart = $metadata.PreviewReleaseTag - if($versionPart -match '-.*$') - { - $versionPart = $versionPart -replace '-.*$' - } - - $releaseTag = "$versionPart-$branchOnly" - $vstsCommandString = "vso[task.setvariable variable=$Variable]$releaseTag" - Write-Verbose -Message "setting $Variable to $releaseTag" -Verbose - Write-Host -Object "##$vstsCommandString" - - if ($CreateJson.IsPresent) - { - New-BuildInfoJson -ReleaseTag $releaseTag - } - } -} - -$vstsCommandString = "vso[task.setvariable variable=IS_DAILY]$($isDaily.ToString().ToLowerInvariant())" -Write-Verbose -Message "$vstsCommandString" -Verbose -Write-Host -Object "##$vstsCommandString" - -$vstsCommandString = "vso[task.setvariable variable=MSIX_TYPE]$msixType" -Write-Verbose -Message "$vstsCommandString" -Verbose -Write-Host -Object "##$vstsCommandString" - -Write-Output $releaseTag diff --git a/tools/releaseBuild/setReleaseTag.sh b/tools/releaseBuild/setReleaseTag.sh deleted file mode 100644 index 842ba1e755b..00000000000 --- a/tools/releaseBuild/setReleaseTag.sh +++ /dev/null @@ -1 +0,0 @@ -pwsh -command ".\setReleaseTag.ps1 $*" diff --git a/tools/releaseBuild/signing.xml b/tools/releaseBuild/signing.xml deleted file mode 100644 index a6b19f6a07a..00000000000 --- a/tools/releaseBuild/signing.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/releaseBuild/updateSigning.ps1 b/tools/releaseBuild/updateSigning.ps1 deleted file mode 100644 index bace3aec2b7..00000000000 --- a/tools/releaseBuild/updateSigning.ps1 +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -param( - [string] $SigningXmlPath = (Join-Path -Path $PSScriptRoot -ChildPath 'signing.xml'), - [switch] $SkipPwshExe -) -# Script for use in VSTS to update signing.xml - -if ($SkipPwshExe) { - ## This is required for fxdependent package as no .exe is generated. - $xmlContent = Get-Content $SigningXmlPath | Where-Object { $_ -notmatch '__INPATHROOT__\\pwsh.exe' } -} else { - ## We skip the global tool shim assembly for regular builds. - $xmlContent = Get-Content $signingXmlPath | Where-Object { $_ -notmatch '__INPATHROOT__\\Microsoft.PowerShell.GlobalTool.Shim.dll' } -} - -# Parse the signing xml -$signingXml = [xml] $xmlContent - -# Get any variables to updating 'signType' in the XML -# Define a varabile named `SignType' in VSTS to updating that signing type -# Example: $env:AuthenticodeSignType='newvalue' -# will cause all files with the 'Authenticode' signtype to be updated with the 'newvalue' signtype -$signTypes = @{} -Get-ChildItem -Path env:/*SignType | ForEach-Object -Process { - $signType = $_.Name.ToUpperInvariant().Replace('SIGNTYPE','') - Write-Host "Found SigningType $signType with value $($_.value)" - $signTypes[$signType] = $_.Value -} - -# examine each job in the xml -$signingXml.SignConfigXML.job | ForEach-Object -Process { - # examine each file in the job - $_.file | ForEach-Object -Process { - # if the sign type is one of the variables we found, update it to the new value - $signType = $_.SignType.ToUpperInvariant() - if($signTypes.ContainsKey($signType)) - { - $newSignType = $signTypes[$signType] - Write-Host "Updating $($_.src) to $newSignType" - $_.signType = $newSignType - } - } -} - -$signingXml.Save($signingXmlPath) diff --git a/tools/releaseBuild/vstsbuild.ps1 b/tools/releaseBuild/vstsbuild.ps1 deleted file mode 100644 index 1c2d740c418..00000000000 --- a/tools/releaseBuild/vstsbuild.ps1 +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -[cmdletbinding(DefaultParameterSetName='Build')] -param( - [Parameter(ParameterSetName='packageSigned')] - [Parameter(ParameterSetName='Build')] - [ValidatePattern("^v\d+\.\d+\.\d+(-\w+(\.\d{1,2})?)?$")] - [string]$ReleaseTag, - - # full paths to files to add to container to run the build - [Parameter(Mandatory,ParameterSetName='packageSigned')] - [string] - $BuildPath, - - [Parameter(Mandatory,ParameterSetName='packageSigned')] - [string] - $SignedFilesPath -) - -DynamicParam { - # Add a dynamic parameter '-Name' which specifies the name of the build to run - - # Get the names of the builds. - $buildJsonPath = (Join-Path -Path $PSScriptRoot -ChildPath 'build.json') - $build = Get-Content -Path $buildJsonPath | ConvertFrom-Json - $names = @($build.Windows.Name) - foreach($name in $build.Linux.Name) - { - $names += $name - } - - # Create the parameter attributs - $ParameterAttr = New-Object "System.Management.Automation.ParameterAttribute" - $ValidateSetAttr = New-Object "System.Management.Automation.ValidateSetAttribute" -ArgumentList $names - $Attributes = New-Object "System.Collections.ObjectModel.Collection``1[System.Attribute]" - $Attributes.Add($ParameterAttr) > $null - $Attributes.Add($ValidateSetAttr) > $null - - # Create the parameter - $Parameter = New-Object "System.Management.Automation.RuntimeDefinedParameter" -ArgumentList ("Name", [string], $Attributes) - $Dict = New-Object "System.Management.Automation.RuntimeDefinedParameterDictionary" - $Dict.Add("Name", $Parameter) > $null - return $Dict -} - -Begin { - $Name = $PSBoundParameters['Name'] -} - -End { - $ErrorActionPreference = 'Stop' - - $additionalFiles = @() - $buildPackageName = $null - # If specified, Add package file to container - if ($BuildPath) - { - Import-Module (Join-Path -Path $PSScriptRoot -ChildPath '..\..\build.psm1') - Import-Module (Join-Path -Path $PSScriptRoot -ChildPath '..\packaging') - - # Use temp as destination if not running in VSTS - $destFolder = $env:temp - if($env:BUILD_STAGINGDIRECTORY) - { - # Use artifact staging if running in VSTS - $destFolder = $env:BUILD_STAGINGDIRECTORY - } - - $BuildPackagePath = New-PSSignedBuildZip -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath -DestinationFolder $destFolder - Write-Verbose -Verbose "New-PSSignedBuildZip returned `$BuildPackagePath as: $BuildPackagePath" - Write-Host "##vso[artifact.upload containerfolder=results;artifactname=results]$BuildPackagePath" - $buildPackageName = Split-Path -Path $BuildPackagePath -Leaf - $additionalFiles += $BuildPackagePath - } - - $psReleaseBranch = 'master' - $psReleaseFork = 'PowerShell' - $location = Join-Path -Path $PSScriptRoot -ChildPath 'PSRelease' - if(Test-Path $location) - { - Remove-Item -Path $location -Recurse -Force - } - - $gitBinFullPath = (Get-Command -Name git).Source - if (-not $gitBinFullPath) - { - throw "Git is required to proceed. Install from 'https://git-scm.com/download/win'" - } - - Write-Verbose "cloning -b $psReleaseBranch --quiet https://github.com/$psReleaseFork/PSRelease.git" -Verbose - & $gitBinFullPath clone -b $psReleaseBranch --quiet https://github.com/$psReleaseFork/PSRelease.git $location - - Push-Location -Path $PWD.Path - - $unresolvedRepoRoot = Join-Path -Path $PSScriptRoot '../..' - $resolvedRepoRoot = (Resolve-Path -Path $unresolvedRepoRoot).ProviderPath - - try - { - Write-Verbose "Starting build at $resolvedRepoRoot ..." -Verbose - Import-Module "$location/vstsBuild" -Force - Import-Module "$location/dockerBasedBuild" -Force - Clear-VstsTaskState - - $buildParameters = @{ - ReleaseTag = $ReleaseTag - BuildPackageName = $buildPackageName - } - - Invoke-Build -RepoPath $resolvedRepoRoot -BuildJsonPath './tools/releaseBuild/build.json' -Name $Name -Parameters $buildParameters -AdditionalFiles $AdditionalFiles - } - catch - { - Write-VstsError -Error $_ - } - finally{ - Write-VstsTaskState - exit 0 - } -} diff --git a/tools/releaseBuild/vstsbuild.sh b/tools/releaseBuild/vstsbuild.sh deleted file mode 100644 index d7d0363745f..00000000000 --- a/tools/releaseBuild/vstsbuild.sh +++ /dev/null @@ -1 +0,0 @@ -pwsh -command ".\vstsbuild.ps1 $*" From 91d919cc32712a9bf2559dba911b0546f46269f7 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 2 Apr 2025 18:46:10 -0700 Subject: [PATCH 081/275] [release/v7.5]Add setup dotnet action to the build composite action (#25235) --- .github/actions/build/ci/action.yml | 3 +++ .github/actions/test/nix/action.yml | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml index 90968d81cfe..93adaf6b17a 100644 --- a/.github/actions/build/ci/action.yml +++ b/.github/actions/build/ci/action.yml @@ -11,6 +11,9 @@ runs: if: github.event_name != 'PullRequest' run: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhmmss"))" shell: pwsh + - uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json - name: Bootstrap if: success() run: |- diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index 97575b6b54d..03c44a151c7 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -30,7 +30,11 @@ runs: continue-on-error: true run: Get-ChildItem "${{ github.workspace }}/build/*" -Recurse shell: pwsh - + + - uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + - name: Bootstrap shell: pwsh run: |- From f0e645cc32c4deedb4f7453fd8a365f1aee9ed9c Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 4 Apr 2025 15:11:58 -0700 Subject: [PATCH 082/275] [release/v7.5]Remove obsolete template from Windows Packaging CI (#25237) --- .vsts-ci/windows/templates/windows-packaging.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.vsts-ci/windows/templates/windows-packaging.yml b/.vsts-ci/windows/templates/windows-packaging.yml index 84b02d14dfd..b0e97d7f6a9 100644 --- a/.vsts-ci/windows/templates/windows-packaging.yml +++ b/.vsts-ci/windows/templates/windows-packaging.yml @@ -47,9 +47,6 @@ jobs: displayName: Capture PowerShell Version Table condition: succeededOrFailed() - - - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml - - pwsh: | Import-Module .\tools\ci.psm1 Switch-PSNugetConfig -Source Public From efb55e20acaef57a9b54dbfa4ebc1e1c79eef5c3 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 4 Apr 2025 15:56:37 -0700 Subject: [PATCH 083/275] [release/v7.5] Add UseDotnet task for installing dotnet (#25281) Co-authored-by: Aditya Patwardhan --- .../actions/test/linux-packaging/action.yml | 2 +- .github/actions/test/windows/action.yml | 5 +- .github/workflows/linux-ci.yml | 5 ++ .github/workflows/macos-ci.yml | 2 +- .pipelines/templates/compliance/apiscan.yml | 14 ++-- .pipelines/templates/linux-package-build.yml | 2 +- .pipelines/templates/linux.yml | 8 +- .pipelines/templates/mac-package-build.yml | 2 +- .pipelines/templates/mac.yml | 9 ++- .pipelines/templates/nupkg.yml | 9 ++- .../release-validate-fxdpackages.yml | 38 ++-------- .../release-validate-globaltools.yml | 43 ++--------- .pipelines/templates/release-validate-sdk.yml | 42 ++--------- .pipelines/templates/testartifacts.yml | 22 +++--- .pipelines/templates/windows-hosted-build.yml | 12 ++- .../templates/windows-package-build.yml | 11 ++- .vsts-ci/linux/templates/packaging.yml | 8 +- .vsts-ci/mac.yml | 2 +- .vsts-ci/psresourceget-acr.yml | 1 - .vsts-ci/templates/ci-build.yml | 6 ++ .vsts-ci/templates/nix-test.yml | 6 ++ .../templates/test/nix-container-test.yml | 6 ++ .vsts-ci/templates/windows-test.yml | 8 +- .vsts-ci/windows-daily.yml | 11 ++- .../windows/templates/windows-packaging.yml | 7 ++ build.psm1 | 75 ++++++++++--------- tools/ci.psm1 | 6 +- tools/packaging/packaging.psm1 | 4 +- 28 files changed, 178 insertions(+), 188 deletions(-) diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index 61d23742056..b4a9c3b55c0 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -27,7 +27,7 @@ runs: - name: Bootstrap run: |- Import-Module ./build.psm1 - Start-PSBootstrap -Package + Start-PSBootstrap -Scenario Package shell: pwsh - name: Capture Artifacts Directory continue-on-error: true diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index c8e1c86024a..d2af55ce5a9 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -31,6 +31,10 @@ runs: run: Get-ChildItem "${{ github.workspace }}\build\*" -Recurse shell: pwsh + - uses: actions/setup-dotnet@v4 + with: + global-json-file: .\global.json + - name: Bootstrap shell: powershell run: |- @@ -50,7 +54,6 @@ runs: if: success() run: |- Import-Module .\build.psm1 -force - Start-PSBootstrap Import-Module .\tools\ci.psm1 Restore-PSOptions -PSOptionsPath '${{ github.workspace }}\build\psoptions.json' $options = (Get-PSOptions) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 8f15e9a080d..68b651c7e46 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -77,6 +77,7 @@ jobs: uses: actions/checkout@v4.1.0 with: fetch-depth: 1000 + - name: Build uses: "./.github/actions/build/ci" linux_test_unelevated_ci: @@ -187,6 +188,10 @@ jobs: with: fetch-depth: '0' + - uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index fafb6140285..b414afebfc9 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -174,7 +174,7 @@ jobs: if: success() || failure() run: |- import-module ./build.psm1 - start-psbootstrap -package + start-psbootstrap -Scenario package shell: pwsh ready_to_merge: name: macos ready to merge diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml index b30d72f6a56..bfe97827801 100644 --- a/.pipelines/templates/compliance/apiscan.yml +++ b/.pipelines/templates/compliance/apiscan.yml @@ -61,14 +61,12 @@ jobs: parameters: repoRoot: '$(repoRoot)' - - pwsh: | - Import-Module .\build.psm1 -force - Start-PSBootstrap - workingDirectory: '$(repoRoot)' - retryCountOnTaskFailure: 2 - displayName: 'Bootstrap' - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: $(Build.SourcesDirectory)" - pwsh: | Import-Module .\build.psm1 -force diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index 05c798cd2c3..a9f4833cc1d 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -103,7 +103,7 @@ jobs: Import-Module "$repoRoot/build.psm1" Import-Module "$repoRoot/tools/packaging" - Start-PSBootstrap -Package + Start-PSBootstrap -Scenario Package $psOptionsPath = "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/${unsignedDrop}/psoptions/psoptions.json" diff --git a/.pipelines/templates/linux.yml b/.pipelines/templates/linux.yml index 2e6f9c3e5e3..d6026dc5336 100644 --- a/.pipelines/templates/linux.yml +++ b/.pipelines/templates/linux.yml @@ -62,6 +62,13 @@ jobs: AnalyzeInPipeline: true Language: csharp + - task: UseDotNet@2 + inputs: + useGlobalJson: true + workingDirectory: $(PowerShellRoot) + env: + ob_restore_phase: true + - pwsh: | $runtime = $env:RUNTIME @@ -75,7 +82,6 @@ jobs: Import-Module -Name $(PowerShellRoot)/build.psm1 -Force $buildWithSymbolsPath = New-Item -ItemType Directory -Path $(Pipeline.Workspace)/Symbols_$(Runtime) -Force - Start-PSBootstrap $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose $ReleaseTagParam = @{} diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 2da8c2b7615..f009fdae06f 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -110,7 +110,7 @@ jobs: Write-Verbose -Message "LTS Release: $LTS" } - Start-PSBootstrap -Package + Start-PSBootstrap -Scenario Package $macosRuntime = "osx-$buildArch" diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index 4f9604ea100..310c5695979 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -39,9 +39,16 @@ jobs: sudo chown $env:USER "$(Agent.TempDirectory)/PowerShell" displayName: 'Create $(Agent.TempDirectory)/PowerShell' + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: $(PowerShellRoot) + - pwsh: | Import-Module $(PowerShellRoot)/build.psm1 -Force - Start-PSBootstrap -Package + Start-PSBootstrap -Scenario Package displayName: 'Bootstrap VM' env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index be4b704557e..d7837c5c3dc 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -97,12 +97,17 @@ jobs: - task: NuGetToolInstaller@1 displayName: 'Install NuGet.exe' + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: '$(PowerShellRoot)' + - pwsh: | Set-Location -Path '$(PowerShellRoot)' Import-Module "$(PowerShellRoot)/build.psm1" -Force - Start-PSBootstrap -Verbose - $sharedModules = @('Microsoft.PowerShell.Commands.Management', 'Microsoft.PowerShell.Commands.Utility', 'Microsoft.PowerShell.ConsoleHost', diff --git a/.pipelines/templates/release-validate-fxdpackages.yml b/.pipelines/templates/release-validate-fxdpackages.yml index 62e907fcf36..baf6c431787 100644 --- a/.pipelines/templates/release-validate-fxdpackages.yml +++ b/.pipelines/templates/release-validate-fxdpackages.yml @@ -44,38 +44,12 @@ jobs: Get-ChildItem "$(Pipeline.Workspace)/PSPackagesOfficial/$artifactName" -Recurse displayName: 'Capture Downloaded Artifacts' - - pwsh: | - $repoRoot = "$(Build.SourcesDirectory)/PowerShell" - $dotnetMetadataPath = "$repoRoot/DotnetRuntimeMetadata.json" - $dotnetMetadataJson = Get-Content $dotnetMetadataPath -Raw | ConvertFrom-Json - - # Channel is like: $Channel = "5.0.1xx-preview2" - $Channel = $dotnetMetadataJson.sdk.channel - - $sdkVersion = (Get-Content "$repoRoot/global.json" -Raw | ConvertFrom-Json).sdk.version - Import-Module "$repoRoot/build.psm1" -Force - - Find-Dotnet - - if(-not (Get-PackageSource -Name 'dotnet' -ErrorAction SilentlyContinue)) - { - $nugetFeed = ([xml](Get-Content $repoRoot/nuget.config -Raw)).Configuration.packagesources.add | Where-Object { $_.Key -eq 'dotnet' } | Select-Object -ExpandProperty Value - if ($nugetFeed) { - Register-PackageSource -Name 'dotnet' -Location $nugetFeed -ProviderName NuGet - Write-Verbose -Message "Register new package source 'dotnet'" -verbose - } - } - - ## Install latest version from the channel - - #Install-Dotnet -Channel "$Channel" -Version $sdkVersion - Start-PSBootstrap - - Write-Verbose -Message "Installing .NET SDK completed." -Verbose - - displayName: Install .NET - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: $(Build.SourcesDirectory)/PowerShell" - pwsh: | $artifactName = '$(artifactName)' diff --git a/.pipelines/templates/release-validate-globaltools.yml b/.pipelines/templates/release-validate-globaltools.yml index 0820e5591f6..3c88a278791 100644 --- a/.pipelines/templates/release-validate-globaltools.yml +++ b/.pipelines/templates/release-validate-globaltools.yml @@ -38,44 +38,15 @@ jobs: Get-ChildItem "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" -Recurse displayName: 'Capture Downloaded Artifacts' - - pwsh: | - $repoRoot = "$(Build.SourcesDirectory)/PowerShell" - $dotnetMetadataPath = "$repoRoot/DotnetRuntimeMetadata.json" - $dotnetMetadataJson = Get-Content $dotnetMetadataPath -Raw | ConvertFrom-Json - - # Channel is like: $Channel = "5.0.1xx-preview2" - $Channel = $dotnetMetadataJson.sdk.channel - - $sdkVersion = (Get-Content "$repoRoot/global.json" -Raw | ConvertFrom-Json).sdk.version - Import-Module "$repoRoot/build.psm1" -Force - - Find-Dotnet - - if(-not (Get-PackageSource -Name 'dotnet' -ErrorAction SilentlyContinue)) - { - $nugetFeed = ([xml](Get-Content $repoRoot/nuget.config -Raw)).Configuration.packagesources.add | Where-Object { $_.Key -eq 'dotnet' } | Select-Object -ExpandProperty Value - if ($nugetFeed) { - Register-PackageSource -Name 'dotnet' -Location $nugetFeed -ProviderName NuGet - Write-Verbose -Message "Register new package source 'dotnet'" -verbose - } - } - - ## Install latest version from the channel - - #Install-Dotnet -Channel "$Channel" -Version $sdkVersion - Start-PSBootstrap - - Write-Verbose -Message "Installing .NET SDK completed." -Verbose - - displayName: Install .NET - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: $(REPOROOT) - pwsh: | $repoRoot = "$(Build.SourcesDirectory)/PowerShell" - $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - Import-Module "$repoRoot/build.psm1" -Force - Start-PSBootstrap $toolPath = New-Item -ItemType Directory "$(System.DefaultWorkingDirectory)/toolPath" | Select-Object -ExpandProperty FullName @@ -108,8 +79,6 @@ jobs: - pwsh: | $repoRoot = "$(Build.SourcesDirectory)/PowerShell" - Import-Module "$repoRoot/build.psm1" -Force - Start-PSBootstrap $exeName = if ($IsWindows) { "pwsh.exe" } else { "pwsh" } diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index 3f365f5ebb9..0d50b213961 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -46,47 +46,17 @@ jobs: Get-ChildItem "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" -Recurse displayName: 'Capture Downloaded Artifacts' - - pwsh: | - $repoRoot = "$(Build.SourcesDirectory)" - - $dotnetMetadataPath = "$repoRoot/DotnetRuntimeMetadata.json" - $dotnetMetadataJson = Get-Content $dotnetMetadataPath -Raw | ConvertFrom-Json - - # Channel is like: $Channel = "5.0.1xx-preview2" - $Channel = $dotnetMetadataJson.sdk.channel - - $sdkVersion = (Get-Content "$repoRoot/global.json" -Raw | ConvertFrom-Json).sdk.version - Import-Module "$repoRoot/build.psm1" -Force - - Find-Dotnet - - if(-not (Get-PackageSource -Name 'dotnet' -ErrorAction SilentlyContinue)) - { - $nugetFeed = ([xml](Get-Content $repoRoot/nuget.config -Raw)).Configuration.packagesources.add | Where-Object { $_.Key -eq 'dotnet' } | Select-Object -ExpandProperty Value - - if ($nugetFeed) { - Register-PackageSource -Name 'dotnet' -Location $nugetFeed -ProviderName NuGet - Write-Verbose -Message "Register new package source 'dotnet'" -verbose - } - } - - ## Install latest version from the channel - #Install-Dotnet -Channel "$Channel" -Version $sdkVersion - - Start-PSBootstrap - - Write-Verbose -Message "Installing .NET SDK completed." -Verbose - - displayName: Install .NET - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: $(REPOROOT) - pwsh: | $repoRoot = "$(Build.SourcesDirectory)" $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - Import-Module "$repoRoot/build.psm1" -Force - Start-PSBootstrap $localLocation = "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" $xmlElement = @" diff --git a/.pipelines/templates/testartifacts.yml b/.pipelines/templates/testartifacts.yml index 039e9336d7c..240ceae80f7 100644 --- a/.pipelines/templates/testartifacts.yml +++ b/.pipelines/templates/testartifacts.yml @@ -30,12 +30,13 @@ jobs: repoRoot: $(Build.SourcesDirectory)/PowerShell ob_restore_phase: true - - pwsh: | - Import-Module $(Build.SourcesDirectory)/PowerShell/build.psm1 - Start-PSBootstrap - displayName: Bootstrap + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: $(Build.SourcesDirectory)/PowerShell" env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) ob_restore_phase: true - pwsh: | @@ -97,12 +98,13 @@ jobs: repoRoot: $(Build.SourcesDirectory)/PowerShell ob_restore_phase: true - - pwsh: | - Import-Module $(Build.SourcesDirectory)/PowerShell/build.psm1 - Start-PSBootstrap - displayName: Bootstrap + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: $(Build.SourcesDirectory)/PowerShell" env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) ob_restore_phase: true - pwsh: | diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index 735ed7cc48f..8f8273f4ec8 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -63,6 +63,13 @@ jobs: AnalyzeInPipeline: true Language: csharp + - task: UseDotNet@2 + inputs: + useGlobalJson: true + workingDirectory: $(PowerShellRoot) + env: + ob_restore_phase: true + - pwsh: | $runtime = switch ($env:Architecture) { @@ -86,7 +93,7 @@ jobs: Import-Module -Name $(PowerShellRoot)/build.psm1 -Force $buildWithSymbolsPath = New-Item -ItemType Directory -Path $(Pipeline.Workspace)/Symbols_$(Architecture) -Force - Start-PSBootstrap -Package + Start-PSBootstrap -Scenario Package $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose $ReleaseTagParam = @{} @@ -135,7 +142,6 @@ jobs: } Import-Module -Name $(PowerShellRoot)/build.psm1 -Force - Start-PSBootstrap ## Build global tool Write-Verbose -Message "Building PowerShell global tool for Windows.x64" -Verbose @@ -229,8 +235,6 @@ jobs: After that, we repack using Compress-Archive and rename it back to a nupkg. #> - Import-Module -Name $(PowerShellRoot)/build.psm1 -Force - Start-PSBootstrap $packagingStrings = Import-PowerShellDataFile "$(PowerShellRoot)\tools\packaging\packaging.strings.psd1" $outputPath = Join-Path '$(ob_outputDirectory)' 'globaltool' diff --git a/.pipelines/templates/windows-package-build.yml b/.pipelines/templates/windows-package-build.yml index da2579d75a3..08dd15fc79f 100644 --- a/.pipelines/templates/windows-package-build.yml +++ b/.pipelines/templates/windows-package-build.yml @@ -78,6 +78,13 @@ jobs: env: ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + - task: UseDotNet@2 + inputs: + useGlobalJson: true + workingDirectory: $(REPOROOT) + env: + ob_restore_phase: true + - pwsh: | $msixUrl = '$(makeappUrl)' Invoke-RestMethod -Uri $msixUrl -OutFile '$(Pipeline.Workspace)\makeappx.zip' @@ -105,7 +112,7 @@ jobs: Import-Module "$repoRoot\build.psm1" Import-Module "$repoRoot\tools\packaging" - Start-PSBootstrap -Package + Start-PSBootstrap -Scenario Package $signedFilesPath, $psoptionsFilePath = if ($env:RUNTIME -eq 'minsize') { "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_x64_${runtime}\$signedFolder" @@ -136,7 +143,7 @@ jobs: Write-Verbose -Message "LTS Release: $LTS" } - Start-PSBootstrap -Package + Start-PSBootstrap -Scenario Package $WindowsRuntime = switch ($runtime) { 'x64' { 'win7-x64' } diff --git a/.vsts-ci/linux/templates/packaging.yml b/.vsts-ci/linux/templates/packaging.yml index fab2e1101fa..e6294951cb6 100644 --- a/.vsts-ci/linux/templates/packaging.yml +++ b/.vsts-ci/linux/templates/packaging.yml @@ -13,6 +13,12 @@ jobs: displayName: ${{ parameters.name }} packaging steps: + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + - pwsh: | Get-ChildItem -Path env: displayName: Capture Environment @@ -33,7 +39,7 @@ jobs: - pwsh: | Import-Module .\build.psm1 - Start-PSBootstrap -Package + Start-PSBootstrap -Scenario Package displayName: Bootstrap - pwsh: | diff --git a/.vsts-ci/mac.yml b/.vsts-ci/mac.yml index bfb0b3afd21..05d6d71ea71 100644 --- a/.vsts-ci/mac.yml +++ b/.vsts-ci/mac.yml @@ -110,6 +110,6 @@ stages: clean: true - pwsh: | import-module ./build.psm1 - start-psbootstrap -package + start-psbootstrap -Scenario package displayName: Bootstrap packaging condition: succeededOrFailed() diff --git a/.vsts-ci/psresourceget-acr.yml b/.vsts-ci/psresourceget-acr.yml index c4211d35d95..1a24983b5b5 100644 --- a/.vsts-ci/psresourceget-acr.yml +++ b/.vsts-ci/psresourceget-acr.yml @@ -137,7 +137,6 @@ stages: - pwsh: | Import-Module .\build.psm1 -force - Start-PSBootstrap Import-Module .\tools\ci.psm1 Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' $options = (Get-PSOptions) diff --git a/.vsts-ci/templates/ci-build.yml b/.vsts-ci/templates/ci-build.yml index 59d63002567..2c2fbe8d91d 100644 --- a/.vsts-ci/templates/ci-build.yml +++ b/.vsts-ci/templates/ci-build.yml @@ -57,6 +57,12 @@ jobs: - ${{ if ne(variables['UseAzDevOpsFeed'], '') }}: - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + - pwsh: | Import-Module .\tools\ci.psm1 Invoke-CIInstall -SkipUser diff --git a/.vsts-ci/templates/nix-test.yml b/.vsts-ci/templates/nix-test.yml index ab3985dacd6..214ae14b2c6 100644 --- a/.vsts-ci/templates/nix-test.yml +++ b/.vsts-ci/templates/nix-test.yml @@ -13,6 +13,12 @@ jobs: displayName: ${{ parameters.name }} Test - ${{ parameters.purpose }} - ${{ parameters.tagSet }} steps: + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + - template: ./test/nix-test-steps.yml parameters: purpose: ${{ parameters.purpose }} diff --git a/.vsts-ci/templates/test/nix-container-test.yml b/.vsts-ci/templates/test/nix-container-test.yml index 931af6fc675..37c60a4c53b 100644 --- a/.vsts-ci/templates/test/nix-container-test.yml +++ b/.vsts-ci/templates/test/nix-container-test.yml @@ -23,6 +23,12 @@ jobs: displayName: ${{ parameters.name }} Test - ${{ parameters.purpose }} - ${{ parameters.tagSet }} steps: + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + - template: ./nix-test-steps.yml parameters: purpose: ${{ parameters.purpose }} diff --git a/.vsts-ci/templates/windows-test.yml b/.vsts-ci/templates/windows-test.yml index 50ff67a32a8..02a8ddd1ea8 100644 --- a/.vsts-ci/templates/windows-test.yml +++ b/.vsts-ci/templates/windows-test.yml @@ -54,6 +54,13 @@ jobs: displayName: 'Capture Artifacts Directory' continueOnError: true + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: $(Build.SourcesDirectory)" + # must be run frow Windows PowerShell - powershell: | # Remove "Program Files\dotnet" from the env variable PATH, so old SDKs won't affect us. @@ -74,7 +81,6 @@ jobs: - pwsh: | Import-Module .\build.psm1 -force - Start-PSBootstrap Import-Module .\tools\ci.psm1 Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' $options = (Get-PSOptions) diff --git a/.vsts-ci/windows-daily.yml b/.vsts-ci/windows-daily.yml index 4abcf8ec966..5a2f5ed2425 100644 --- a/.vsts-ci/windows-daily.yml +++ b/.vsts-ci/windows-daily.yml @@ -93,6 +93,13 @@ stages: displayName: Bootstrap condition: succeededOrFailed() + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: $(Build.SourcesDirectory)" + - pwsh: | Import-Module .\build.psm1 Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' @@ -104,7 +111,6 @@ stages: - pwsh: | Import-Module .\build.psm1 - Start-PSBootstrap Import-Module .\tools\ci.psm1 Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' Invoke-CITest -Purpose UnelevatedPesterTests -TagSet CI @@ -113,7 +119,6 @@ stages: - pwsh: | Import-Module .\build.psm1 - Start-PSBootstrap Import-Module .\tools\ci.psm1 Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' Invoke-CITest -Purpose ElevatedPesterTests -TagSet CI @@ -122,7 +127,6 @@ stages: - pwsh: | Import-Module .\build.psm1 - Start-PSBootstrap Import-Module .\tools\ci.psm1 Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' Invoke-CITest -Purpose UnelevatedPesterTests -TagSet Others @@ -131,7 +135,6 @@ stages: - pwsh: | Import-Module .\build.psm1 - Start-PSBootstrap Import-Module .\tools\ci.psm1 Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' Invoke-CITest -Purpose ElevatedPesterTests -TagSet Others diff --git a/.vsts-ci/windows/templates/windows-packaging.yml b/.vsts-ci/windows/templates/windows-packaging.yml index b0e97d7f6a9..cc32837a304 100644 --- a/.vsts-ci/windows/templates/windows-packaging.yml +++ b/.vsts-ci/windows/templates/windows-packaging.yml @@ -54,6 +54,13 @@ jobs: condition: succeeded() workingDirectory: $(repoPath) + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: $(repoPath) + - pwsh: | Import-Module .\tools\ci.psm1 Invoke-CIInstall -SkipUser diff --git a/build.psm1 b/build.psm1 index e05b5639af1..e882e2f797c 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2226,10 +2226,12 @@ function Start-PSBootstrap { # we currently pin dotnet-cli version, and will # update it when more stable version comes out. [string]$Version = $dotnetCLIRequiredVersion, - [switch]$Package, [switch]$NoSudo, [switch]$BuildLinuxArm, - [switch]$Force + [switch]$Force, + [Parameter(Mandatory = $true)] + [ValidateSet("Package", "DotNet", "Both")] + [string]$Scenario = "Package" ) Write-Log -message "Installing PowerShell build dependencies" @@ -2262,7 +2264,7 @@ function Start-PSBootstrap { elseif ($environment.IsUbuntu18) { $Deps += "libicu60"} # Packaging tools - if ($Package) { $Deps += "ruby-dev", "groff", "libffi-dev", "rpm", "g++", "make" } + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-dev", "groff", "libffi-dev", "rpm", "g++", "make" } # Install dependencies # change the fontend from apt-get to noninteractive @@ -2286,7 +2288,7 @@ function Start-PSBootstrap { $Deps += "libicu", "openssl-libs" # Packaging tools - if ($Package) { $Deps += "ruby-devel", "rpm-build", "groff", 'libffi-devel', "gcc-c++" } + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-devel", "rpm-build", "groff", 'libffi-devel', "gcc-c++" } $PackageManager = Get-RedHatPackageManager @@ -2307,7 +2309,7 @@ function Start-PSBootstrap { $Deps += "wget" # Packaging tools - if ($Package) { $Deps += "ruby-devel", "rpmbuild", "groff", 'libffi-devel', "gcc" } + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-devel", "rpmbuild", "groff", 'libffi-devel', "gcc" } $PackageManager = "zypper --non-interactive install" $baseCommand = "$sudo $PackageManager" @@ -2347,7 +2349,7 @@ function Start-PSBootstrap { } # Install [fpm](https://github.com/jordansissel/fpm) - if ($Package) { + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.16.3" Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" @@ -2355,42 +2357,45 @@ function Start-PSBootstrap { } } - Write-Verbose -Verbose "Calling Find-Dotnet from Start-PSBootstrap" + if ($Scenario -eq 'DotNet' -or $Scenario -eq 'Both') { - # Try to locate dotnet-SDK before installing it - Find-Dotnet + Write-Verbose -Verbose "Calling Find-Dotnet from Start-PSBootstrap" - Write-Verbose -Verbose "Back from calling Find-Dotnet from Start-PSBootstrap" + # Try to locate dotnet-SDK before installing it + Find-Dotnet - # Install dotnet-SDK - $dotNetExists = precheck 'dotnet' $null - $dotNetVersion = [string]::Empty - if($dotNetExists) { - $dotNetVersion = Find-RequiredSDK $dotnetCLIRequiredVersion - } + Write-Verbose -Verbose "Back from calling Find-Dotnet from Start-PSBootstrap" - if(!$dotNetExists -or $dotNetVersion -ne $dotnetCLIRequiredVersion -or $Force.IsPresent) { - if($Force.IsPresent) { - Write-Log -message "Installing dotnet due to -Force." - } - elseif(!$dotNetExists) { - Write-Log -message "dotnet not present. Installing dotnet." - } - else { - Write-Log -message "dotnet out of date ($dotNetVersion). Updating dotnet." + # Install dotnet-SDK + $dotNetExists = precheck 'dotnet' $null + $dotNetVersion = [string]::Empty + if($dotNetExists) { + $dotNetVersion = Find-RequiredSDK $dotnetCLIRequiredVersion } - $DotnetArguments = @{ Channel=$Channel; Version=$Version; NoSudo=$NoSudo } + if(!$dotNetExists -or $dotNetVersion -ne $dotnetCLIRequiredVersion -or $Force.IsPresent) { + if($Force.IsPresent) { + Write-Log -message "Installing dotnet due to -Force." + } + elseif(!$dotNetExists) { + Write-Log -message "dotnet not present. Installing dotnet." + } + else { + Write-Log -message "dotnet out of date ($dotNetVersion). Updating dotnet." + } + + $DotnetArguments = @{ Channel=$Channel; Version=$Version; NoSudo=$NoSudo } - if ($dotnetAzureFeed) { - $null = $DotnetArguments.Add("AzureFeed", $dotnetAzureFeed) - $null = $DotnetArguments.Add("FeedCredential", $dotnetAzureFeedSecret) - } + if ($dotnetAzureFeed) { + $null = $DotnetArguments.Add("AzureFeed", $dotnetAzureFeed) + $null = $DotnetArguments.Add("FeedCredential", $dotnetAzureFeedSecret) + } - Install-Dotnet @DotnetArguments - } - else { - Write-Log -message "dotnet is already installed. Skipping installation." + Install-Dotnet @DotnetArguments + } + else { + Write-Log -message "dotnet is already installed. Skipping installation." + } } # Install Windows dependencies if `-Package` or `-BuildWindowsNative` is specified @@ -2402,7 +2407,7 @@ function Start-PSBootstrap { $psInstallFile = [System.IO.Path]::Combine($PSScriptRoot, "tools", "install-powershell.ps1") & $psInstallFile -AddToPath } - if ($Package) { + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { Import-Module "$PSScriptRoot\tools\wix\wix.psm1" $isArm64 = "$env:RUNTIME" -eq 'arm64' Install-Wix -arm64:$isArm64 diff --git a/tools/ci.psm1 b/tools/ci.psm1 index f09d159b4c8..317f05effd0 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -188,8 +188,6 @@ function Invoke-CIInstall } Set-BuildVariable -Name TestPassed -Value False - Write-Verbose -Verbose -Message "Calling Start-PSBootstrap from Invoke-CIInstall" - Start-PSBootstrap } function Invoke-CIxUnit @@ -402,8 +400,6 @@ function New-CodeCoverageAndTestPackage if (Test-DailyBuild) { - Start-PSBootstrap -Verbose - Start-PSBuild -Configuration 'CodeCoverage' -Clean $codeCoverageOutput = Split-Path -Parent (Get-PSOutput) @@ -691,7 +687,7 @@ function Invoke-BootstrapStage Write-Log -Message "Executing ci.psm1 Bootstrap Stage" # Make sure we have all the tags Sync-PSTags -AddRemoteIfMissing - Start-PSBootstrap -Package:$createPackages + Start-PSBootstrap -Scenario Package:$createPackages } # Run pester tests for Linux and macOS diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 6e88df19dec..43a8d5d8dd4 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1637,7 +1637,7 @@ function Get-PackageDependencies function Test-Dependencies { foreach ($Dependency in "fpm") { - if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Package")) { + if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { # These tools are not added to the path automatically on OpenSUSE 13.2 # try adding them to the path and re-tesing first [string] $gemsPath = $null @@ -1647,7 +1647,7 @@ function Test-Dependencies $depenencyPath = Get-ChildItem -Path (Join-Path -Path $gemsPath -ChildPath "gems" -AdditionalChildPath $Dependency) -Recurse | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty DirectoryName $originalPath = $env:PATH $env:PATH = $ENV:PATH +":" + $depenencyPath - if ((precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Package")) { + if ((precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { continue } else { From 99c93ee38a6417311a9ff9058b2103c15efc8c42 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 10 Apr 2025 13:14:01 -0700 Subject: [PATCH 084/275] [release/v7.5] Migrate MacOS Signing to OneBranch (#25304) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung --- .pipelines/templates/mac-package-build.yml | 59 +++++++++------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index f009fdae06f..40a6faef06c 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -173,56 +173,43 @@ jobs: Get-ChildItem -Path $(Pipeline.Workspace) -Filter "*.zip" -File | Write-Verbose -Verbose displayName: Compress package files for signing - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 - displayName: 'ESRP CodeSigning' + - task: onebranch.pipeline.signing@1 + displayName: 'OneBranch CodeSigning Package' inputs: - ConnectedServiceName: 'ESRPMacOSSigning' - AppRegistrationClientId: '$(AppRegistrationClientId)' - AppRegistrationTenantId: '$(AppRegistrationTenantId)' - AuthAKVName: 'pwsh-CICD-Keyvault' - AuthCertName: 'PS-macos-signing' - AuthSignCertName: 'ESRP-OneCert' # this is not needed for pkg signing - FolderPath: $(Pipeline.Workspace) - Pattern: '*.zip' - signConfigType: inlineSignParams - inlineOperation: | - [{ + command: 'sign' + files_to_sign: '**/*-osx-*.zip' + search_root: '$(Pipeline.Workspace)' + inline_operation: | + [ + { "KeyCode": "$(KeyCode)", - "OperationSetCode": "MacAppDeveloperSign", - "parameters": [ - { - "parameterName": "hardening", - "parameterValue": "enable" - }, - { - "parameterName": "OpusInfo", - "parameterValue": "http://Microsoft.com" - } - ], + "OperationCode": "MacAppDeveloperSign", "ToolName": "sign", - "ToolVersion": "1.0" - }] - SessionTimeout: 90 - ServiceEndpointUrl: '$(ServiceEndpointUrl)' - MaxConcurrency: 25 + "ToolVersion": "1.0", + "Parameters": { + "Hardening": "Enable", + "OpusInfo": "http://microsoft.com" + } + } + ] - pwsh: | $signedPkg = Get-ChildItem -Path $(Pipeline.Workspace) -Filter "*osx*.zip" -File - + $signedPkg | ForEach-Object { Write-Verbose -Verbose "Signed package zip: $_" - + if (-not (Test-Path $_)) { throw "Package not found: $_" } - - if (-not (Test-Path $env:ob_outputDirectory)) { - $null = New-Item -Path $env:ob_outputDirectory -ItemType Directory + + if (-not (Test-Path $(ob_outputDirectory))) { + $null = New-Item -Path $(ob_outputDirectory) -ItemType Directory } - Expand-Archive -Path $_ -DestinationPath $env:ob_outputDirectory -Verbose + Expand-Archive -Path $_ -DestinationPath $(ob_outputDirectory) -Verbose } Write-Verbose -Verbose "Expanded pkg file:" - Get-ChildItem -Path $env:ob_outputDirectory | Write-Verbose -Verbose + Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose displayName: Expand signed file From a4fef36995bbe415218533ba3a997abd92b5820b Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 10 Apr 2025 16:20:09 -0700 Subject: [PATCH 085/275] [release/v7.5] Give the pipeline runs meaningful names (#25309) Co-authored-by: Travis Plunk --- .pipelines/PowerShell-Coordinated_Packages-Official.yml | 2 +- .pipelines/PowerShell-Packages-Official.yml | 2 ++ .pipelines/PowerShell-Release-Official-Azure.yml | 2 ++ .pipelines/PowerShell-Release-Official.yml | 2 ++ .pipelines/PowerShell-vPack-Official.yml | 4 ++-- 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index d478f351252..672674a21b7 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -1,4 +1,4 @@ -name: UnifiedPackageBuild-$(Build.BuildId) +name: bins-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) trigger: none parameters: diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index a39b4e866fc..7fce394ca19 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -24,6 +24,8 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Signing type: string default: 'NO' + +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index db6b114d901..acba669ffa3 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -14,6 +14,8 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: string default: 'NO' +name: ev2-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) + variables: - name: CDP_DEFINITION_BUILD_COUNT value: $[counter('', 0)] diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 30c820cabcc..8cda2f5c3b1 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -26,6 +26,8 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false +name: release-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) + variables: - name: CDP_DEFINITION_BUILD_COUNT value: $[counter('', 0)] diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 33eddc88d0e..6a4ceda5cac 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -1,5 +1,3 @@ -name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr) - trigger: none parameters: # parameters are shown up in ADO UI in a build queue time @@ -28,6 +26,8 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: 'Release Tag Var:' default: 'fromBranch' +name: vPack_${{ parameters.architecture }}_$(date:yyMM).$(date:dd)$(rev:rrr) + variables: - name: CDP_DEFINITION_BUILD_COUNT value: $[counter('', 0)] From b09675d12024205f6935c3f5666e6488f795c712 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 10 Apr 2025 16:20:37 -0700 Subject: [PATCH 086/275] [release/v7.5] Add Justin Chung as PowerShell team member in `releaseTools.psm1` (#25302) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung --- tools/releaseTools.psm1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/releaseTools.psm1 b/tools/releaseTools.psm1 index a50651d8889..71277a1c92e 100644 --- a/tools/releaseTools.psm1 +++ b/tools/releaseTools.psm1 @@ -43,6 +43,7 @@ $Script:powershell_team = @( "Patrick Meinecke" "Steven Bucher" "PowerShell Team Bot" + "Justin Chung" ) # They are very active contributors, so we keep their email-login mappings here to save a few queries to Github. From da482a8f17c4d57ea1e7e1dceba8009eb90e3c38 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 10 Apr 2025 16:31:09 -0700 Subject: [PATCH 087/275] [release/v7.5] Update path filters for Windows CI (#25312) Co-authored-by: Travis Plunk --- .vsts-ci/windows.yml | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/.vsts-ci/windows.yml b/.vsts-ci/windows.yml index ca5352cb4e2..f2f47698ee2 100644 --- a/.vsts-ci/windows.yml +++ b/.vsts-ci/windows.yml @@ -25,22 +25,17 @@ pr: - feature* paths: include: - - '*' + - src/* + - .vsts-ci/windows.yml + - .vsts-ci/templates/* + - test/* + - build.psm1 + - tools/buildCommon/* + - tools/ci.psm1 + - tools/WindowsCI.psm1 exclude: - - .dependabot/config.yml - - .github/ISSUE_TEMPLATE/* - - .github/workflows/* - - .vsts-ci/misc-analysis.yml - - tools/cgmanifest.json - - LICENSE.txt - test/common/markdown/* - - test/perf/* - - tools/packaging/* - - tools/releaseBuild/* - - tools/releaseBuild/azureDevOps/templates/* - - README.md - - .spelling - - .pipelines/* + - test/perf/* variables: GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" From 33e9d5810404b69bfa327548bc82fd6d0b8ae542 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 10 Apr 2025 16:34:08 -0700 Subject: [PATCH 088/275] [release/v7.5] Fix V-Pack download package name (#25314) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung Co-authored-by: Travis Plunk --- .pipelines/PowerShell-vPack-Official.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 6a4ceda5cac..3bf03b89e3f 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -138,7 +138,7 @@ extends: installationPath: $(Agent.ToolsDirectory)/dotnet - pwsh: | - $packageArtifactName = 'drop_windows_package_package_${{ parameters.architecture }}' + $packageArtifactName = 'drop_windows_package_package_win_${{ parameters.architecture }}' $vstsCommandString = "vso[task.setvariable variable=PackageArtifactName]$packageArtifactName" Write-Host "sending " + $vstsCommandString Write-Host "##$vstsCommandString" From 9d14d5068a07ac48913f91a586b1b9e7de3208a3 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 10 Apr 2025 16:35:51 -0700 Subject: [PATCH 089/275] [release/v7.5] Add *.props and sort path filters for windows CI (#25316) Co-authored-by: Travis Plunk --- .vsts-ci/windows.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.vsts-ci/windows.yml b/.vsts-ci/windows.yml index f2f47698ee2..c0f08f54a41 100644 --- a/.vsts-ci/windows.yml +++ b/.vsts-ci/windows.yml @@ -25,17 +25,18 @@ pr: - feature* paths: include: - - src/* - - .vsts-ci/windows.yml - .vsts-ci/templates/* - - test/* + - .vsts-ci/windows.yml + - '*.props' - build.psm1 + - src/* + - test/* - tools/buildCommon/* - tools/ci.psm1 - tools/WindowsCI.psm1 exclude: - test/common/markdown/* - - test/perf/* + - test/perf/* variables: GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" From 8ee12f6c526594ffeae070defcb16bdc5fe2efc9 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 12:39:54 -0700 Subject: [PATCH 090/275] [release/v7.5] Make sure the vPack pipeline does not produce an empty package (#25320) Co-authored-by: Travis Plunk --- .pipelines/PowerShell-vPack-Official.yml | 25 ++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 3bf03b89e3f..33c72f8963f 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -142,18 +142,27 @@ extends: $vstsCommandString = "vso[task.setvariable variable=PackageArtifactName]$packageArtifactName" Write-Host "sending " + $vstsCommandString Write-Host "##$vstsCommandString" - displayName: 'Set package artifact name' + + $packageArtifactPath = '$(Pipeline.Workspace)\PSPackagesOfficial' + $vstsCommandString = "vso[task.setvariable variable=PackageArtifactPath]$packageArtifactPath" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: 'Set package artifact variables' - download: PSPackagesOfficial artifact: $(PackageArtifactName) displayName: Download package - - pwsh: 'Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty Name' + - pwsh: 'Get-ChildItem $(PackageArtifactPath)\* -recurse | Select-Object -ExpandProperty Name' displayName: 'Capture Artifact Listing' - pwsh: | $message = @() - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -include *.zip, *.msi | ForEach-Object { + $packages = Get-ChildItem $(PackageArtifactPath)\* -recurse -include *.zip, *.msi + + if($packages.count -eq 0) {throw "No packages found in $(PackageArtifactPath)"} + + $packages | ForEach-Object { if($_.Name -notmatch 'PowerShell-\d+\.\d+\.\d+\-([a-z]*.\d+\-)?win\-(fxdependent|x64|arm64|x86|fxdependentWinDesktop)\.(msi|zip){1}') { $messageInstance = "$($_.Name) is not a valid package name" @@ -166,7 +175,7 @@ extends: displayName: 'Validate Zip and MSI Package Names' - pwsh: | - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -include *.zip, *.msi | ForEach-Object { + Get-ChildItem $(PackageArtifactPath)\* -recurse -include *.zip | ForEach-Object { if($_.Name -match 'PowerShell-\d+\.\d+\.\d+\-([a-z]*.\d+\-)?win\-(${{ parameters.architecture }})\.(zip){1}') { Expand-Archive -Path $_.FullName -DestinationPath $(ob_outputDirectory) @@ -197,7 +206,11 @@ extends: - pwsh: | Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose - Get-ChildItem -Path $(ob_outputDirectory)\* -Recurse + $vpackFiles = Get-ChildItem -Path $(ob_outputDirectory)\* -Recurse + if($vpackFiles.Count -eq 0) { + throw "No files found in $(ob_outputDirectory)" + } + $vpackFiles displayName: Debug Output Directory and Version condition: succeededOrFailed() @@ -207,5 +220,5 @@ extends: command: 'sign' signing_environment: 'azure-ado' cp_code: $(windows_build_tools_cert_id) - files_to_sign: '**/*.exe;**/*.dll;**/*.ps1;**/*.psm1' + files_to_sign: '**/*.exe;**/System.Management.Automation.dll' search_root: $(ob_outputDirectory) From dc5833b71ab9aa72487985913a27fc76b92658a0 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:02:24 -0700 Subject: [PATCH 091/275] [release/v7.5]!!!MERGE_CONFLICT!!! Remove Az module installs and AzureRM uninstalls in pipeline (#25327) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Travis Plunk --- .pipelines/PowerShell-Packages-Official.yml | 2 +- .../PowerShell-Release-Official-Azure.yml | 2 +- .pipelines/PowerShell-Release-Official.yml | 2 +- .pipelines/templates/checkAzureContainer.yml | 10 -------- .pipelines/templates/compliance/apiscan.yml | 13 ----------- .../templates/compliance/generateNotice.yml | 23 ------------------- .../templates/release-MakeBlobPublic.yml | 22 ------------------ .pipelines/templates/release-create-msix.yml | 3 ++- .../templates/release-upload-buildinfo.yml | 11 --------- .../release-validate-packagenames.yml | 12 ---------- .pipelines/templates/uploadToAzure.yml | 12 ---------- 11 files changed, 5 insertions(+), 107 deletions(-) diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 7fce394ca19..13fc4cf54be 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -64,7 +64,7 @@ variables: resources: pipelines: - pipeline: CoOrdinatedBuildPipeline - source: 'PowerShell-Coordinated Packages-Official' + source: 'PowerShell-Coordinated Binaries-Official' trigger: branches: include: diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index acba669ffa3..2d644c7a5dd 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -56,7 +56,7 @@ resources: pipelines: - pipeline: CoOrdinatedBuildPipeline - source: 'PowerShell-Coordinated Packages-Official' + source: 'PowerShell-Coordinated Binaries-Official' - pipeline: PSPackagesOfficial source: 'PowerShell-Packages-Official' diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 8cda2f5c3b1..6f7a6b5348a 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -72,7 +72,7 @@ resources: pipelines: - pipeline: CoOrdinatedBuildPipeline - source: 'PowerShell-Coordinated Packages-Official' + source: 'PowerShell-Coordinated Binaries-Official' - pipeline: PSPackagesOfficial source: 'PowerShell-Packages-Official' diff --git a/.pipelines/templates/checkAzureContainer.yml b/.pipelines/templates/checkAzureContainer.yml index a5ce2b1c666..f5e36f38a92 100644 --- a/.pipelines/templates/checkAzureContainer.yml +++ b/.pipelines/templates/checkAzureContainer.yml @@ -51,16 +51,6 @@ jobs: } displayName: 'Check suppress.json' - # Needed as per FAQ here: https://eng.ms/docs/products/onebranch/build/troubleshootingfaqs - - task: PowerShell@2 - displayName: 'Update Az.Storage Module' - inputs: - targetType: 'inline' - script: | - Get-PackageProvider -Name NuGet -ForceBootstrap - Install-Module -Name Az.Storage -Verbose -Force -AllowClobber - Uninstall-AzureRm -Verbose - - task: AzurePowerShell@5 displayName: Check if blob exists and delete if specified inputs: diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml index bfe97827801..4e945b40349 100644 --- a/.pipelines/templates/compliance/apiscan.yml +++ b/.pipelines/templates/compliance/apiscan.yml @@ -78,19 +78,6 @@ jobs: workingDirectory: '$(repoRoot)' retryCountOnTaskFailure: 2 - - pwsh: | - $modules = 'Az.Accounts', 'Az.Storage' - foreach($module in $modules) { - if(!(get-module $module -listavailable)) { - Write-Verbose "installing $module..." -verbose - Install-Module $module -force -AllowClobber - } else { - Write-Verbose "$module already installed." -verbose - } - } - displayName: Install PowerShell modules - workingDirectory: '$(repoRoot)' - - task: AzurePowerShell@5 displayName: Download winverify-private Artifacts inputs: diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml index 9a00ed6f01d..b9d489795b1 100644 --- a/.pipelines/templates/compliance/generateNotice.yml +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -95,29 +95,6 @@ jobs: Get-PackageProvider -Name NuGet -ForceBootstrap displayName: Initalize PowerShellGet - - powershell: | - $modules = 'Az.Accounts', 'Az.Storage' - foreach($module in $modules) { - if(!(get-module $module -listavailable)) { - Write-Verbose "installing $module..." -verbose - Install-Module $module -force -AllowClobber - } else { - Write-Verbose "$module already installed." -verbose - #Update-Module $module -verbose - } - } - displayName: Install PowerShell modules - - - powershell: | - if(Get-Command -Name Uninstall-AzureRm -ErrorAction Ignore){ - Write-Verbose "running Uninstall-AzureRm" -verbose - Uninstall-AzureRm - } else { - Write-Verbose "Uninstall-AzureRm not present" -verbose - } - displayName: Uninstall Uninstall-AzureRm - continueOnError: true - - task: AzurePowerShell@5 displayName: Upload Notice inputs: diff --git a/.pipelines/templates/release-MakeBlobPublic.yml b/.pipelines/templates/release-MakeBlobPublic.yml index 84a02c9e0f0..bfa07c9b27f 100644 --- a/.pipelines/templates/release-MakeBlobPublic.yml +++ b/.pipelines/templates/release-MakeBlobPublic.yml @@ -52,17 +52,6 @@ jobs: Get-ChildItem Env: displayName: 'Capture Environment Variables' - - pwsh: | - $azureRmModule = Get-InstalledModule AzureRM -ErrorAction SilentlyContinue -Verbose - if ($azureRmModule) { - Write-Host 'AzureRM module exists. Removing it' - Uninstall-AzureRm - Write-Host 'AzureRM module removed' - } - - Install-Module -Name Az.Storage -Force -AllowClobber -Scope CurrentUser -Verbose - displayName: Remove AzRM modules - - task: AzurePowerShell@5 displayName: Copy blobs to PSInfra storage inputs: @@ -150,17 +139,6 @@ jobs: Get-ChildItem Env: displayName: 'Capture Environment Variables' - - pwsh: | - $azureRmModule = Get-InstalledModule AzureRM -ErrorAction SilentlyContinue -Verbose - if ($azureRmModule) { - Write-Host 'AzureRM module exists. Removing it' - Uninstall-AzureRm - Write-Host 'AzureRM module removed' - } - - Install-Module -Name Az.Storage -Force -AllowClobber -Scope CurrentUser -Verbose - displayName: Remove AzRM modules - - task: AzurePowerShell@5 displayName: Copy blobs to PSInfra storage inputs: diff --git a/.pipelines/templates/release-create-msix.yml b/.pipelines/templates/release-create-msix.yml index 3b1573d9777..90d2acd493b 100644 --- a/.pipelines/templates/release-create-msix.yml +++ b/.pipelines/templates/release-create-msix.yml @@ -27,7 +27,8 @@ jobs: artifact: drop_windows_package_package_win_x86 displayName: Download x86 msix patterns: '**/*.msix' - + + # Finds the makeappx tool on the machine with image: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - pwsh: | $cmd = Get-Command makeappx.exe -ErrorAction Ignore if ($cmd) { diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index ea7b90db8e3..d35630168a0 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -104,17 +104,6 @@ jobs: } displayName: Create json files - - pwsh: | - $azureRmModule = Get-InstalledModule AzureRM -ErrorAction SilentlyContinue -Verbose - if ($azureRmModule) { - Write-Host 'AzureRM module exists. Removing it' - Uninstall-AzureRm - Write-Host 'AzureRM module removed' - } - - Install-Module -Name Az.Storage -Force -AllowClobber -Scope CurrentUser -Verbose - displayName: Remove AzRM modules - - task: AzurePowerShell@5 displayName: Upload buildjson to blob inputs: diff --git a/.pipelines/templates/release-validate-packagenames.yml b/.pipelines/templates/release-validate-packagenames.yml index 3e2987591aa..1eaf9c070ee 100644 --- a/.pipelines/templates/release-validate-packagenames.yml +++ b/.pipelines/templates/release-validate-packagenames.yml @@ -28,18 +28,6 @@ jobs: Write-Host "##vso[build.updatebuildnumber]$name" displayName: Set Release Name - - pwsh: | - $azureRmModule = Get-InstalledModule AzureRM -ErrorAction SilentlyContinue -Verbose - if ($azureRmModule) { - Write-Host 'AzureRM module exists. Removing it' - Uninstall-AzureRm - Write-Host 'AzureRM module removed' - } - - Install-Module -Name Az.Storage -Force -AllowClobber -Scope CurrentUser -Verbose - - displayName: Remove AzRM modules and install Az.Storage - - task: AzurePowerShell@5 displayName: Upload packages to blob inputs: diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index 35a11ec383c..5c0d80ec10f 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -256,18 +256,6 @@ jobs: New-Item -Path $(Build.ArtifactStagingDirectory)/uploaded -ItemType Directory -Force displayName: Create output directory for packages - - pwsh: | - $azureRmModule = Get-InstalledModule AzureRM -ErrorAction SilentlyContinue -Verbose - if ($azureRmModule) { - Write-Host 'AzureRM module exists. Removing it' - Uninstall-AzureRm - Write-Host 'AzureRM module removed' - } - - Install-Module -Name Az.Storage -Force -AllowClobber -Scope CurrentUser -Verbose - - displayName: Remove AzRM modules - - task: AzurePowerShell@5 displayName: Upload packages to blob inputs: From 7ff28d37381bc77d5f736e5f79a26657571d7b2d Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:09:10 -0700 Subject: [PATCH 092/275] [release/v7.5] Make Component Manifest Updater use neutral target in addition to RID target (#25325) Co-authored-by: Travis Plunk --- tools/findMissingNotices.ps1 | 63 +++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/tools/findMissingNotices.ps1 b/tools/findMissingNotices.ps1 index 490edebb81b..d02f5eedb36 100644 --- a/tools/findMissingNotices.ps1 +++ b/tools/findMissingNotices.ps1 @@ -203,28 +203,34 @@ function Get-CGRegistrations { "alpine-.*" { $folder = $unixProjectName $target = "$dotnetTargetName|$Runtime" + $neutralTarget = "$dotnetTargetName" } "linux-.*" { $folder = $unixProjectName $target = "$dotnetTargetName|$Runtime" + $neutralTarget = "$dotnetTargetName" } "osx-.*" { $folder = $unixProjectName $target = "$dotnetTargetName|$Runtime" + $neutralTarget = "$dotnetTargetName" } "win-x*" { $sdkToUse = $winDesktopSdk $folder = $windowsProjectName $target = "$dotnetTargetNameWin7|$Runtime" + $neutralTarget = "$dotnetTargetNameWin7" } "win-.*" { $folder = $windowsProjectName $target = "$dotnetTargetNameWin7|$Runtime" + $neutralTarget = "$dotnetTargetNameWin7" } "modules" { $folder = "modules" $actualRuntime = 'linux-x64' $target = "$dotnetTargetName|$actualRuntime" + $neutralTarget = "$dotnetTargetName" } Default { throw "Invalid runtime name: $Runtime" @@ -241,6 +247,7 @@ function Get-CGRegistrations { $null = New-PADrive -Path $PSScriptRoot\..\src\$folder\obj\project.assets.json -Name $folder try { $targets = Get-ChildItem -Path "${folder}:/targets/$target" -ErrorAction Stop | Where-Object { $_.Type -eq 'package' } | select-object -ExpandProperty name + $targets += Get-ChildItem -Path "${folder}:/targets/$neutralTarget" -ErrorAction Stop | Where-Object { $_.Type -eq 'project' } | select-object -ExpandProperty name } catch { Get-ChildItem -Path "${folder}:/targets" | Out-String | Write-Verbose -Verbose throw @@ -250,27 +257,51 @@ function Get-CGRegistrations { Get-PSDrive -Name $folder -ErrorAction Ignore | Remove-PSDrive } + # Name to skip for TPN generation + $skipNames = @( + "Microsoft.PowerShell.Native" + "Microsoft.Management.Infrastructure.Runtime.Unix" + "Microsoft.Management.Infrastructure" + "Microsoft.PowerShell.Commands.Diagnostics" + "Microsoft.PowerShell.Commands.Management" + "Microsoft.PowerShell.Commands.Utility" + "Microsoft.PowerShell.ConsoleHost" + "Microsoft.PowerShell.SDK" + "Microsoft.PowerShell.Security" + "Microsoft.Management.Infrastructure.CimCmdlets" + "Microsoft.WSMan.Management" + "Microsoft.WSMan.Runtime" + "System.Management.Automation" + ) + + Write-Verbose "Found $($targets.Count) targets to process..." -Verbose $targets | ForEach-Object { $target = $_ $parts = ($target -split '\|') $name = $parts[0] - $targetVersion = $parts[1] - $publicVersion = Get-NuGetPublicVersion -Name $name -Version $targetVersion - - # Add the registration to the cgmanifest if the TPN does not contain the name of the target OR - # the exisitng CG contains the registration, because if the existing CG contains the registration, - # that might be the only reason it is in the TPN. - if (!$RegistrationTable.ContainsKey($target)) { - $DevelopmentDependency = $false - if (!$existingRegistrationTable.ContainsKey($name) -or $existingRegistrationTable.$name.Component.Version() -ne $publicVersion) { - $registrationChanged = $true - } - if ($existingRegistrationTable.ContainsKey($name) -and $existingRegistrationTable.$name.DevelopmentDependency) { - $DevelopmentDependency = $true - } - $registration = New-NugetComponent -Name $name -Version $publicVersion -DevelopmentDependency:$DevelopmentDependency - $RegistrationTable.Add($target, $registration) + if ($name -in $skipNames) { + Write-Verbose "Skipping $name..." + + } else { + $targetVersion = $parts[1] + $publicVersion = Get-NuGetPublicVersion -Name $name -Version $targetVersion + + # Add the registration to the cgmanifest if the TPN does not contain the name of the target OR + # the exisitng CG contains the registration, because if the existing CG contains the registration, + # that might be the only reason it is in the TPN. + if (!$RegistrationTable.ContainsKey($target)) { + $DevelopmentDependency = $false + if (!$existingRegistrationTable.ContainsKey($name) -or $existingRegistrationTable.$name.Component.Version() -ne $publicVersion) { + $registrationChanged = $true + } + if ($existingRegistrationTable.ContainsKey($name) -and $existingRegistrationTable.$name.DevelopmentDependency) { + $DevelopmentDependency = $true + } + + $registration = New-NugetComponent -Name $name -Version $publicVersion -DevelopmentDependency:$DevelopmentDependency + $RegistrationTable.Add($target, $registration) + } } } From 9b4168119229169db75f087b38072a0ff48c7c57 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:24:00 -0700 Subject: [PATCH 093/275] [release/v7.5] Only build Linux for packaging changes (#25326) Co-authored-by: Travis Plunk --- .vsts-ci/linux-internal.yml | 116 ++++++++++++++++++++++++++++++++++++ .vsts-ci/linux.yml | 28 ++++----- 2 files changed, 126 insertions(+), 18 deletions(-) create mode 100644 .vsts-ci/linux-internal.yml diff --git a/.vsts-ci/linux-internal.yml b/.vsts-ci/linux-internal.yml new file mode 100644 index 00000000000..6286a03fb52 --- /dev/null +++ b/.vsts-ci/linux-internal.yml @@ -0,0 +1,116 @@ +# Pipeline to run Linux CI internally +name: PR-$(System.PullRequest.PullRequestNumber)-$(Date:yyyyMMdd)$(Rev:.rr) +trigger: + # Batch merge builds together while a merge build is running + batch: true + branches: + include: + - master + - release* + - feature* + paths: + include: + - '*' + exclude: + - .vsts-ci/misc-analysis.yml + - .github/ISSUE_TEMPLATE/* + - .github/workflows/* + - .dependabot/config.yml + - .pipelines/* + - test/perf/* +pr: + branches: + include: + - master + - release* + - feature* + paths: + include: + - '*' + exclude: + - .dependabot/config.yml + - .github/ISSUE_TEMPLATE/* + - .github/workflows/* + - .vsts-ci/misc-analysis.yml + - .vsts-ci/windows.yml + - .vsts-ci/windows/* + - tools/cgmanifest.json + - LICENSE.txt + - test/common/markdown/* + - test/perf/* + - tools/releaseBuild/* + - tools/install* + - tools/releaseBuild/azureDevOps/templates/* + - README.md + - .spelling + - .pipelines/* + +variables: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + +resources: + repositories: + - repository: Docker + type: github + endpoint: PowerShell + name: PowerShell/PowerShell-Docker + ref: master + +stages: +- stage: BuildLinuxStage + displayName: Build for Linux + jobs: + - template: templates/ci-build.yml + parameters: + pool: ubuntu-20.04 + jobName: linux_build + displayName: linux Build + +- stage: TestUbuntu + displayName: Test for Ubuntu + dependsOn: [BuildLinuxStage] + jobs: + - template: templates/nix-test.yml + parameters: + name: Ubuntu + pool: ubuntu-20.04 + purpose: UnelevatedPesterTests + tagSet: CI + + - template: templates/nix-test.yml + parameters: + name: Ubuntu + pool: ubuntu-20.04 + purpose: ElevatedPesterTests + tagSet: CI + + - template: templates/nix-test.yml + parameters: + name: Ubuntu + pool: ubuntu-20.04 + purpose: UnelevatedPesterTests + tagSet: Others + + - template: templates/nix-test.yml + parameters: + name: Ubuntu + pool: ubuntu-20.04 + purpose: ElevatedPesterTests + tagSet: Others + + - template: templates/verify-xunit.yml + parameters: + pool: ubuntu-20.04 + +- stage: PackageLinux + displayName: Package Linux + dependsOn: ["BuildLinuxStage"] + jobs: + - template: linux/templates/packaging.yml + parameters: + pool: ubuntu-20.04 diff --git a/.vsts-ci/linux.yml b/.vsts-ci/linux.yml index b1bb74197a0..338821e37dd 100644 --- a/.vsts-ci/linux.yml +++ b/.vsts-ci/linux.yml @@ -34,24 +34,16 @@ pr: - feature* paths: include: - - '*' - exclude: - - .dependabot/config.yml - - .github/ISSUE_TEMPLATE/* - - .github/workflows/* - - .vsts-ci/misc-analysis.yml - - .vsts-ci/windows.yml - - .vsts-ci/windows/* - - tools/cgmanifest.json - - LICENSE.txt - - test/common/markdown/* - - test/perf/* - - tools/releaseBuild/* - - tools/install* - - tools/releaseBuild/azureDevOps/templates/* - - README.md - - .spelling - - .pipelines/* + - .vsts-ci/linux.yml + - .vsts-ci/linux/templates/packaging.yml + - assets/manpage/* + - build.psm1 + - global.json + - nuget.config + - PowerShell.Common.props + - src/*.csproj + - tools/ci.psm1 + - tools/packaging/* variables: DOTNET_CLI_TELEMETRY_OPTOUT: 1 From c6bb5074a3a38614c521040887f3c2b29e580017 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:25:39 -0700 Subject: [PATCH 094/275] [release/v7.5] Check GH token availability for Get-Changelog (#25328) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung Co-authored-by: Travis Plunk --- tools/releaseTools.psm1 | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/tools/releaseTools.psm1 b/tools/releaseTools.psm1 index 71277a1c92e..6207c4be3f7 100644 --- a/tools/releaseTools.psm1 +++ b/tools/releaseTools.psm1 @@ -151,13 +151,20 @@ function Get-ChangeLog [Parameter(Mandatory = $true)] [string]$ThisReleaseTag, - [Parameter(Mandatory)] + [Parameter(Mandatory = $false)] [string]$Token, [Parameter()] [switch]$HasCherryPick ) + if(-not $Token) { + $Token = Get-GHDefaultAuthToken + if(-not $Token) { + throw "No GitHub Auth Token provided" + } + } + $tag_hash = git rev-parse "$LastReleaseTag^0" $format = '%H||%P||%aN||%aE||%s' $header = @{"Authorization"="token $Token"} @@ -361,6 +368,29 @@ function Get-ChangeLog Write-Output "[${version}]: https://github.com/PowerShell/PowerShell/compare/${LastReleaseTag}...${ThisReleaseTag}`n" } +function Get-GHDefaultAuthToken { + $IsGHCLIInstalled = $false + if (Get-command -CommandType Application -Name gh -ErrorAction SilentlyContinue) { + $IsGHCLIInstalled = $true + } else { + Write-Error -Message "GitHub CLI is not installed. Please install it from https://cli.github.com/" -ErrorAction Stop + } + + if ($IsGHCLIInstalled) { + try { + $Token = & gh auth token + } catch { + Write-Error -Message "Please login to GitHub CLI using 'gh auth login'" + } + } + + if (-not $Token) { + $Token = Read-Host -Prompt "Enter GitHub Auth Token" + } + + return $Token +} + function PrintChangeLog($clSection, $sectionTitle, [switch] $Compress) { if ($clSection.Count -gt 0) { "### $sectionTitle`n" From 6781b392276d286e94469bca4c30683d053fab5d Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:32:19 -0700 Subject: [PATCH 095/275] [release/v7.5] Skip additional packages when generating component manifest (#25329) Co-authored-by: Travis Plunk --- tools/findMissingNotices.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/findMissingNotices.ps1 b/tools/findMissingNotices.ps1 index d02f5eedb36..3200bdeeaaf 100644 --- a/tools/findMissingNotices.ps1 +++ b/tools/findMissingNotices.ps1 @@ -272,6 +272,8 @@ function Get-CGRegistrations { "Microsoft.WSMan.Management" "Microsoft.WSMan.Runtime" "System.Management.Automation" + "Microsoft.PowerShell.GraphicalHost" + "Microsoft.PowerShell.CoreCLR.Eventing" ) Write-Verbose "Found $($targets.Count) targets to process..." -Verbose From dc5461e90ef05cd91e69b06edcd6a13c396c479b Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:34:28 -0700 Subject: [PATCH 096/275] [release/v7.5] Update package pipeline windows image version (#25331) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung Co-authored-by: Travis Plunk --- .pipelines/PowerShell-Packages-Official.yml | 5 ++++- .pipelines/templates/checkAzureContainer.yml | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 13fc4cf54be..30b9e415215 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -51,7 +51,7 @@ variables: - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' # Docker image which is used to build the project + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' # Docker image which is used to build the project - name: LinuxContainerImage value: mcr.microsoft.com/onebranch/cbl-mariner/build:2.0 - group: mscodehub-feed-read-general @@ -83,6 +83,9 @@ extends: cloudvault: enabled: false featureFlags: + WindowsHostVersion: + Version: 2022 + Network: KS3 linuxEsrpSigning: true globalSdl: disableLegacyManifest: true diff --git a/.pipelines/templates/checkAzureContainer.yml b/.pipelines/templates/checkAzureContainer.yml index f5e36f38a92..a6a86214d07 100644 --- a/.pipelines/templates/checkAzureContainer.yml +++ b/.pipelines/templates/checkAzureContainer.yml @@ -56,7 +56,8 @@ jobs: inputs: azureSubscription: az-blob-cicd-infra scriptType: inlineScript - azurePowerShellVersion: latestVersion + azurePowerShellVersion: LatestVersion + pwsh: true inline: | $containersToDelete = @('$(AzureVersion)', '$(AzureVersion)-private', '$(AzureVersion)-nuget', '$(AzureVersion)-gc') From e671bffe56e487c8926ca01ba7ca40c6d77d600f Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:41:12 -0700 Subject: [PATCH 097/275] [release/v7.5] Simplify PR Template (#25333) Co-authored-by: Travis Plunk Co-authored-by: Dongbo Wang --- .github/PULL_REQUEST_TEMPLATE.md | 18 ++---------------- .github/workflows/markdownLink.yml | 19 +++++++++++++------ .prettierrc | 4 ++++ tools/super-linter/config/super-linter.env | 8 ++++++++ tools/super-linter/super-linter.ps1 | 15 +++++++++++++++ 5 files changed, 42 insertions(+), 22 deletions(-) create mode 100644 .prettierrc create mode 100644 tools/super-linter/config/super-linter.env create mode 100644 tools/super-linter/super-linter.ps1 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a3dc6fd5198..27089847987 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -14,8 +14,7 @@ - Use the present tense and imperative mood when describing your changes - [ ] [Summarized changes](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) - [ ] [Make sure all `.h`, `.cpp`, `.cs`, `.ps1` and `.psm1` files have the correct copyright header](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) -- [ ] This PR is ready to merge and is not [Work in Progress](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---work-in-progress). - - If the PR is work in progress, please add the prefix `WIP:` or `[ WIP ]` to the beginning of the title (the `WIP` bot will keep its status check at `Pending` while the prefix is present) and remove the prefix when the PR is ready. +- [ ] This PR is ready to merge. If this PR is a work in progress, please open this as a [Draft Pull Request and mark it as Ready to Review when it is ready to merge](https://docs.github.com/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests). - **[Breaking changes](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#making-breaking-changes)** - [ ] None - **OR** @@ -25,21 +24,8 @@ - [ ] Not Applicable - **OR** - [ ] [Documentation needed](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) - - [ ] Issue filed: + - [ ] Issue filed: - **Testing - New and feature** - [ ] N/A or can only be tested interactively - **OR** - [ ] [Make sure you've added a new test if existing tests do not effectively test the code changed](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#before-submitting) -- **Tooling** - - [ ] I have considered the user experience from a tooling perspective and don't believe tooling will be impacted. - - **OR** - - [ ] I have considered the user experience from a tooling perspective and opened an issue in the relevant tool repository. This may include: - - [ ] Impact on [PowerShell Editor Services](https://github.com/PowerShell/PowerShellEditorServices) which is used in the [PowerShell extension](https://github.com/PowerShell/vscode-powershell) for VSCode - (which runs in a different PS Host). - - [ ] Issue filed: - - [ ] Impact on Completions (both in the console and in editors) - one of PowerShell's most powerful features. - - [ ] Issue filed: - - [ ] Impact on [PSScriptAnalyzer](https://github.com/PowerShell/PSScriptAnalyzer) (which provides linting & formatting in the editor extensions). - - [ ] Issue filed: - - [ ] Impact on [EditorSyntax](https://github.com/PowerShell/EditorSyntax) (which provides syntax highlighting with in VSCode, GitHub, and many other editors). - - [ ] Issue filed: diff --git a/.github/workflows/markdownLink.yml b/.github/workflows/markdownLink.yml index baf668d83d1..950534f1e56 100644 --- a/.github/workflows/markdownLink.yml +++ b/.github/workflows/markdownLink.yml @@ -31,13 +31,20 @@ jobs: # Full git history is needed to get a proper # list of changed files within `super-linter` fetch-depth: 0 + - name: Load super-linter configuration + # Use grep inverse matching to exclude eventual comments in the .env file + # because the GitHub Actions command to set environment variables doesn't + # support comments. + # Ref: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-environment-variable + run: grep -v '^#' tools/super-linter/config/super-linter.env >> "$GITHUB_ENV" - name: Lint Markdown uses: super-linter/super-linter@b4515bd4ad9d0aa4681960e053916ab991bdbe96 # v6.8.0 env: - VALIDATE_ALL_CODEBASE: false - DEFAULT_BRANCH: master - FILTER_REGEX_INCLUDE: .*\.md GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VALIDATE_EDITORCONFIG: false - VALIDATE_JSCPD: false - VALIDATE_CHECKOV: false + - name: Super-Linter correction instructions + if: failure() + uses: actions/github-script@v7.0.1 + with: + script: | + const message = "Super-Linter found issues in the changed files. Please check the logs for details. You can run the linter locally using the command: `./tools/super-lister/super-lister.ps1`."; + core.setFailed(message); diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000000..222861c3415 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "tabWidth": 2, + "useTabs": false +} diff --git a/tools/super-linter/config/super-linter.env b/tools/super-linter/config/super-linter.env new file mode 100644 index 00000000000..e7324b0feb9 --- /dev/null +++ b/tools/super-linter/config/super-linter.env @@ -0,0 +1,8 @@ +VALIDATE_ALL_CODEBASE=false +DEFAULT_BRANCH=master +FILTER_REGEX_INCLUDE=.*\.md +VALIDATE_EDITORCONFIG=false +VALIDATE_JSCPD=false +VALIDATE_CHECKOV=false +FIX_MARKDOWN_PRETTIER=true +FIX_MARKDOWN=true diff --git a/tools/super-linter/super-linter.ps1 b/tools/super-linter/super-linter.ps1 new file mode 100644 index 00000000000..571ba9c7f8d --- /dev/null +++ b/tools/super-linter/super-linter.ps1 @@ -0,0 +1,15 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +param( + [string]$RepoRoot = (Join-Path -Path $PSScriptRoot -ChildPath '../..'), + [string]$Platform +) + +$resolvedPath = (Resolve-Path $RepoRoot).ProviderPath +$platformParam = @() +if ($Platform) { + $platformParam = @("--platform", $Platform) +} + +docker run $platformParam -e RUN_LOCAL=true --env-file "$PSScriptRoot/config/super-linter.env" -v "${resolvedPath}:/tmp/lint" ghcr.io/super-linter/super-linter:latest From 8b196aa3edb611210e73e022b590944cb6a34367 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:47:19 -0700 Subject: [PATCH 098/275] [release/v7.5] Update CODEOWNERS (#25321) Co-authored-by: Aditya Patwardhan Co-authored-by: Travis Plunk --- .github/CODEOWNERS | 52 ++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 26e01101693..d4adcefefad 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -6,72 +6,60 @@ # Area: Performance # @adityapatwardhan -# Area: Portability -# @JamesWTruher - # Area: Security -# @TravisEz13 @PaulHigin -src/System.Management.Automation/security/wldpNativeMethods.cs @TravisEz13 @PaulHigin - -# Area: Documentation -.github/ @joeyaiello @TravisEz13 +src/System.Management.Automation/security/wldpNativeMethods.cs @TravisEz13 @seeminglyscience -# Area: Test -# @JamesWTruher @TravisEz13 @adityapatwardhan - -# Area: Cmdlets Core -# @JamesWTruher @SteveL-MSFT @anmenaga +# Area: CI Build +.github/workflows @PowerShell/powershell-maintainers +.github/actions @PowerShell/powershell-maintainers # Now, areas that should have paths or filters, although we might not have them defined # According to the docs, order here must be by precedence of the filter, with later rules overwritting # but the feature seems to make taking a union of all the matching rules. # Area: Cmdlets Management -src/Microsoft.PowerShell.Commands.Management/ @daxian-dbw @adityapatwardhan +# src/Microsoft.PowerShell.Commands.Management/ @daxian-dbw @adityapatwardhan # Area: Utility Cmdlets -src/Microsoft.PowerShell.Commands.Utility/ @JamesWTruher @PaulHigin +# src/Microsoft.PowerShell.Commands.Utility/ # Area: Console -src/Microsoft.PowerShell.ConsoleHost/ @daxian-dbw @anmenaga @TylerLeonhardt - -# Area: Demos -demos/ @joeyaiello @SteveL-MSFT @HemantMahawar +# src/Microsoft.PowerShell.ConsoleHost/ @daxian-dbw # Area: DSC -src/System.Management.Automation/DscSupport @TravisEz13 @SteveL-MSFT +# src/System.Management.Automation/DscSupport @TravisEz13 @SteveL-MSFT # Area: Engine # src/System.Management.Automation/engine @daxian-dbw # Area: Debugging # Must be below engine to override -src/System.Management.Automation/engine/debugger/ @PaulHigin +# src/System.Management.Automation/engine/debugger/ # Area: Help -src/System.Management.Automation/help @adityapatwardhan +src/System.Management.Automation/help @adityapatwardhan @daxian-dbw # Area: Intellisense # @daxian-dbw # Area: Language -src/System.Management.Automation/engine/parser @daxian-dbw +src/System.Management.Automation/engine/parser @daxian-dbw @seeminglyscience # Area: Providers -src/System.Management.Automation/namespaces @anmenaga +# src/System.Management.Automation/namespaces # Area: Remoting -src/System.Management.Automation/engine/remoting @PaulHigin +src/System.Management.Automation/engine/remoting @daxian-dbw @TravisEz13 # Areas: Build # Must be last -*.config @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin -*.props @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin -*.yml @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin -*.csproj @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin -build.* @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin -tools/ @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin -docker/ @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin +*.config @PowerShell/powershell-maintainers +*.props @PowerShell/powershell-maintainers +*.yml @PowerShell/powershell-maintainers +*.csproj @PowerShell/powershell-maintainers +build.* @PowerShell/powershell-maintainers +tools/ @PowerShell/powershell-maintainers +# docker/ @PowerShell/powershell-maintainers # Area: Compliance tools/terms @TravisEz13 From 307c0d9c23965420c74846a0d57d7ed16fe8e9f4 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:49:15 -0700 Subject: [PATCH 099/275] [release/v7.5] Remove call to NuGet (#25334) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung --- .pipelines/templates/compliance/generateNotice.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml index b9d489795b1..7de316e8b49 100644 --- a/.pipelines/templates/compliance/generateNotice.yml +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -84,17 +84,6 @@ jobs: displayName: Capture Notice continueOnError: true - - powershell: | - [System.Net.ServicePointManager]::SecurityProtocol = - [System.Net.ServicePointManager]::SecurityProtocol -bor - [System.Security.Authentication.SslProtocols]::Tls12 -bor - [System.Security.Authentication.SslProtocols]::Tls11 - - Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord - Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord - Get-PackageProvider -Name NuGet -ForceBootstrap - displayName: Initalize PowerShellGet - - task: AzurePowerShell@5 displayName: Upload Notice inputs: From de9f4c8c170a5348ed00f9a9f54eb768035a9764 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:59:05 -0700 Subject: [PATCH 100/275] [release/v7.5] Revert "Cleanup old release pipelines (#25201)" (#25335) Co-authored-by: Aditya Patwardhan --- tools/releaseBuild/setReleaseTag.ps1 | 161 +++++++++++++++++++++++++++ tools/releaseBuild/setReleaseTag.sh | 1 + 2 files changed, 162 insertions(+) create mode 100644 tools/releaseBuild/setReleaseTag.ps1 create mode 100644 tools/releaseBuild/setReleaseTag.sh diff --git a/tools/releaseBuild/setReleaseTag.ps1 b/tools/releaseBuild/setReleaseTag.ps1 new file mode 100644 index 00000000000..c5f2f016554 --- /dev/null +++ b/tools/releaseBuild/setReleaseTag.ps1 @@ -0,0 +1,161 @@ +param( + [Parameter(HelpMessage='ReleaseTag from the job. Set to "fromBranch" or $null to update using the branch name')] + [string]$ReleaseTag, + + [Parameter(HelpMessage='The branch name used to update the release tag.')] + [string]$Branch=$env:BUILD_SOURCEBRANCH, + + [Parameter(HelpMessage='The variable name to put the new release tagin.')] + [string]$Variable='ReleaseTag', + + [switch]$CreateJson +) + +function New-BuildInfoJson { + param( + [parameter(Mandatory = $true)] + [string] + $ReleaseTag, + [switch] $IsDaily + ) + + $blobName = $ReleaseTag -replace '\.', '-' + + $isPreview = $ReleaseTag -like '*-*' + + $filename = 'stable.json' + if($isPreview) + { + $filename = 'preview.json' + } + if($IsDaily.IsPresent) + { + $filename = 'daily.json' + } + + ## Get the UTC time and round up to the second. + $dateTime = [datetime]::UtcNow + $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) + + @{ + ReleaseTag = $ReleaseTag + ReleaseDate = $dateTime + BlobName = $blobName + BaseUrl = 'https://powershellinfraartifacts-gkhedzdeaghdezhr.z01.azurefd.net/install' + } | ConvertTo-Json | Out-File -Encoding ascii -Force -FilePath $filename + + $resolvedPath = (Resolve-Path -Path $filename).ProviderPath + $vstsCommandString = "vso[task.setvariable variable=BuildInfoPath]$resolvedPath" + Write-Verbose -Message "$vstsCommandString" -Verbose + Write-Host -Object "##$vstsCommandString" + + # Upload for ADO pipelines + Write-Host "##vso[artifact.upload containerfolder=BuildInfoJson;artifactname=BuildInfoJson]$resolvedPath" + + # Copy to location where OneBranch Pipelines uploads from + + # if the environment variable does not exist, we are not in OneBranch. So just return. + if (-not $env:ob_outputDirectory) { + return + } + + if (-not (Test-Path $env:ob_outputDirectory)) { + $null = New-Item -Path $env:ob_outputDirectory -ItemType Directory -Force -Verbose + } + + Copy-Item $resolvedPath -Destination $env:ob_outputDirectory -Force -Verbose +} + +# Script to set the release tag based on the branch name if it is not set or it is "fromBranch" +# the branch name is expected to be release- or +# VSTS passes it as 'refs/heads/release-v6.0.2' + +$branchOnly = $Branch -replace '^refs/heads/'; +$branchOnly = $branchOnly -replace '[_\-]' + +$msixType = 'preview' + +$isDaily = $false + +if($ReleaseTag -eq 'fromBranch' -or !$ReleaseTag) +{ + # Branch is named release- + $releaseBranchRegex = '^.*((release/|rebuild/.*rebuild))' + if($Branch -match $releaseBranchRegex) + { + $msixType = 'release' + Write-Verbose "release branch:" -Verbose + $releaseTag = $Branch -replace '^.*((release|rebuild)/)' + $vstsCommandString = "vso[task.setvariable variable=$Variable]$releaseTag" + Write-Verbose -Message "setting $Variable to $releaseTag" -Verbose + Write-Host -Object "##$vstsCommandString" + + if ($CreateJson.IsPresent) + { + New-BuildInfoJson -ReleaseTag $releaseTag + } + } + elseif(($branchOnly -eq 'master' -and $env:BUILD_REASON -ne 'Manual') -or $branchOnly -like '*dailytest*') + { + $isDaily = $true + Write-Verbose "daily build" -Verbose + $jsonPath = "${env:SYSTEM_ARTIFACTSDIRECTORY}\BuildInfoJson\daily.json" + if (test-path -Path $jsonPath) { + Write-Verbose "restoring from buildinfo json..." -Verbose + $buildInfo = Get-Content -Path $jsonPath | ConvertFrom-Json + $releaseTag = $buildInfo.ReleaseTag + } else { + Write-Verbose "creating from branch counter and metadata.json..." -Verbose + $metaDataJsonPath = Join-Path $PSScriptRoot -ChildPath '..\metadata.json' + $metadata = Get-Content $metaDataJsonPath | ConvertFrom-Json + $versionPart = $metadata.PreviewReleaseTag + if ($versionPart -match '-.*$') { + $versionPart = $versionPart -replace '-.*$' + } + + $releaseTag = "$versionPart-daily$((Get-Date).ToString('yyyyMMdd')).$($env:BRANCHCOUNTER)" + } + + $vstsCommandString = "vso[task.setvariable variable=$Variable]$releaseTag" + Write-Verbose -Message "setting $Variable to $releaseTag" -Verbose + Write-Host -Object "##$vstsCommandString" + + if ($CreateJson.IsPresent) + { + New-BuildInfoJson -ReleaseTag $releaseTag -IsDaily + } + } + else + { + Write-Verbose "non-release branch" -Verbose + # Branch is named + # Get version from metadata and append - + $metaDataJsonPath = Join-Path $PSScriptRoot -ChildPath '..\metadata.json' + $metadata = Get-Content $metaDataJsonPath | ConvertFrom-Json + $versionPart = $metadata.PreviewReleaseTag + if($versionPart -match '-.*$') + { + $versionPart = $versionPart -replace '-.*$' + } + + $releaseTag = "$versionPart-$branchOnly" + $vstsCommandString = "vso[task.setvariable variable=$Variable]$releaseTag" + Write-Verbose -Message "setting $Variable to $releaseTag" -Verbose + Write-Host -Object "##$vstsCommandString" + + if ($CreateJson.IsPresent) + { + New-BuildInfoJson -ReleaseTag $releaseTag + } + } +} + +$vstsCommandString = "vso[task.setvariable variable=IS_DAILY]$($isDaily.ToString().ToLowerInvariant())" +Write-Verbose -Message "$vstsCommandString" -Verbose +Write-Host -Object "##$vstsCommandString" + +$vstsCommandString = "vso[task.setvariable variable=MSIX_TYPE]$msixType" +Write-Verbose -Message "$vstsCommandString" -Verbose +Write-Host -Object "##$vstsCommandString" + +Write-Output $releaseTag diff --git a/tools/releaseBuild/setReleaseTag.sh b/tools/releaseBuild/setReleaseTag.sh new file mode 100644 index 00000000000..842ba1e755b --- /dev/null +++ b/tools/releaseBuild/setReleaseTag.sh @@ -0,0 +1 @@ +pwsh -command ".\setReleaseTag.ps1 $*" From 2e0faf7ca31d3bfc56cbcac648d1be6766157001 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:02:06 -0700 Subject: [PATCH 101/275] [release/v7.5] Update GitHub Actions to work in private GitHub repo (#25332) Co-authored-by: Travis Plunk --- .github/workflows/AssignPrs.yml | 1 + .github/workflows/createReminders.yml | 2 ++ .github/workflows/labels.yml | 2 +- .github/workflows/linux-ci.yml | 5 +++-- .github/workflows/macos-ci.yml | 5 +++-- .github/workflows/markdownLink.yml | 2 ++ .github/workflows/processReminders.yml | 1 + .github/workflows/scorecards.yml | 1 + .github/workflows/windows-ci.yml | 5 +++-- 9 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/workflows/AssignPrs.yml b/.github/workflows/AssignPrs.yml index d398cd7cffe..a01c0bb0950 100644 --- a/.github/workflows/AssignPrs.yml +++ b/.github/workflows/AssignPrs.yml @@ -7,6 +7,7 @@ permissions: jobs: run: + if: github.repository_owner == 'PowerShell' runs-on: ubuntu-latest permissions: issues: write diff --git a/.github/workflows/createReminders.yml b/.github/workflows/createReminders.yml index ef2c5fa1cce..0333b635d59 100644 --- a/.github/workflows/createReminders.yml +++ b/.github/workflows/createReminders.yml @@ -9,6 +9,8 @@ permissions: jobs: reminder: + if: github.repository_owner == 'PowerShell' + permissions: issues: write # for agrc/create-reminder-action to set reminders on issues pull-requests: write # for agrc/create-reminder-action to set reminders on PRs diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index 794ef64b213..fdb0ae4cd77 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -13,7 +13,7 @@ permissions: jobs: verify-labels: - if: github.repository_owner == 'PowerShell' + if: startsWith(github.repository_owner, 'azure') || github.repository_owner == 'PowerShell' runs-on: ubuntu-latest steps: diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 68b651c7e46..d7d76310846 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -37,6 +37,7 @@ env: system_debug: 'false' jobs: changes: + if: startsWith(github.repository_owner, 'azure') || github.repository_owner == 'PowerShell' name: Change Detection runs-on: ubuntu-latest # Required permissions @@ -50,7 +51,7 @@ jobs: uses: actions/checkout@v4.1.0 # For pull requests it's not necessary to checkout the code - - uses: dorny/paths-filter@v3 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.2.0 id: filter with: list-files: json @@ -232,7 +233,7 @@ jobs: - linux_test_unelevated_others - analyze if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@master + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: needs_context: ${{ toJson(needs) }} # TODO: Enable this when we have a Linux packaging workflow diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index b414afebfc9..d7d5dc76d0b 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -38,6 +38,7 @@ jobs: changes: name: Change Detection runs-on: ubuntu-latest + if: startsWith(github.repository_owner, 'azure') || github.repository_owner == 'PowerShell' # Required permissions permissions: pull-requests: read @@ -49,7 +50,7 @@ jobs: uses: actions/checkout@v4.1.0 # For pull requests it's not necessary to checkout the code - - uses: dorny/paths-filter@v3 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.2.0 id: filter with: list-files: json @@ -186,6 +187,6 @@ jobs: - macos_test_unelevated_ci - macos_test_unelevated_others if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@master + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: needs_context: ${{ toJson(needs) }} diff --git a/.github/workflows/markdownLink.yml b/.github/workflows/markdownLink.yml index 950534f1e56..85b9f51a742 100644 --- a/.github/workflows/markdownLink.yml +++ b/.github/workflows/markdownLink.yml @@ -11,6 +11,8 @@ permissions: jobs: markdown-link-check: runs-on: ubuntu-latest + if: github.repository_owner == 'PowerShell' + steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1 diff --git a/.github/workflows/processReminders.yml b/.github/workflows/processReminders.yml index c6ac936343c..a2d5b4dbd93 100644 --- a/.github/workflows/processReminders.yml +++ b/.github/workflows/processReminders.yml @@ -10,6 +10,7 @@ permissions: jobs: reminder: + if: github.repository_owner == 'PowerShell' permissions: issues: write # for agrc/reminder-action to set reminders on issues pull-requests: write # for agrc/reminder-action to set reminders on PRs diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 21430546a1f..90ac8e0b762 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -20,6 +20,7 @@ permissions: read-all jobs: analysis: name: Scorecard analysis + if: github.repository_owner == 'PowerShell' runs-on: ubuntu-latest permissions: # Needed to upload the results to code-scanning dashboard. diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index c93983a765f..9f2aef06a59 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -39,6 +39,7 @@ jobs: changes: name: Change Detection runs-on: ubuntu-latest + if: startsWith(github.repository_owner, 'azure') || github.repository_owner == 'PowerShell' # Required permissions permissions: pull-requests: read @@ -50,7 +51,7 @@ jobs: uses: actions/checkout@v4.1.0 # For pull requests it's not necessary to checkout the code - - uses: dorny/paths-filter@v3 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.2.0 id: filter with: list-files: json @@ -170,6 +171,6 @@ jobs: - windows_test_unelevated_ci - windows_test_unelevated_others if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@master + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: needs_context: ${{ toJson(needs) }} From 06782f0a886f6f2da3d1db2012fd80236abc10f7 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:04:23 -0700 Subject: [PATCH 102/275] [release/v7.5] Disable SBOM generation on set variables job in release build (#25340) Co-authored-by: Aditya Patwardhan --- .pipelines/PowerShell-Coordinated_Packages-Official.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 672674a21b7..11215302e46 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -138,6 +138,8 @@ extends: value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - name: ob_signing_setup_enabled value: false + - name: ob_sdl_sbom_enabled + value: false steps: - checkout: self From d390c57b50bbbc1fc9c6ddc982edfaf2cba3a23d Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:26:34 -0700 Subject: [PATCH 103/275] [release/v7.5] Update security extensions (#25322) Co-authored-by: Travis Plunk --- .../System.Management.Automation.csproj | 2 +- tools/cgmanifest.json | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index d0ed69efaaf..ed65de03c1a 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -49,7 +49,7 @@ - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index d73e68035dd..feb4257f1d0 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -175,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Security.Extensions", - "Version": "1.3.0" + "Version": "1.4.0" } }, "DevelopmentDependency": false @@ -900,6 +901,5 @@ }, "DevelopmentDependency": false } - ], - "$schema": "https://json.schemastore.org/component-detection-manifest.json" + ] } From 27d193267a7879dd117d54d50e759d9c901a8aff Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:46:34 -0700 Subject: [PATCH 104/275] [release/v7.5]Make GitHub Workflows work in the internal mirror (#25342) Co-authored-by: Travis Plunk --- .../infrastructure/path-filters/action.yml | 88 +++++++++++++++++ .github/actions/test/nix/action.yml | 27 +++++- .../test/process-pester-results/action.yml | 64 ++++++------- .github/workflows/linux-ci.yml | 26 ++--- .github/workflows/macos-ci.yml | 23 ++--- .github/workflows/windows-ci.yml | 23 ++--- build.psm1 | 95 ++++++++++++++++++- 7 files changed, 257 insertions(+), 89 deletions(-) create mode 100644 .github/actions/infrastructure/path-filters/action.yml diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml new file mode 100644 index 00000000000..58255fab55c --- /dev/null +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -0,0 +1,88 @@ +name: Path Filters +description: 'Path Filters' +inputs: + GITHUB_TOKEN: + description: 'GitHub token' + required: true +outputs: + source: + description: 'Source code changes (composite of all changes)' + value: ${{ steps.filter.outputs.source }} + githubChanged: + description: 'GitHub workflow changes' + value: ${{ steps.filter.outputs.githubChanged }} + toolsChanged: + description: 'Tools changes' + value: ${{ steps.filter.outputs.toolsChanged }} + propsChanged: + description: 'Props changes' + value: ${{ steps.filter.outputs.propsChanged }} + testsChanged: + description: 'Tests changes' + value: ${{ steps.filter.outputs.testsChanged }} + mainSourceChanged: + description: 'Main source code changes (any changes in src/)' + value: ${{ steps.filter.outputs.mainSourceChanged }} + buildModuleChanged: + description: 'Build module changes' + value: ${{ steps.filter.outputs.buildModuleChanged }} +runs: + using: composite + steps: + - name: Check if GitHubWorkflowChanges is present + id: filter + uses: actions/github-script@v7.0.1 + with: + github-token: ${{ inputs.GITHUB_TOKEN }} + script: | + // Fetch the list of files changed in the PR + let files = []; + let page = 1; + let fetchedFiles; + do { + fetchedFiles = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + per_page: 100, + page: page++ + }); + files = files.concat(fetchedFiles.data); + } while (fetchedFiles.data.length > 0); + + const actionsChanged = files.some(file => file.filename.startsWith('.github/actions')); + const workflowsChanged = files.some(file => file.filename.startsWith('.github/workflows')); + const githubChanged = actionsChanged || workflowsChanged; + + const toolsCiPsm1Changed = files.some(file => file.filename.startsWith('tools/ci.psm1')); + const toolsBuildCommonChanged = files.some(file => file.filename.startsWith('tools/buildCommon/')); + const toolsChanged = toolsCiPsm1Changed || toolsBuildCommonChanged; + + const propsChanged = files.some(file => file.filename.endsWith('.props')); + + const testsChanged = files.some(file => file.filename.startsWith('test/powershell/') || file.filename.startsWith('test/tools/') || file.filename.startsWith('test/xUnit/')); + + const mainSourceChanged = files.some(file => file.filename.startsWith('src/')); + + const buildModuleChanged = files.some(file => file.filename.startsWith('build.psm1')); + + const source = mainSourceChanged || toolsChanged || githubChanged || propsChanged || testsChanged; + + core.setOutput('toolsChanged', toolsChanged); + core.setOutput('githubChanged', githubChanged); + core.setOutput('propsChanged', propsChanged); + core.setOutput('testsChanged', testsChanged); + core.setOutput('mainSourceChanged', mainSourceChanged); + core.setOutput('buildModuleChanged', buildModuleChanged); + core.setOutput('source', source); + + - name: Capture outputs + run: | + Write-Verbose -Verbose "source: ${{ steps.filter.outputs.source }}" + Write-Verbose -Verbose "github: ${{ steps.filter.outputs.githubChanged }}" + Write-Verbose -Verbose "tools: ${{ steps.filter.outputs.toolsChanged }}" + Write-Verbose -Verbose "props: ${{ steps.filter.outputs.propsChanged }}" + Write-Verbose -Verbose "tests: ${{ steps.filter.outputs.testsChanged }}" + Write-Verbose -Verbose "mainSource: ${{ steps.filter.outputs.mainSourceChanged }}" + Write-Verbose -Verbose "buildModule: ${{ steps.filter.outputs.buildModuleChanged }}" + shell: pwsh diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index 03c44a151c7..cf586f894a0 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -20,26 +20,39 @@ runs: steps: - name: Capture Environment if: success() || failure() - run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' + run: |- + Import-Module ./build.psm1 + Write-LogGroupStart -Title 'Environment' + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + Write-LogGroupEnd -Title 'Environment' shell: pwsh + - name: Download Build Artifacts uses: actions/download-artifact@v4 with: path: "${{ github.workspace }}" + - name: Capture Artifacts Directory continue-on-error: true - run: Get-ChildItem "${{ github.workspace }}/build/*" -Recurse + run: |- + Import-Module ./build.psm1 + Write-LogGroupStart -Title 'Artifacts Directory' + Get-ChildItem "${{ github.workspace }}/build/*" -Recurse + Write-LogGroupEnd -Title 'Artifacts Directory' shell: pwsh - + - uses: actions/setup-dotnet@v4 with: global-json-file: ./global.json - + - name: Bootstrap shell: pwsh run: |- + Import-Module ./build.psm1 + Write-LogGroupStart -Title 'Bootstrap' Import-Module ./tools/ci.psm1 Invoke-CIInstall -SkipUser + Write-LogGroupEnd -Title 'Bootstrap' - name: Extract Files uses: actions/github-script@v7.0.0 @@ -68,7 +81,11 @@ runs: - name: Capture Extracted Build ZIP continue-on-error: true - run: Get-ChildItem "${{ github.workspace }}/bins/*" -Recurse -ErrorAction SilentlyContinue + run: |- + Import-Module ./build.psm1 + Write-LogGroupStart -Title 'Extracted Build ZIP' + Get-ChildItem "${{ github.workspace }}/bins/*" -Recurse -ErrorAction SilentlyContinue + Write-LogGroupEnd -Title 'Extracted Build ZIP' shell: pwsh - name: Test diff --git a/.github/actions/test/process-pester-results/action.yml b/.github/actions/test/process-pester-results/action.yml index 758bbdfc353..e1072ec08ca 100644 --- a/.github/actions/test/process-pester-results/action.yml +++ b/.github/actions/test/process-pester-results/action.yml @@ -18,36 +18,39 @@ inputs: runs: using: composite steps: - - name: Convert JUnit to CTRF - run: |- + - name: Log Summary + run: | + if (-not $env:GITHUB_STEP_SUMMARY) { + Write-Error "GITHUB_STEP_SUMMARY is not set. Ensure this workflow is running in a GitHub Actions environment." + exit 1 + } + + $testCaseCount = 0 + $testErrorCount = 0 + $testFailureCount = 0 + $testDisabledCount = 0 Get-ChildItem -Path "${{ inputs.testResultsFolder }}/*.xml" -Recurse | ForEach-Object { - npx --yes junit-to-ctrf $_.FullName --output ./${{ inputs.ctrfFolder }}/$($_.BaseName).json --tool Pester + $results = [xml] (get-content $_.FullName) + $testCaseCount += $results.testsuites.tests + $testErrorCount += $results.testsuites.errors + $testFailureCount += $results.testsuites.failures + $testDisabledCount += $results.testsuites.disabled } - shell: pwsh - # this task only takes / as directory separators - - name: Publish Test Report - uses: ctrf-io/github-test-reporter@v1 - with: - report-path: './${{ inputs.ctrfFolder }}/*.json' - exit-on-fail: true - summary-report: true - test-report: false - test-list-report: false - failed-report: false - fail-rate-report: false - flaky-report: false - flaky-rate-report: false - failed-folded-report: true - previous-results-report: false - ai-report: true - skipped-report: false - suite-folded-report: false - suite-list-report: false - pull-request-report: false - commit-report: false - custom-report: false - if: always() + @" + + # Summary of ${{ inputs.name }} + + - Total Tests: $testCaseCount + - Total Errors: $testErrorCount + - Total Failures: $testFailureCount + - Total Disabled: $testDisabledCount + + "@ | Out-File -FilePath $ENV:GITHUB_STEP_SUMMARY -Append + + Write-Host "Summary written to $ENV:GITHUB_STEP_SUMMARY" + Get-Content $ENV:GITHUB_STEP_SUMMARY + shell: pwsh - name: Upload testResults artifact if: always() @@ -55,10 +58,3 @@ runs: with: name: junit-pester-${{ inputs.name }} path: ${{ runner.workspace }}/testResults - - - name: Upload ctrf artifact - if: always() - uses: actions/upload-artifact@v4 - with: - name: ctrf-pester-${{ inputs.name }} - path: ${{ inputs.ctrfFolder }} diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index d7d76310846..eda1ea56167 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -9,6 +9,7 @@ on: branches: - master - release/** + - github-mirror paths: - "**" - "!.github/ISSUE_TEMPLATE/**" @@ -19,6 +20,7 @@ on: branches: - master - release/** + - github-mirror # Path filters for PRs need to go into the changes job concurrency: @@ -43,30 +45,22 @@ jobs: # Required permissions permissions: pull-requests: read + contents: read + # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4 + with: + persist-credentials: false - # For pull requests it's not necessary to checkout the code - - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.2.0 + - name: Change Detection id: filter + uses: "./.github/actions/infrastructure/path-filters" with: - list-files: json - filters: .github/action-filters.yml - - - name: Capture outputs - run: | - "source: ${{ steps.filter.outputs.source }}" - "github: ${{ steps.filter.outputs.github }}" - "tools: ${{ steps.filter.outputs.tools }}" - "props: ${{ steps.filter.outputs.props }}" - "tests: ${{ steps.filter.outputs.tests }}" - "mainSource: ${{ steps.filter.outputs.mainSource }}" - "buildModule: ${{ steps.filter.outputs.buildModule }}" - shell: pwsh + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ci_build: name: Build PowerShell diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index d7d5dc76d0b..9184dc088f0 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -7,6 +7,7 @@ on: branches: - master - release/** + - github-mirror paths: - "**" - "!.github/ISSUE_TEMPLATE/**" @@ -17,6 +18,7 @@ on: branches: - master - release/** + - github-mirror # Path filters for PRs need to go into the changes job concurrency: @@ -34,6 +36,7 @@ env: __SuppressAnsiEscapeSequences: 1 nugetMultiFeedWarnLevel: none system_debug: 'false' + jobs: changes: name: Change Detection @@ -42,6 +45,8 @@ jobs: # Required permissions permissions: pull-requests: read + contents: read + # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} @@ -49,23 +54,11 @@ jobs: - name: checkout uses: actions/checkout@v4.1.0 - # For pull requests it's not necessary to checkout the code - - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.2.0 + - name: Change Detection id: filter + uses: "./.github/actions/infrastructure/path-filters" with: - list-files: json - filters: .github/action-filters.yml - - - name: Capture outputs - run: | - "source: ${{ steps.filter.outputs.source }}" - "github: ${{ steps.filter.outputs.github }}" - "tools: ${{ steps.filter.outputs.tools }}" - "props: ${{ steps.filter.outputs.props }}" - "tests: ${{ steps.filter.outputs.tests }}" - "mainSource: ${{ steps.filter.outputs.mainSource }}" - "buildModule: ${{ steps.filter.outputs.buildModule }}" - shell: pwsh + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ci_build: name: Build PowerShell diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 9f2aef06a59..1e955c78be6 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -5,6 +5,7 @@ on: branches: - master - release/** + - github-mirror paths: - "**" - "!.vsts-ci/misc-analysis.yml" @@ -16,6 +17,8 @@ on: branches: - master - release/** + - github-mirror + # Path filters for PRs need to go into the changes job concurrency: @@ -43,6 +46,8 @@ jobs: # Required permissions permissions: pull-requests: read + contents: read + # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} @@ -50,23 +55,11 @@ jobs: - name: checkout uses: actions/checkout@v4.1.0 - # For pull requests it's not necessary to checkout the code - - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.2.0 + - name: Change Detection id: filter + uses: "./.github/actions/infrastructure/path-filters" with: - list-files: json - filters: .github/action-filters.yml - - - name: Capture outputs - run: | - "source: ${{ steps.filter.outputs.source }}" - "github: ${{ steps.filter.outputs.github }}" - "tools: ${{ steps.filter.outputs.tools }}" - "props: ${{ steps.filter.outputs.props }}" - "tests: ${{ steps.filter.outputs.tests }}" - "mainSource: ${{ steps.filter.outputs.mainSource }}" - "buildModule: ${{ steps.filter.outputs.buildModule }}" - shell: pwsh + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ci_build: name: Build PowerShell diff --git a/build.psm1 b/build.psm1 index e882e2f797c..73becb3f0d0 100644 --- a/build.psm1 +++ b/build.psm1 @@ -179,6 +179,8 @@ function Get-EnvironmentInformation $environment += @{'IsUbuntu16' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '16.04'} $environment += @{'IsUbuntu18' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '18.04'} $environment += @{'IsUbuntu20' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '20.04'} + $environment += @{'IsUbuntu22' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '22.04'} + $environment += @{'IsUbuntu24' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '24.04'} $environment += @{'IsCentOS' = $LinuxInfo.ID -match 'centos' -and $LinuxInfo.VERSION_ID -match '7'} $environment += @{'IsFedora' = $LinuxInfo.ID -match 'fedora' -and $LinuxInfo.VERSION_ID -ge 24} $environment += @{'IsOpenSUSE' = $LinuxInfo.ID -match 'opensuse'} @@ -2693,6 +2695,10 @@ function script:Write-Log if ($isError) { Write-Host -Foreground Red $message + if($env:GITHUB_WORKFLOW) + { + Write-Host "::error::${message}" + } } else { @@ -2701,6 +2707,59 @@ function script:Write-Log #reset colors for older package to at return to default after error message on a compilation error [console]::ResetColor() } + +function script:Write-LogGroup { + param + ( + [Parameter(Position = 0, Mandatory)] + [ValidateNotNullOrEmpty()] + [string[]] $Message, + [Parameter(Mandatory)] + [string] $Title + ) + + + Write-LogGroupStart -Title $Title + + foreach ($line in $Message) { + Write-Log -Message $line + } + + Write-LogGroupEnd -Title $Title +} + +$script:logGroupColor = [System.ConsoleColor]::Cyan + +function script:Write-LogGroupStart { + param + ( + [Parameter(Mandatory)] + [string] $Title + ) + + if ($env:GITHUB_WORKFLOW) { + Write-Host "::group::${Title}" + } + else { + Write-Host -ForegroundColor $script:logGroupColor "=== BEGIN: $Title ===" + } +} + +function script:Write-LogGroupEnd { + param + ( + [Parameter(Mandatory)] + [string] $Title + ) + + if ($env:GITHUB_WORKFLOW) { + Write-Host "::endgroup::" + } + else { + Write-Host -ForegroundColor $script:logGroupColor "==== END: $Title ====" + } +} + function script:precheck([string]$command, [string]$missedMessage) { $c = Get-Command $command -ErrorAction Ignore if (-not $c) { @@ -3619,22 +3678,50 @@ function Set-PipelineNugetAuthentication { function Set-CorrectLocale { + Write-LogGroupStart -Title "Set-CorrectLocale" + if (-not $IsLinux) { + Write-LogGroupEnd -Title "Set-CorrectLocale" return } $environment = Get-EnvironmentInformation - if ($environment.IsUbuntu -and $environment.IsUbuntu20) - { + if ($environment.IsUbuntu16 -or $environment.IsUbuntu18) { + Write-Verbose -Message "Don't set locale before Ubuntu 20" -Verbose + Write-LogGroupEnd -Title "Set-CorrectLocale" + Write-Locale + return + } + + if ($environment.IsUbuntu) { + Write-Log -Message "Setting locale to en_US.UTF-8" $env:LC_ALL = 'en_US.UTF-8' $env:LANG = 'en_US.UTF-8' sudo locale-gen $env:LANG - sudo update-locale + if ($environment.IsUbuntu20) { + Write-Log -Message "Updating locale for Ubuntu 20" + sudo update-locale + } else { + Write-Log -Message "Updating locale for Ubuntu 22 and newer" + sudo update-locale LANG=$env:LANG LC_ALL=$env:LC_ALL + } + } + + Write-LogGroupEnd -Title "Set-CorrectLocale" + Write-Locale + +} + +function Write-Locale { + if (-not $IsLinux -and -not $IsMacOS) { + Write-Verbose -Message "only supported on Linux and macOS" -Verbose + return } # Output the locale to log it - locale + $localOutput = & locale + Write-LogGroup -Title "Capture Locale" -Message $localOutput } function Install-AzCopy { From 8b7192eab84ce43403cd8323f20b98af16c9185f Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 15:38:26 -0700 Subject: [PATCH 105/275] [release/v7.5] Fix MSIX stage in release pipeline (#25345) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Travis Plunk --- .pipelines/PowerShell-Release-Official.yml | 17 +++++------ .pipelines/templates/release-create-msix.yml | 26 ++++------------- .../release-validate-fxdpackages.yml | 29 +++++++++++++++---- .pipelines/templates/uploadToAzure.yml | 4 +-- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 6f7a6b5348a..1d986f872d6 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -204,8 +204,10 @@ extends: displayName: 'Validate Linux ARM64 Fxd Packages' jobtype: 'linux' artifactName: 'drop_linux_package_fxdependent' + # this is really an architecture independent package packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' arm64: 'yes' + enableCredScan: false - stage: validatePackages displayName: 'Validate Packages' @@ -333,25 +335,20 @@ extends: displayName: Publish PMC dependsOn: PushGitTagAndMakeDraftPublic jobs: - - template: /.pipelines/templates/release-publish-pmc.yml@self + - template: /.pipelines/templates/approvalJob.yml@self parameters: - skipPublish: ${{ parameters.SkipPMCPublish }} + displayName: Publish to PMC + jobName: ReleaseToPMC + instructions: | + Run PowerShell-Release-Official-Azure.yml pipeline to publish to PMC - stage: ReleaseDocker dependsOn: PushGitTagAndMakeDraftPublic displayName: 'Docker Release' jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Start Docker Build - jobName: StartDockerBuild - instructions: | - Kick off Docker build - - template: /.pipelines/templates/approvalJob.yml@self parameters: displayName: Start Docker Release - dependsOnJob: StartDockerBuild jobName: StartDockerRelease instructions: | Kickoff docker release diff --git a/.pipelines/templates/release-create-msix.yml b/.pipelines/templates/release-create-msix.yml index 90d2acd493b..3714e623b5e 100644 --- a/.pipelines/templates/release-create-msix.yml +++ b/.pipelines/templates/release-create-msix.yml @@ -37,18 +37,16 @@ jobs: } else { $toolsDir = '$(Pipeline.Workspace)\releasePipeline\tools' New-Item $toolsDir -Type Directory -Force > $null - Invoke-RestMethod -Uri '$(makeappUrl)' -OutFile "$toolsDir\makeappx.zip" - Expand-Archive "$toolsDir\makeappx.zip" -DestinationPath "$toolsDir\makeappx" -Force - $exePath = "$toolsDir\makeappx\makeappx.exe" - - Write-Verbose -Verbose 'makeappx was installed:' - Get-ChildItem -Path $toolsDir -Recurse + $makeappx = Get-ChildItem -Recurse 'C:\Program Files (x86)\Windows Kits\10\makeappx.exe' | + Where-Object { $_.DirectoryName -match 'x64' } | + Select-Object -Last 1 + $exePath = $makeappx.FullName + Write-Verbose -Verbose 'makeappx was found:' } - $vstsCommandString = "vso[task.setvariable variable=MakeAppxPath]$exePath" Write-Host "sending " + $vstsCommandString Write-Host "##$vstsCommandString" - displayName: Install makeappx tool + displayName: Find makeappx tool retryCountOnTaskFailure: 1 - pwsh: | @@ -77,18 +75,6 @@ jobs: displayName: Create MsixBundle retryCountOnTaskFailure: 1 - - pwsh: | - $azureRmModule = Get-InstalledModule AzureRM -ErrorAction SilentlyContinue -Verbose - if ($azureRmModule) { - Write-Host 'AzureRM module exists. Removing it' - Uninstall-AzureRm - Write-Host 'AzureRM module removed' - } - - Install-Module -Name Az.Storage -Force -AllowClobber -Scope CurrentUser -Verbose - - displayName: Remove AzRM modules and install Az.Storage - - task: AzurePowerShell@5 displayName: Upload msix to blob inputs: diff --git a/.pipelines/templates/release-validate-fxdpackages.yml b/.pipelines/templates/release-validate-fxdpackages.yml index baf6c431787..53657e6414a 100644 --- a/.pipelines/templates/release-validate-fxdpackages.yml +++ b/.pipelines/templates/release-validate-fxdpackages.yml @@ -1,10 +1,25 @@ parameters: - jobName: "" - displayName: "" - jobtype: "" - artifactName: "" - packageNamePattern: "" - arm64: "no" + - name: jobName + type: string + default: "" + - name: displayName + type: string + default: "" + - name: jobtype + type: string + default: "" + - name: artifactName + type: string + default: "" + - name: packageNamePattern + type: string + default: "" + - name: arm64 + type: string + default: "no" + - name: enableCredScan + type: boolean + default: true jobs: - job: ${{ parameters.jobName }} @@ -19,6 +34,8 @@ jobs: value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - name: ob_sdl_tsa_configFile value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_sdl_credscan_enabled + value: ${{ parameters.enableCredScan }} pool: type: ${{ parameters.jobtype }} diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index 5c0d80ec10f..0994c7ef2b0 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -6,7 +6,7 @@ jobs: type: windows variables: - name: ob_sdl_sbom_enabled - value: false + value: true - name: runCodesignValidationInjection value: false - name: NugetSecurityAnalysisWarningLevel @@ -241,7 +241,7 @@ jobs: Write-Verbose -Verbose "Creating output directory for GitHub Release files: $(ob_outputDirectory)/GitHubPackages" New-Item -Path $(ob_outputDirectory)/GitHubPackages -ItemType Directory -Force Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)/downloads/*" -Recurse | - Where-Object { $_.Extension -notin '.msix', '.nupkg' } | + Where-Object { $_.Extension -notin '.msix', '.nupkg' -and $_.Name -notmatch '-gc'} | Copy-Item -Destination $(ob_outputDirectory)/GitHubPackages -Recurse -Verbose Write-Verbose -Verbose "Creating output directory for NuGet packages: $(ob_outputDirectory)/NuGetPackages" From 94c401c29c4915327f85f5d7e04bc00fdd7c672a Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 15:39:21 -0700 Subject: [PATCH 106/275] [release/v7.5] Do not run labels workflow in the internal repo (#25343) Co-authored-by: Travis Plunk --- .github/workflows/labels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index fdb0ae4cd77..794ef64b213 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -13,7 +13,7 @@ permissions: jobs: verify-labels: - if: startsWith(github.repository_owner, 'azure') || github.repository_owner == 'PowerShell' + if: github.repository_owner == 'PowerShell' runs-on: ubuntu-latest steps: From 156dba65a47b79d31e0209fedcb52864e182cfcb Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 15:52:08 -0700 Subject: [PATCH 107/275] [release/v7.5] Update test result processing to use NUnitXml format and enhance logging for better clarity (#25344) Co-authored-by: Travis Plunk --- .github/actions/test/nix/action.yml | 2 +- .../test/process-pester-results/action.yml | 37 +--------- .../process-pester-results.ps1 | 68 +++++++++++++++++++ .github/actions/test/windows/action.yml | 20 ++++-- build.psm1 | 57 ++++++++++------ 5 files changed, 125 insertions(+), 59 deletions(-) create mode 100644 .github/actions/test/process-pester-results/process-pester-results.ps1 diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index cf586f894a0..b338c398340 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -101,7 +101,7 @@ runs: chmod a+x $pwshPath $options.Output = $pwshPath Set-PSOptions $options - Invoke-CITest -Purpose '${{ inputs.purpose }}' -TagSet '${{ inputs.tagSet }}' -TitlePrefix '${{ inputs.buildName }}' -OutputFormat JUnitXml + Invoke-CITest -Purpose '${{ inputs.purpose }}' -TagSet '${{ inputs.tagSet }}' -TitlePrefix '${{ inputs.buildName }}' -OutputFormat NUnitXml shell: pwsh - name: Convert, Publish, and Upload Pester Test Results diff --git a/.github/actions/test/process-pester-results/action.yml b/.github/actions/test/process-pester-results/action.yml index e1072ec08ca..27b94f6ebcb 100644 --- a/.github/actions/test/process-pester-results/action.yml +++ b/.github/actions/test/process-pester-results/action.yml @@ -10,46 +10,13 @@ inputs: required: false default: "${{ runner.workspace }}/testResults" type: string - ctrfFolder: - required: false - default: ctrf - type: string runs: using: composite steps: - name: Log Summary - run: | - if (-not $env:GITHUB_STEP_SUMMARY) { - Write-Error "GITHUB_STEP_SUMMARY is not set. Ensure this workflow is running in a GitHub Actions environment." - exit 1 - } - - $testCaseCount = 0 - $testErrorCount = 0 - $testFailureCount = 0 - $testDisabledCount = 0 - Get-ChildItem -Path "${{ inputs.testResultsFolder }}/*.xml" -Recurse | ForEach-Object { - $results = [xml] (get-content $_.FullName) - $testCaseCount += $results.testsuites.tests - $testErrorCount += $results.testsuites.errors - $testFailureCount += $results.testsuites.failures - $testDisabledCount += $results.testsuites.disabled - } - - @" - - # Summary of ${{ inputs.name }} - - - Total Tests: $testCaseCount - - Total Errors: $testErrorCount - - Total Failures: $testFailureCount - - Total Disabled: $testDisabledCount - - "@ | Out-File -FilePath $ENV:GITHUB_STEP_SUMMARY -Append - - Write-Host "Summary written to $ENV:GITHUB_STEP_SUMMARY" - Get-Content $ENV:GITHUB_STEP_SUMMARY + run: |- + & "$env:GITHUB_ACTION_PATH/process-pester-results.ps1" -Name '${{ inputs.name }}' -TestResultsFolder '${{ inputs.testResultsFolder }}' shell: pwsh - name: Upload testResults artifact diff --git a/.github/actions/test/process-pester-results/process-pester-results.ps1 b/.github/actions/test/process-pester-results/process-pester-results.ps1 new file mode 100644 index 00000000000..523de3bebaa --- /dev/null +++ b/.github/actions/test/process-pester-results/process-pester-results.ps1 @@ -0,0 +1,68 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +param( + [parameter(Mandatory)] + [string]$Name, + [parameter(Mandatory)] + [string]$TestResultsFolder +) + +Import-Module "$PSScriptRoot/../../../../build.psm1" + +if (-not $env:GITHUB_STEP_SUMMARY) { + Write-Error "GITHUB_STEP_SUMMARY is not set. Ensure this workflow is running in a GitHub Actions environment." + exit 1 +} + +$testCaseCount = 0 +$testErrorCount = 0 +$testFailureCount = 0 +$testNotRunCount = 0 +$testInconclusiveCount = 0 +$testIgnoredCount = 0 +$testSkippedCount = 0 +$testInvalidCount = 0 + +Get-ChildItem -Path "${TestResultsFolder}/*.xml" -Recurse | ForEach-Object { + $results = [xml] (get-content $_.FullName) + + $testCaseCount += [int]$results.'test-results'.total + $testErrorCount += [int]$results.'test-results'.errors + $testFailureCount += [int]$results.'test-results'.failures + $testNotRunCount += [int]$results.'test-results'.'not-run' + $testInconclusiveCount += [int]$results.'test-results'.inconclusive + $testIgnoredCount += [int]$results.'test-results'.ignored + $testSkippedCount += [int]$results.'test-results'.skipped + $testInvalidCount += [int]$results.'test-results'.invalid +} + +@" + +# Summary of $Name + +- Total Tests: $testCaseCount +- Total Errors: $testErrorCount +- Total Failures: $testFailureCount +- Total Not Run: $testNotRunCount +- Total Inconclusive: $testInconclusiveCount +- Total Ignored: $testIgnoredCount +- Total Skipped: $testSkippedCount +- Total Invalid: $testInvalidCount + +"@ | Out-File -FilePath $ENV:GITHUB_STEP_SUMMARY -Append + +Write-Log "Summary written to $ENV:GITHUB_STEP_SUMMARY" + +Write-LogGroupStart -Title 'Test Results' +Get-Content $ENV:GITHUB_STEP_SUMMARY +Write-LogGroupEnd -Title 'Test Results' + +if ($testErrorCount -gt 0 -or $testFailureCount -gt 0) { + Write-Error "There were $testErrorCount/$testFailureCount errors/failures in the test results." + exit 1 +} +if ($testCaseCount -eq 0) { + Write-Error "No test cases were run." + exit 1 +} diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index d2af55ce5a9..734e30208f0 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -20,15 +20,25 @@ runs: steps: - name: Capture Environment if: success() || failure() - run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' + run: |- + Import-Module ./build.psm1 + Write-LogGroupStart -Title 'Environment' + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + Write-LogGroupEnd -Title 'Environment' shell: pwsh + - name: Download Build Artifacts uses: actions/download-artifact@v4 with: path: "${{ github.workspace }}" + - name: Capture Artifacts Directory continue-on-error: true - run: Get-ChildItem "${{ github.workspace }}\build\*" -Recurse + run: |- + Import-Module ./build.psm1 + Write-LogGroupStart -Title 'Artifacts Directory' + Get-ChildItem "${{ github.workspace }}/build/*" -Recurse + Write-LogGroupEnd -Title 'Artifacts Directory' shell: pwsh - uses: actions/setup-dotnet@v4 @@ -38,7 +48,8 @@ runs: - name: Bootstrap shell: powershell run: |- - # Remove "Program Files\dotnet" from the env variable PATH, so old SDKs won't affect us. + Import-Module ./build.psm1 + Write-LogGroupStart -Title 'Bootstrap' Write-Host "Old Path:" Write-Host $env:Path $dotnetPath = Join-Path $env:SystemDrive 'Program Files\dotnet' @@ -49,6 +60,7 @@ runs: # Bootstrap Import-Module .\tools\ci.psm1 Invoke-CIInstall + Write-LogGroupEnd -Title 'Bootstrap' - name: Test if: success() @@ -60,7 +72,7 @@ runs: $path = split-path -path $options.Output $rootPath = split-Path -path $path Expand-Archive -Path '${{ github.workspace }}\build\build.zip' -DestinationPath $rootPath -Force - Invoke-CITest -Purpose '${{ inputs.purpose }}' -TagSet '${{ inputs.tagSet }}' -OutputFormat JUnitXml + Invoke-CITest -Purpose '${{ inputs.purpose }}' -TagSet '${{ inputs.tagSet }}' -OutputFormat NUnitXml shell: pwsh - name: Convert, Publish, and Upload Pester Test Results diff --git a/build.psm1 b/build.psm1 index 73becb3f0d0..b371891d706 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1231,6 +1231,7 @@ function Get-PesterTag { # testing PowerShell remote custom connections. function Publish-CustomConnectionTestModule { + Write-LogGroupStart -Title "Publish-CustomConnectionTestModule" $sourcePath = "${PSScriptRoot}/test/tools/NamedPipeConnection" $outPath = "${PSScriptRoot}/test/tools/NamedPipeConnection/out/Microsoft.PowerShell.NamedPipeConnection" $publishPath = "${PSScriptRoot}/test/tools/Modules" @@ -1255,6 +1256,8 @@ function Publish-CustomConnectionTestModule finally { Pop-Location } + + Write-LogGroupEnd -Title "Publish-CustomConnectionTestModule" } function Publish-PSTestTools { @@ -1264,6 +1267,7 @@ function Publish-PSTestTools { $runtime ) + Write-LogGroupStart -Title "Publish-PSTestTools" Find-Dotnet $tools = @( @@ -1335,6 +1339,7 @@ function Publish-PSTestTools { # Publish the Microsoft.PowerShell.NamedPipeConnection module Publish-CustomConnectionTestModule + Write-LogGroupEnd -Title "Publish-PSTestTools" } function Get-ExperimentalFeatureTests { @@ -1822,12 +1827,16 @@ function Show-PSPesterError throw 'Unknown Show-PSPester parameter set' } - Write-Log -isError -message ("Description: " + $description) - Write-Log -isError -message ("Name: " + $name) - Write-Log -isError -message "message:" - Write-Log -isError -message $message - Write-Log -isError -message "stack-trace:" - Write-Log -isError -message $stack_trace + # Empty line at the end is intentional formatting + Write-Log -isError -message @" +Description: $description +Name: $name +message: +$message +stack-trace: +$stack_trace + +"@ } @@ -1867,13 +1876,17 @@ function Test-XUnitTestResults $message = $failure.failure.message $stack_trace = $failure.failure.'stack-trace' - Write-Log -isError -message ("Description: " + $description) - Write-Log -isError -message ("Name: " + $name) - Write-Log -isError -message "message:" - Write-Log -isError -message $message - Write-Log -isError -message "stack-trace:" - Write-Log -isError -message $stack_trace - Write-Log -isError -message " " + # Empty line at the end is intentional formatting + Write-Log -isError -message @" + Description: $description + Name: $name + message: + $message + stack-trace: + $stack_trace + +"@ + } throw "$($results.assemblies.assembly.failed) tests failed" @@ -1909,7 +1922,8 @@ function Test-PSPesterResults $x = [xml](Get-Content -Raw $testResultsFile) if ([int]$x.'test-results'.failures -gt 0) { - Write-Log -isError -message "TEST FAILURES" + Write-LogGroupStart -Title 'TEST FAILURES' + # switch between methods, SelectNode is not available on dotnet core if ( "System.Xml.XmlDocumentXPathExtensions" -as [Type] ) { @@ -1923,6 +1937,8 @@ function Test-PSPesterResults { Show-PSPesterError -testFailure $testfail } + + Write-LogGroupEnd -Title 'TEST FAILURES' throw "$($x.'test-results'.failures) tests in $TestArea failed" } } @@ -1943,11 +1959,12 @@ function Test-PSPesterResults } elseif ($ResultObject.FailedCount -gt 0) { - Write-Log -isError -message 'TEST FAILURES' + Write-LogGroupStart -Title 'TEST FAILURES' $ResultObject.TestResult | Where-Object {$_.Passed -eq $false} | ForEach-Object { Show-PSPesterError -testFailureObject $_ } + Write-LogGroupEnd -Title 'TEST FAILURES' throw "$($ResultObject.FailedCount) tests in $TestArea failed" } @@ -2694,10 +2711,12 @@ function script:Write-Log ) if ($isError) { - Write-Host -Foreground Red $message - if($env:GITHUB_WORKFLOW) - { - Write-Host "::error::${message}" + if ($env:GITHUB_WORKFLOW) { + # https://github.com/actions/toolkit/issues/193#issuecomment-605394935 + $escapedMessage = $message -replace "`n", "%0A" -replace "`r" + Write-Host "::error::${escapedMessage}" + } else { + Write-Host -Foreground Red $message } } else From b6f02c3cc1d05b7c6a37308a70c75644b476ea2a Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 11 Apr 2025 16:03:58 -0700 Subject: [PATCH 108/275] [release/v7.5] Fallback to AppLocker after `WldpCanExecuteFile` (#25305) Co-authored-by: Patrick Meinecke Co-authored-by: Travis Plunk --- .../security/wldpNativeMethods.cs | 197 ++++++++++-------- 1 file changed, 114 insertions(+), 83 deletions(-) diff --git a/src/System.Management.Automation/security/wldpNativeMethods.cs b/src/System.Management.Automation/security/wldpNativeMethods.cs index a59f37c0a8f..ab49f927614 100644 --- a/src/System.Management.Automation/security/wldpNativeMethods.cs +++ b/src/System.Management.Automation/security/wldpNativeMethods.cs @@ -6,6 +6,7 @@ // #if !UNIX +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Management.Automation.Internal; using System.Management.Automation.Runspaces; @@ -148,7 +149,7 @@ public static SystemEnforcementMode GetSystemLockdownPolicy() { lock (s_systemLockdownPolicyLock) { - s_systemLockdownPolicy = GetDebugLockdownPolicy(path: null); + s_systemLockdownPolicy = GetDebugLockdownPolicy(path: null, out _); } } @@ -172,93 +173,89 @@ public static SystemScriptFileEnforcement GetFilePolicyEnforcement( System.IO.FileStream fileStream) { SafeHandle fileHandle = fileStream.SafeFileHandle; - var systemLockdownPolicy = SystemPolicy.GetSystemLockdownPolicy(); + SystemEnforcementMode systemLockdownPolicy = GetSystemLockdownPolicy(); // First check latest WDAC APIs if available. - // Revert to legacy APIs if system policy is in AUDIT mode or debug hook is in effect. - Exception errorException = null; - if (s_wldpCanExecuteAvailable && systemLockdownPolicy == SystemEnforcementMode.Enforce) + if (systemLockdownPolicy is SystemEnforcementMode.Enforce + && s_wldpCanExecuteAvailable + && TryGetWldpCanExecuteFileResult(filePath, fileHandle, out SystemScriptFileEnforcement wldpFilePolicy)) { - try - { - string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath); - string auditMsg = $"PowerShell ExternalScriptInfo reading file: {fileName}"; + return GetLockdownPolicy(filePath, fileHandle, wldpFilePolicy); + } - int hr = WldpNativeMethods.WldpCanExecuteFile( - host: PowerShellHost, - options: WLDP_EXECUTION_EVALUATION_OPTIONS.WLDP_EXECUTION_EVALUATION_OPTION_NONE, - fileHandle: fileHandle.DangerousGetHandle(), - auditInfo: auditMsg, - result: out WLDP_EXECUTION_POLICY canExecuteResult); + // Failed to invoke WldpCanExecuteFile, revert to legacy APIs. + if (systemLockdownPolicy is SystemEnforcementMode.None) + { + return SystemScriptFileEnforcement.None; + } - PSEtwLog.LogWDACQueryEvent("WldpCanExecuteFile", filePath, hr, (int)canExecuteResult); + // WldpCanExecuteFile was invoked successfully so we can skip running + // legacy WDAC APIs. AppLocker must still be checked in case it is more + // strict than the current WDAC policy. + return GetLockdownPolicy(filePath, fileHandle, canExecuteResult: null); + } - if (hr >= 0) - { - switch (canExecuteResult) - { - case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_ALLOWED: - return SystemScriptFileEnforcement.Allow; + private static SystemScriptFileEnforcement ConvertToModernFileEnforcement(SystemEnforcementMode legacyMode) + { + return legacyMode switch + { + SystemEnforcementMode.None => SystemScriptFileEnforcement.Allow, + SystemEnforcementMode.Audit => SystemScriptFileEnforcement.AllowConstrainedAudit, + SystemEnforcementMode.Enforce => SystemScriptFileEnforcement.AllowConstrained, + _ => SystemScriptFileEnforcement.Block, + }; + } - case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_BLOCKED: - return SystemScriptFileEnforcement.Block; + private static bool TryGetWldpCanExecuteFileResult(string filePath, SafeHandle fileHandle, out SystemScriptFileEnforcement result) + { + try + { + string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath); + string auditMsg = $"PowerShell ExternalScriptInfo reading file: {fileName}"; - case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_REQUIRE_SANDBOX: - return SystemScriptFileEnforcement.AllowConstrained; + int hr = WldpNativeMethods.WldpCanExecuteFile( + host: PowerShellHost, + options: WLDP_EXECUTION_EVALUATION_OPTIONS.WLDP_EXECUTION_EVALUATION_OPTION_NONE, + fileHandle: fileHandle.DangerousGetHandle(), + auditInfo: auditMsg, + result: out WLDP_EXECUTION_POLICY canExecuteResult); - default: - // Fall through to legacy system policy checks. - System.Diagnostics.Debug.Assert(false, $"Unknown execution policy returned from WldCanExecute: {canExecuteResult}"); - break; - } - } + PSEtwLog.LogWDACQueryEvent("WldpCanExecuteFile", filePath, hr, (int)canExecuteResult); - // If HResult is unsuccessful (such as E_NOTIMPL (0x80004001)), fall through to legacy system checks. - } - catch (DllNotFoundException ex) - { - // Fall back to legacy system policy checks. - s_wldpCanExecuteAvailable = false; - errorException = ex; - } - catch (EntryPointNotFoundException ex) + if (hr >= 0) { - // Fall back to legacy system policy checks. - s_wldpCanExecuteAvailable = false; - errorException = ex; + switch (canExecuteResult) + { + case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_ALLOWED: + result = SystemScriptFileEnforcement.Allow; + return true; + + case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_BLOCKED: + result = SystemScriptFileEnforcement.Block; + return true; + + case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_REQUIRE_SANDBOX: + result = SystemScriptFileEnforcement.AllowConstrained; + return true; + + default: + // Fall through to legacy system policy checks. + Debug.Assert(false, $"Unknown policy result returned from WldCanExecute: {canExecuteResult}"); + break; + } } - if (errorException != null) - { - PSEtwLog.LogWDACQueryEvent("WldpCanExecuteFile_Failed", filePath, errorException.HResult, 0); - } + // If HResult is unsuccessful (such as E_NOTIMPL (0x80004001)), fall through to legacy system checks. } - - // Original (legacy) WDAC and AppLocker system checks. - if (systemLockdownPolicy == SystemEnforcementMode.None) + catch (Exception ex) when (ex is DllNotFoundException or EntryPointNotFoundException) { - return SystemScriptFileEnforcement.None; + // Fall back to legacy system policy checks. + s_wldpCanExecuteAvailable = false; + PSEtwLog.LogWDACQueryEvent("WldpCanExecuteFile_Failed", filePath, ex.HResult, 0); } - // Check policy for file. - switch (SystemPolicy.GetLockdownPolicy(filePath, fileHandle)) - { - case SystemEnforcementMode.Enforce: - // File is not allowed by policy enforcement and must run in CL mode. - return SystemScriptFileEnforcement.AllowConstrained; - - case SystemEnforcementMode.Audit: - // File is allowed but would be run in CL mode if policy was enforced and not audit. - return SystemScriptFileEnforcement.AllowConstrainedAudit; - - case SystemEnforcementMode.None: - // No restrictions, file will run in FL mode. - return SystemScriptFileEnforcement.Allow; - - default: - System.Diagnostics.Debug.Assert(false, "GetFilePolicyEnforcement: Unknown SystemEnforcementMode."); - return SystemScriptFileEnforcement.Block; - } + result = default; + return false; } /// @@ -267,9 +264,32 @@ public static SystemScriptFileEnforcement GetFilePolicyEnforcement( /// An EnforcementMode that describes policy. public static SystemEnforcementMode GetLockdownPolicy(string path, SafeHandle handle) { + SystemScriptFileEnforcement modernMode = GetLockdownPolicy(path, handle, canExecuteResult: null); + Debug.Assert( + modernMode is not SystemScriptFileEnforcement.Block, + "Block should never be converted to legacy file enforcement."); + + return modernMode switch + { + SystemScriptFileEnforcement.Block => SystemEnforcementMode.Enforce, + SystemScriptFileEnforcement.AllowConstrained => SystemEnforcementMode.Enforce, + SystemScriptFileEnforcement.AllowConstrainedAudit => SystemEnforcementMode.Audit, + SystemScriptFileEnforcement.Allow => SystemEnforcementMode.None, + SystemScriptFileEnforcement.None => SystemEnforcementMode.None, + _ => throw new ArgumentOutOfRangeException(nameof(modernMode)), + }; + } + + private static SystemScriptFileEnforcement GetLockdownPolicy( + string path, + SafeHandle handle, + SystemScriptFileEnforcement? canExecuteResult) + { + SystemScriptFileEnforcement wldpFilePolicy = canExecuteResult + ?? ConvertToModernFileEnforcement(GetWldpPolicy(path, handle)); + // Check the WLDP File policy via API - var wldpFilePolicy = GetWldpPolicy(path, handle); - if (wldpFilePolicy == SystemEnforcementMode.Enforce) + if (wldpFilePolicy is SystemScriptFileEnforcement.Block or SystemScriptFileEnforcement.AllowConstrained) { return wldpFilePolicy; } @@ -281,29 +301,28 @@ public static SystemEnforcementMode GetLockdownPolicy(string path, SafeHandle ha var appLockerFilePolicy = GetAppLockerPolicy(path, handle); if (appLockerFilePolicy == SystemEnforcementMode.Enforce) { - return appLockerFilePolicy; + return ConvertToModernFileEnforcement(appLockerFilePolicy); } // At this point, LockdownPolicy = Audit or Allowed. // If there was a WLDP policy, but WLDP didn't block it, // then it was explicitly allowed. Therefore, return the result for the file. - SystemEnforcementMode systemWldpPolicy = s_cachedWldpSystemPolicy.GetValueOrDefault(SystemEnforcementMode.None); - if ((systemWldpPolicy == SystemEnforcementMode.Audit) || - (systemWldpPolicy == SystemEnforcementMode.Enforce)) + if (s_cachedWldpSystemPolicy is SystemEnforcementMode.Audit or SystemEnforcementMode.Enforce + || wldpFilePolicy is SystemScriptFileEnforcement.AllowConstrainedAudit) { return wldpFilePolicy; } // If there was a system-wide AppLocker policy, but AppLocker didn't block it, // then return AppLocker's status. - if (s_cachedSaferSystemPolicy.GetValueOrDefault(SaferPolicy.Allowed) == - SaferPolicy.Disallowed) + if (s_cachedSaferSystemPolicy is SaferPolicy.Disallowed) { - return appLockerFilePolicy; + return ConvertToModernFileEnforcement(appLockerFilePolicy); } // If it's not set to 'Enforce' by the platform, allow debug overrides - return GetDebugLockdownPolicy(path); + GetDebugLockdownPolicy(path, out SystemScriptFileEnforcement debugPolicy); + return debugPolicy; } [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", @@ -558,7 +577,7 @@ private static SaferPolicy TestSaferPolicy(string testPathScript, string testPat return result; } - private static SystemEnforcementMode GetDebugLockdownPolicy(string path) + private static SystemEnforcementMode GetDebugLockdownPolicy(string path, out SystemScriptFileEnforcement modernEnforcement) { s_allowDebugOverridePolicy = true; @@ -569,10 +588,19 @@ private static SystemEnforcementMode GetDebugLockdownPolicy(string path) // check so that we can actually put it in the filename during testing. if (path.Contains("System32", StringComparison.OrdinalIgnoreCase)) { + modernEnforcement = SystemScriptFileEnforcement.Allow; return SystemEnforcementMode.None; } // No explicit debug allowance for the file, so return the system policy if there is one. + modernEnforcement = s_systemLockdownPolicy switch + { + SystemEnforcementMode.Enforce => SystemScriptFileEnforcement.AllowConstrained, + SystemEnforcementMode.Audit => SystemScriptFileEnforcement.AllowConstrainedAudit, + SystemEnforcementMode.None => SystemScriptFileEnforcement.None, + _ => SystemScriptFileEnforcement.None, + }; + return s_systemLockdownPolicy.GetValueOrDefault(SystemEnforcementMode.None); } @@ -582,10 +610,13 @@ private static SystemEnforcementMode GetDebugLockdownPolicy(string path) if (result != null) { pdwLockdownState = LanguagePrimitives.ConvertTo(result); - return GetLockdownPolicyForResult(pdwLockdownState); + SystemEnforcementMode policy = GetLockdownPolicyForResult(pdwLockdownState); + modernEnforcement = ConvertToModernFileEnforcement(policy); + return policy; } // If the system-wide debug policy had no preference, then there is no enforcement. + modernEnforcement = SystemScriptFileEnforcement.None; return SystemEnforcementMode.None; } From e07cc52056ca367e3d6231ec91ca868be0ffd303 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 16 Apr 2025 15:12:35 -0700 Subject: [PATCH 109/275] [release/v7.5] Add Windows Store Signing to MSIX bundle (#25370) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung --- .pipelines/PowerShell-Release-Official.yml | 1 + .pipelines/templates/release-create-msix.yml | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 1d986f872d6..bbbf7d86454 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -58,6 +58,7 @@ variables: - name: ReleaseTagVar value: ${{ parameters.ReleaseTagVar }} - group: PoolNames + - group: MSIXSigningProfile resources: repositories: diff --git a/.pipelines/templates/release-create-msix.yml b/.pipelines/templates/release-create-msix.yml index 3714e623b5e..751ce1ec5e2 100644 --- a/.pipelines/templates/release-create-msix.yml +++ b/.pipelines/templates/release-create-msix.yml @@ -75,6 +75,24 @@ jobs: displayName: Create MsixBundle retryCountOnTaskFailure: 1 + - task: onebranch.pipeline.signing@1 + displayName: Sign MsixBundle + inputs: + command: 'sign' + signing_profile: $(MSIXProfile) + files_to_sign: '**/*.msixbundle' + search_root: '$(BundleDir)' + + - pwsh: | + $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File + Write-Verbose -Verbose "Signed bundle: $signedBundle" + + Copy-Item -Path $signedBundle -Destination $(ob_outputDirectory) -Verbose + + Write-Verbose -Verbose "Uploaded Bundle:" + Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose + displayName: Upload msixbundle to Artifacts + - task: AzurePowerShell@5 displayName: Upload msix to blob inputs: From 06334ccf772fe18ec4faa754394c71b3b75354e2 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 16 Apr 2025 15:13:06 -0700 Subject: [PATCH 110/275] [release/v7.5] Combine GitHub and Nuget Release Stage (#25371) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> --- .pipelines/PowerShell-Release-Official.yml | 43 ++++---------- ...ithubtasks.yml => release-githubNuget.yml} | 58 +++++++++++++++++++ .../templates/release-publish-nuget.yml | 58 ------------------- 3 files changed, 68 insertions(+), 91 deletions(-) rename .pipelines/templates/{release-githubtasks.yml => release-githubNuget.yml} (61%) delete mode 100644 .pipelines/templates/release-publish-nuget.yml diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index bbbf7d86454..46a6926fd7a 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -17,8 +17,8 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Signing type: string default: 'NO' - - name: SkipPMCPublish - displayName: Skip PMC Publish + - name: SkipPublish + displayName: Skip Publishing to GitHub and Nuget type: boolean default: false - name: SkipPSInfraInstallers @@ -281,19 +281,21 @@ extends: Update and merge the changelog for the release. This step is required for creating GitHub draft release. - - stage: PublishGitHubRelease - displayName: Publish GitHub Release - dependsOn: + - stage: PublishGitHubReleaseAndNuget + displayName: Publish GitHub and Nuget Release + dependsOn: - setReleaseTagAndUploadTools - UpdateChangeLog variables: ob_release_environment: Production jobs: - - template: /.pipelines/templates/release-githubtasks.yml@self + - template: /.pipelines/templates/release-githubNuget.yml@self + parameters: + skipPublish: ${{ parameters.SkipPublish }} - stage: PushGitTagAndMakeDraftPublic displayName: Push Git Tag and Make Draft Public - dependsOn: PublishGitHubRelease + dependsOn: PublishGitHubReleaseAndNuget jobs: - template: /.pipelines/templates/approvalJob.yml@self parameters: @@ -320,18 +322,6 @@ extends: parameters: SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} - - stage: PublishNuGet - displayName: Publish NuGet - dependsOn: - - setReleaseTagAndUploadTools - - PushGitTagAndMakeDraftPublic - variables: - ob_release_environment: Production - jobs: - - template: /.pipelines/templates/release-publish-nuget.yml@self - parameters: - skipPublish: true - - stage: PublishPMC displayName: Publish PMC dependsOn: PushGitTagAndMakeDraftPublic @@ -423,8 +413,7 @@ extends: - stage: ChangesToMaster displayName: Ensure changes are in GH master - dependsOn: - - PublishNuGet + dependsOn: - PublishPMC jobs: - template: /.pipelines/templates/approvalJob.yml@self @@ -434,17 +423,6 @@ extends: instructions: | Make sure that changes README.md and metadata.json are merged into master on GitHub. - - stage: ReleaseSnap - displayName: Release Snap - dependsOn: ChangesToMaster - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Publish Snap - jobName: PublishSnapJob - instructions: | - Publish Snap - - stage: ReleaseToMU displayName: Release to MU dependsOn: PushGitTagAndMakeDraftPublic # This only needs the blob to be available @@ -460,7 +438,6 @@ extends: dependsOn: - ReleaseToMU - ReleaseSymbols - - ReleaseSnap jobs: - template: /.pipelines/templates/approvalJob.yml@self parameters: diff --git a/.pipelines/templates/release-githubtasks.yml b/.pipelines/templates/release-githubNuget.yml similarity index 61% rename from .pipelines/templates/release-githubtasks.yml rename to .pipelines/templates/release-githubNuget.yml index 31e66b793a4..2d76c13dc99 100644 --- a/.pipelines/templates/release-githubtasks.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -1,3 +1,7 @@ +parameters: + - name: skipPublish + type: boolean + jobs: - job: GithubReleaseDraft displayName: Create GitHub Release Draft @@ -58,6 +62,7 @@ jobs: displayName: List all files in the workspace - task: PowerShell@2 + condition: and(ne('${{ parameters.skipPublish }}', 'false'), succeeded()) inputs: targetType: inline pwsh: true @@ -86,3 +91,56 @@ jobs: Publish-ReleaseDraft -Tag '$(ReleaseTag)' -Name '$(ReleaseTag) Release of PowerShell' -Description $clContent -User PowerShell -Repository PowerShell -PackageFolder "$(Pipeline.Workspace)/GitHubPackages" -Token $(GitHubReleasePat) displayName: Publish Release Draft + +- job: NuGetPublish + displayName: Publish to NuGet + condition: succeeded() + pool: + type: release + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: drop_setReleaseTagAndUploadTools_SetTagAndTools + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_upload_upload_packages + variables: + - template: ./variable/release-shared.yml@self + parameters: + VERSION: $[ stageDependencies.setReleaseTagAndUploadTools.SetTagAndTools.outputs['OutputVersion.Version'] ] + + steps: + - template: release-install-pwsh.yml + + - pwsh: | + Write-Verbose -Verbose "Version: $(Version)" + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: 'Capture Environment Variables' + + - pwsh: | + #Exclude all global tool packages. Their names start with 'PowerShell.' + $null = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/release" + Copy-Item "$(Pipeline.Workspace)/NuGetPackages/*.nupkg" -Destination "$(Pipeline.Workspace)/release" -Exclude "PowerShell.*.nupkg" -Force -Verbose + + $releaseVersion = '$(Version)' + $globalToolPath = "$(Pipeline.Workspace)/NuGetPackages/PowerShell.$releaseVersion.nupkg" + + if ($releaseVersion -notlike '*-*') { + # Copy the global tool package for stable releases + Copy-Item $globalToolPath -Destination "$(Pipeline.Workspace)/release" + } + + Write-Verbose -Verbose "The .nupkgs below will be pushed:" + Get-ChildItem "$(Pipeline.Workspace)/release" -recurse + displayName: Download and capture nupkgs + condition: and(ne('${{ parameters.skipPublish }}', 'false'), succeeded()) + + - task: NuGetCommand@2 + displayName: 'NuGet push' + condition: and(ne('${{ parameters.skipPublish }}', 'false'), succeeded()) + inputs: + command: push + packagesToPush: '$(Pipeline.Workspace)/release/*.nupkg' + nuGetFeedType: external + publishFeedCredentials: PowerShellNuGetOrgPush diff --git a/.pipelines/templates/release-publish-nuget.yml b/.pipelines/templates/release-publish-nuget.yml deleted file mode 100644 index 98249844d4c..00000000000 --- a/.pipelines/templates/release-publish-nuget.yml +++ /dev/null @@ -1,58 +0,0 @@ -parameters: - - name: skipPublish - default: false - type: boolean - -jobs: -- job: NuGetPublish - displayName: Publish to NuGet - condition: succeeded() - pool: - type: release - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: drop_setReleaseTagAndUploadTools_SetTagAndTools - - input: pipelineArtifact - pipeline: PSPackagesOfficial - artifactName: drop_upload_upload_packages - variables: - - template: ./variable/release-shared.yml@self - parameters: - VERSION: $[ stageDependencies.setReleaseTagAndUploadTools.SetTagAndTools.outputs['OutputVersion.Version'] ] - - steps: - - template: release-install-pwsh.yml - - - pwsh: | - Write-Verbose -Verbose "Version: $(Version)" - Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - displayName: 'Capture Environment Variables' - - - pwsh: | - #Exclude all global tool packages. Their names start with 'PowerShell.' - $null = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/release" - Copy-Item "$(Pipeline.Workspace)/NuGetPackages/*.nupkg" -Destination "$(Pipeline.Workspace)/release" -Exclude "PowerShell.*.nupkg" -Force -Verbose - - $releaseVersion = '$(Version)' - $globalToolPath = "$(Pipeline.Workspace)/NuGetPackages/PowerShell.$releaseVersion.nupkg" - - if ($releaseVersion -notlike '*-*') { - # Copy the global tool package for stable releases - Copy-Item $globalToolPath -Destination "$(Pipeline.Workspace)/release" - } - - Write-Verbose -Verbose "The .nupkgs below will be pushed:" - Get-ChildItem "$(Pipeline.Workspace)/release" -recurse - displayName: Download and capture nupkgs - condition: and(ne('${{ parameters.skipPublish }}', 'false'), succeeded()) - - - task: NuGetCommand@2 - displayName: 'NuGet push' - condition: and(ne('${{ parameters.skipPublish }}', 'false'), succeeded()) - inputs: - command: push - packagesToPush: '$(Pipeline.Workspace)/release/*.nupkg' - nuGetFeedType: external - publishFeedCredentials: PowerShellNuGetOrgPush From c28e3ed09b37561cb51c9ef5e0df278d022f79c0 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 16 Apr 2025 15:13:33 -0700 Subject: [PATCH 111/275] [release/v7.5] Add default .NET install path for SDK validation (#25338) Co-authored-by: Aditya Patwardhan --- .pipelines/templates/release-validate-sdk.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index 0d50b213961..bba29ee0c34 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -87,7 +87,16 @@ jobs: Get-Content $nugetPath # Add workaround to unblock xUnit testing see issue: https://github.com/dotnet/sdk/issues/26462 - $dotnetPath = if ($IsWindows) { "$env:LocalAppData\Microsoft\dotnet" } else { "$env:HOME/.dotnet" } + + $possibleDotnetLocation = "$env:ProgramFiles\dotnet" + + $dotnetPath = if ($IsWindows) { + if (Test-Path $possibleDotnetLocation) { $possibleDotnetLocation } else { "$env:LocalAppData\Microsoft\dotnet" } + } + else { + "$env:HOME/.dotnet" + } + $env:DOTNET_ROOT = $dotnetPath dotnet --info From 0997007528dc22889834e18f99d4531265ab99b1 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 17 Apr 2025 10:05:59 -0700 Subject: [PATCH 112/275] [release/v7.5] Switch to ubuntu-lastest for CI (#25374) Co-authored-by: Travis Plunk --- .github/workflows/linux-ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index eda1ea56167..a7523f430cf 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -64,7 +64,7 @@ jobs: ci_build: name: Build PowerShell - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest needs: changes if: ${{ needs.changes.outputs.source == 'true' }} steps: @@ -81,7 +81,7 @@ jobs: - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: checkout uses: actions/checkout@v4.1.0 @@ -98,7 +98,7 @@ jobs: - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: checkout uses: actions/checkout@v4.1.0 @@ -115,7 +115,7 @@ jobs: - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: checkout uses: actions/checkout@v4.1.0 @@ -132,7 +132,7 @@ jobs: - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: checkout uses: actions/checkout@v4.1.0 From c2e858b9beb44a00d915803ea9927ab2e72e9189 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 17 Apr 2025 12:37:01 -0700 Subject: [PATCH 113/275] [release/v7.5] Update to .NET SDK 9.0.203 (#25373) --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 8 +- ...soft.PowerShell.Commands.Management.csproj | 4 +- ...crosoft.PowerShell.Commands.Utility.csproj | 6 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 98 ++++++------- .../Microsoft.WSMan.Management.csproj | 4 +- .../System.Management.Automation.csproj | 24 ++-- .../BenchmarkDotNet.Extensions.csproj | 4 +- .../ResultsComparer/ResultsComparer.csproj | 4 +- ...soft.PowerShell.NamedPipeConnection.csproj | 24 ++-- test/tools/TestService/TestService.csproj | 94 ++++++------ test/tools/WebListener/WebListener.csproj | 6 +- tools/cgmanifest.json | 136 +++++++----------- 15 files changed, 194 insertions(+), 224 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index e0869f46def..f78f43e709b 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "9.0.201", + "sdkImageVersion": "9.0.203", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 4667f91bae2..e4da652c648 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.201" + "version": "9.0.203" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index d8ab11d9740..4952c8f6ad4 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,11 +7,11 @@ - - - + + + - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 5494c8fa316..4fe6ed61803 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 797849a7e40..1cc347541a2 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -13,7 +13,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + @@ -41,8 +41,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 21912472c59..e5f5b849645 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 549224f457d..1d1fc2f1291 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -17,55 +17,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 8c0f4165524..db972fa45c8 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,11 +7,11 @@ - + - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index ed65de03c1a..afc4c178cb3 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,25 +32,25 @@ - - - - - - + + + + + + - + - - - - + + + + - + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 8eb7c19141f..6f6ef0087ab 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -11,9 +11,9 @@ - + - + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index a7b60b6eb1b..164023a0f62 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -11,9 +11,9 @@ - + - + diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index d0aeab862f9..aa15f08cb56 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -20,18 +20,18 @@ - - - - - - - + + + + + + + - - - - - + + + + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 65837bc7e48..31a95e0b875 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,56 +15,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index d2181a374d7..b609555c9ad 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,9 +7,9 @@ - - + + - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index feb4257f1d0..e64601d8eaf 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -1,5 +1,4 @@ { - "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -116,17 +115,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "8.0.14" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "Microsoft.Management.Infrastructure.Runtime.Unix", - "Version": "3.0.0" + "Version": "8.0.15" } }, "DevelopmentDependency": false @@ -141,16 +130,6 @@ }, "DevelopmentDependency": true }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "Microsoft.Management.Infrastructure", - "Version": "3.0.0" - } - }, - "DevelopmentDependency": false - }, { "Component": { "Type": "nuget", @@ -161,16 +140,6 @@ }, "DevelopmentDependency": false }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "Microsoft.PowerShell.Native", - "Version": "7.4.0" - } - }, - "DevelopmentDependency": false - }, { "Component": { "Type": "nuget", @@ -186,7 +155,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -206,7 +175,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -216,7 +185,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -236,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -246,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -256,7 +225,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -266,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -276,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -286,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -296,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -306,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -316,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -326,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -336,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -346,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -356,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -366,7 +335,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -386,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -396,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -406,7 +375,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -466,7 +435,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -486,7 +455,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -496,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -506,7 +475,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -516,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -526,7 +495,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -546,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.DiagnosticSource", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -556,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -566,7 +535,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -576,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -586,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -596,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -606,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -616,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -626,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -636,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -646,7 +615,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -676,7 +645,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -706,7 +675,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -726,7 +695,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -736,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -746,7 +715,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -756,7 +725,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -826,7 +795,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -836,7 +805,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -846,7 +815,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -856,7 +825,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encoding.CodePages", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -866,7 +835,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encodings.Web", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -876,7 +845,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false @@ -896,10 +865,11 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.3" + "Version": "9.0.4" } }, "DevelopmentDependency": false } - ] + ], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" } From b7de3c5aea083dda0d041ef7102269d6cccaf2b0 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 17 Apr 2025 12:38:47 -0700 Subject: [PATCH 114/275] [release/v7.5] Add CodeQL suppressions for PowerShell intended behavior (#25375) Co-authored-by: Anam Navied Co-authored-by: Travis Plunk --- .../commands/utility/AddType.cs | 1 + .../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 1 + src/System.Management.Automation/engine/ExecutionContext.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs index 81ca82cb3c3..7dc0a9c3556 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs @@ -684,6 +684,7 @@ private void LoadAssemblies(IEnumerable assemblies) { // CoreCLR doesn't allow re-load TPA assemblies with different API (i.e. we load them by name and now want to load by path). // LoadAssemblyHelper helps us avoid re-loading them, if they already loaded. + // codeql[cs/dll-injection-remote] - This is expected PowerShell behavior and integral to the purpose of the class. It allows users to load any C# dependencies they need for their PowerShell application and add other types they require. Assembly assembly = LoadAssemblyHelper(assemblyName) ?? Assembly.LoadFrom(ResolveAssemblyName(assemblyName, false)); if (PassThru) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs index 886c04919b6..810b54a8391 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs @@ -1771,6 +1771,7 @@ private static StringContent GetMultipartStringContent(object fieldName, object ContentDispositionHeaderValue contentDisposition = new("form-data"); contentDisposition.Name = LanguagePrimitives.ConvertTo(fieldName); + // codeql[cs/information-exposure-through-exception] - PowerShell is an on-premise product, meaning local users would already have access to the binaries and stack traces. Therefore, the information would not be exposed in the same way it would be for an ASP .NET service. StringContent result = new(LanguagePrimitives.ConvertTo(fieldValue)); result.Headers.ContentDisposition = contentDisposition; diff --git a/src/System.Management.Automation/engine/ExecutionContext.cs b/src/System.Management.Automation/engine/ExecutionContext.cs index 56f64c1a5c2..e0e078346e9 100644 --- a/src/System.Management.Automation/engine/ExecutionContext.cs +++ b/src/System.Management.Automation/engine/ExecutionContext.cs @@ -1385,6 +1385,7 @@ private static Assembly LoadAssembly(string name, string filePath, out Exception { try { + // codeql[cs/dll-injection-remote] - The dll is loaded during the initial state setup, which is expected behavior. This allows users hosting PowerShell to load additional C# types to enable their specific scenarios. loadedAssembly = Assembly.LoadFrom(filePath); return loadedAssembly; } From a873b33b65d507b613f09d569cb50b683cc8fdf0 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 17 Apr 2025 15:00:53 -0700 Subject: [PATCH 115/275] [release/v7.5] Enhance path filters action to set outputs for all changes when not a PR (#25379) Co-authored-by: Travis Plunk --- .../infrastructure/path-filters/action.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml index 58255fab55c..78426bdff03 100644 --- a/.github/actions/infrastructure/path-filters/action.yml +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -35,6 +35,23 @@ runs: with: github-token: ${{ inputs.GITHUB_TOKEN }} script: | + console.log(`Event Name: ${context.eventName}`); + + // Just say everything changed if this is not a PR + if (context.eventName !== 'pull_request') { + console.log('Not a pull request, setting all outputs to true'); + core.setOutput('toolsChanged', true); + core.setOutput('githubChanged', true); + core.setOutput('propsChanged', true); + core.setOutput('testsChanged', true); + core.setOutput('mainSourceChanged', true); + core.setOutput('buildModuleChanged', true); + core.setOutput('source', true); + return; + } + + console.log(`Getting files changed in PR #${context.issue.number}`); + // Fetch the list of files changed in the PR let files = []; let page = 1; From 16f5b4552692c975e97bfda935b182da8e26ab37 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 17 Apr 2025 15:01:59 -0700 Subject: [PATCH 116/275] [release/v7.5] Retry ClearlyDefined operations (#25387) Co-authored-by: Travis Plunk --- tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 index 2a9434c9cbe..4d874402977 100644 --- a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 +++ b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 @@ -27,7 +27,7 @@ function Start-ClearlyDefinedHarvest { $coordinates = Get-ClearlyDefinedCoordinates @PSBoundParameters $body = @{tool='package';coordinates=$coordinates} | convertto-json Write-Verbose $body -Verbose - (Invoke-WebRequest -Method Post -Uri 'https://api.clearlydefined.io/harvest' -Body $body -ContentType 'application/json').Content + (Invoke-WebRequest -Method Post -Uri 'https://api.clearlydefined.io/harvest' -Body $body -ContentType 'application/json' -MaximumRetryCount 5 -RetryIntervalSec 60 -Verbose).Content } } @@ -117,7 +117,7 @@ Function Get-ClearlyDefinedData { continue } - Invoke-RestMethod -Uri "https://api.clearlydefined.io/definitions/$coordinates" | ForEach-Object { + Invoke-RestMethod -Uri "https://api.clearlydefined.io/definitions/$coordinates" -MaximumRetryCount 5 -RetryIntervalSec 60 | ForEach-Object { [bool] $harvested = if ($_.licensed.declared) { $true } else { $false } Add-Member -NotePropertyName cachedTime -NotePropertyValue (get-date) -InputObject $_ -PassThru | Add-Member -NotePropertyName harvested -NotePropertyValue $harvested -PassThru if ($_.harvested) { From 7b21583dc6aa55d9c74d083e41e805d1d985e2a0 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 21 Apr 2025 14:43:01 -0700 Subject: [PATCH 117/275] [release/v7.5] Update APIScan to use new symbols server (#25399) Co-authored-by: Travis Plunk --- .pipelines/apiscan-gen-notice.yml | 5 ++++- .pipelines/templates/compliance/apiscan.yml | 20 ++++++++++++++++---- build.psm1 | 8 ++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/.pipelines/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml index f4fd167d7a0..1507b9345bd 100644 --- a/.pipelines/apiscan-gen-notice.yml +++ b/.pipelines/apiscan-gen-notice.yml @@ -13,6 +13,9 @@ parameters: default: false variables: + # PAT permissions NOTE: Declare a SymbolServerPAT variable in this group with a 'microsoft' organizanization scoped PAT with 'Symbols' Read permission. + # A PAT in the wrong org will give a single Error 203. No PAT will give a single Error 401, and individual pdbs may be missing even if permissions are correct. + - group: symbols - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: CDP_DEFINITION_BUILD_COUNT @@ -86,8 +89,8 @@ extends: softwareName: "PowerShell" # Default is repo name versionNumber: "7.5" # Default is build number isLargeApp: false # Default: false. + symbolsFolder: $(SymbolsServerUrl);$(ob_outputDirectory) #softwareFolder - relative path to a folder to be scanned. Default value is root of artifacts folder. -#symbolsFolder - relative path to a folder that contains symbols. Default value is root of artifacts folder. tsaOptionsFile: .config\tsaoptions.json diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml index 4e945b40349..17f07a597b5 100644 --- a/.pipelines/templates/compliance/apiscan.yml +++ b/.pipelines/templates/compliance/apiscan.yml @@ -12,9 +12,6 @@ jobs: value: fromBranch # Defines the variables APIScanClient, APIScanTenant and APIScanSecret - group: PS-PS-APIScan - # PAT permissions NOTE: Declare a SymbolServerPAT variable in this group with a 'microsoft' organizanization scoped PAT with 'Symbols' Read permission. - # A PAT in the wrong org will give a single Error 203. No PAT will give a single Error 401, and individual pdbs may be missing even if permissions are correct. - - group: symbols - name: branchCounterKey value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] - name: branchCounter @@ -125,10 +122,25 @@ jobs: } Copy-Item -Path "$OutputFolder\*" -Destination '$(ob_outputDirectory)' -Recurse -Verbose - workingDirectory: '$(repoRoot)' displayName: 'Build PowerShell Source' + - pwsh: | + # Only key windows runtimes + Get-ChildItem -Path '$(ob_outputDirectory)\runtimes\*' -File -Recurse | Where-Object {$_.FullName -notmatch '.*\/runtimes\/win'} | Foreach-Object { + Write-Verbose -Verbose -Message "Deleting $($_.FullName)" + Remove-Item -Force -Verbose -Path $_.FullName + } + + # Temporarily remove runtimes/win-x64 due to issues with that runtime + Get-ChildItem -Path '$(ob_outputDirectory)\runtimes\*' -File -Recurse | Where-Object {$_.FullName -match '.*\/runtimes\/win-x86\/'} | Foreach-Object { + Write-Verbose -Verbose -Message "Deleting $($_.FullName)" + Remove-Item -Force -Verbose -Path $_.FullName + } + + workingDirectory: '$(repoRoot)' + displayName: 'Remove unused runtimes' + - task: CodeQL3000Finalize@0 # Add CodeQL Finalize task right after your 'Build' step. displayName: 🔏 CodeQL 3000 Finalize condition: eq(variables['CODEQL_ENABLED'], 'true') diff --git a/build.psm1 b/build.psm1 index b371891d706..ffaf7b02f9d 100644 --- a/build.psm1 +++ b/build.psm1 @@ -3676,6 +3676,14 @@ function New-NugetConfigFile { $content += $newLine + $nugetConfigFooterTemplate Set-Content -Path (Join-Path $Destination 'nuget.config') -Value $content -Force + + # Set the nuget.config file to be skipped by git + push-location $Destination + try { + git update-index --skip-worktree (Join-Path $Destination 'nuget.config') + } finally { + pop-location + } } function Clear-PipelineNugetAuthentication { From 61874845f400fc4261d5cba0d0a2546dfa55740d Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 21 Apr 2025 14:55:09 -0700 Subject: [PATCH 118/275] [release/v7.5] Use GitHubReleaseTask (#25402) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Travis Plunk --- .pipelines/PowerShell-Release-Official.yml | 8 ++-- ...ols.yml => release-SetTagAndChangelog.yml} | 30 +------------ .pipelines/templates/release-githubNuget.yml | 43 +++++++++++++++---- 3 files changed, 40 insertions(+), 41 deletions(-) rename .pipelines/templates/{release-SetTagAndTools.yml => release-SetTagAndChangelog.yml} (59%) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 46a6926fd7a..12b2c839c69 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -117,10 +117,10 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - stage: setReleaseTagAndUploadTools - displayName: 'Set Release Tag and Upload Tools' + - stage: setReleaseTagAndChangelog + displayName: 'Set Release Tag and Upload Changelog' jobs: - - template: /.pipelines/templates/release-SetTagAndTools.yml@self + - template: /.pipelines/templates/release-SetTagAndChangelog.yml@self - stage: msixbundle displayName: 'Create MSIX Bundle' @@ -284,7 +284,7 @@ extends: - stage: PublishGitHubReleaseAndNuget displayName: Publish GitHub and Nuget Release dependsOn: - - setReleaseTagAndUploadTools + - setReleaseTagAndChangelog - UpdateChangeLog variables: ob_release_environment: Production diff --git a/.pipelines/templates/release-SetTagAndTools.yml b/.pipelines/templates/release-SetTagAndChangelog.yml similarity index 59% rename from .pipelines/templates/release-SetTagAndTools.yml rename to .pipelines/templates/release-SetTagAndChangelog.yml index 7b8a946e323..f0c516dd28f 100644 --- a/.pipelines/templates/release-SetTagAndTools.yml +++ b/.pipelines/templates/release-SetTagAndChangelog.yml @@ -1,6 +1,6 @@ jobs: -- job: SetTagAndTools - displayName: Set Tag and Tools +- job: setTagAndChangelog + displayName: Set Tag and Upload Changelog condition: succeeded() pool: type: windows @@ -19,32 +19,6 @@ jobs: clean: true env: ob_restore_phase: true - - - checkout: PSInternalTools - clean: true - env: - ob_restore_phase: true - - - pwsh: | - New-Item -ItemType Directory -Path '$(Pipeline.Workspace)/ToolArtifact' - Get-ChildItem -Path '$(Build.SourcesDirectory)/Internal-PowerShellTeam-Tools/Scripts' -Filter 'GitHubRelease.psm1' -ErrorAction SilentlyContinue | - Copy-Item -Destination '$(Pipeline.Workspace)/ToolArtifact' -Verbose - displayName: Move GitHub Tool - - - task: onebranch.pipeline.signing@1 - displayName: Sign Tools - inputs: - command: 'sign' - signing_profile: internal_azure_service - files_to_sign: '*.ps1;*.psm1' - search_root: '$(Pipeline.Workspace)/ToolArtifact' - - - pwsh: | - Write-Verbose -Verbose "Creating output directory for release tools: $(ob_outputDirectory)/ToolArtifact" - New-Item -Path $(ob_outputDirectory)/ToolArtifact -ItemType Directory -Force - Get-ChildItem -Path "$(Pipeline.Workspace)/ToolArtifact/*" -Recurse | - Copy-Item -Destination $(ob_outputDirectory)/ToolArtifact -Recurse -Verbose - displayName: Upload Tools - pwsh: | Write-Verbose -Verbose "Release Tag: $(OutputReleaseTag.releaseTag)" diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index 2d76c13dc99..8aca980eff2 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -12,14 +12,14 @@ jobs: templateContext: inputs: - input: pipelineArtifact - artifactName: drop_setReleaseTagAndUploadTools_SetTagAndTools + artifactName: drop_setReleaseTagAndChangelog_SetTagAndChangelog - input: pipelineArtifact pipeline: PSPackagesOfficial artifactName: drop_upload_upload_packages variables: - template: ./variable/release-shared.yml@self parameters: - RELEASETAG: $[ stageDependencies.setReleaseTagAndUploadTools.SetTagAndTools.outputs['OutputReleaseTag.releaseTag'] ] + RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] steps: - task: PowerShell@2 @@ -62,12 +62,10 @@ jobs: displayName: List all files in the workspace - task: PowerShell@2 - condition: and(ne('${{ parameters.skipPublish }}', 'false'), succeeded()) inputs: targetType: inline pwsh: true script: | - Import-module '$(Pipeline.Workspace)/ToolArtifact/GitHubRelease.psm1' $releaseVersion = '$(ReleaseTag)' -replace '^v','' Write-Verbose -Verbose "Available modules: " Get-Module | Write-Verbose -Verbose @@ -89,8 +87,37 @@ jobs: Write-Verbose -Verbose "Selected content: `n$clContent" - Publish-ReleaseDraft -Tag '$(ReleaseTag)' -Name '$(ReleaseTag) Release of PowerShell' -Description $clContent -User PowerShell -Repository PowerShell -PackageFolder "$(Pipeline.Workspace)/GitHubPackages" -Token $(GitHubReleasePat) - displayName: Publish Release Draft + $releaseNotesFilePath = "$(Pipeline.Workspace)/release-notes.md" + $clContent | Out-File -FilePath $releaseNotesFilePath -Encoding utf8 + + Write-Host "##vso[task.setvariable variable=ReleaseNotesFilePath;]$releaseNotesFilePath" + + #if name has prelease then make prerelease true as a variable + if ($releaseVersion -like '*-*') { + Write-Host "##vso[task.setvariable variable=IsPreRelease;]true" + } else { + Write-Host "##vso[task.setvariable variable=IsPreRelease;]false" + } + displayName: Set variables for GitHub release task + + - pwsh: | + Write-Host "ReleaseNotes content:" + Get-Content "$(Pipeline.Workspace)/release-notes.md" -Raw | Out-String -width 9999 | Write-Host + displayName: Verify Release Notes + + - task: GitHubRelease@1 + inputs: + gitHubConnection: GitHubReleasePAT + repositoryName: PowerShell/PowerShell + target: master + assets: '$(Pipeline.Workspace)/GitHubPackages/*' + tagSource: 'userSpecifiedTag' + tag: '$(ReleaseTag)' + isDraft: true + addChangeLog: false + action: 'create' + releaseNotesFilePath: '$(ReleaseNotesFilePath)' + isPrerelease: '$(IsPreRelease)' - job: NuGetPublish displayName: Publish to NuGet @@ -100,15 +127,13 @@ jobs: os: windows templateContext: inputs: - - input: pipelineArtifact - artifactName: drop_setReleaseTagAndUploadTools_SetTagAndTools - input: pipelineArtifact pipeline: PSPackagesOfficial artifactName: drop_upload_upload_packages variables: - template: ./variable/release-shared.yml@self parameters: - VERSION: $[ stageDependencies.setReleaseTagAndUploadTools.SetTagAndTools.outputs['OutputVersion.Version'] ] + VERSION: $[ stageDependencies.setReleaseTagAndChangelog.SetTagAndChangelog.outputs['OutputVersion.Version'] ] steps: - template: release-install-pwsh.yml From c67404200ba69f11a219ec4c3ae8f66d7c8a42fe Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:32:30 -0500 Subject: [PATCH 119/275] Updated Third Party Notices (#25422) --- ThirdPartyNotices.txt | 104 +++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 4abb1717d67..d48be300df3 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -284,7 +284,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 8.0.12 - MIT +Microsoft.Extensions.ObjectPool 8.0.15 - MIT Copyright Jorn Zaefferer @@ -354,7 +354,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Security.Extensions 1.3.0 - MIT +Microsoft.Security.Extensions 1.4.0 - MIT (c) Microsoft Corporation @@ -446,7 +446,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Win32.Registry.AccessControl 9.0.1 - MIT +Microsoft.Win32.Registry.AccessControl 9.0.4 - MIT Copyright (c) 2021 @@ -536,7 +536,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Win32.SystemEvents 9.0.1 - MIT +Microsoft.Win32.SystemEvents 9.0.4 - MIT Copyright (c) 2021 @@ -626,7 +626,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Windows.Compatibility 9.0.1 - MIT +Microsoft.Windows.Compatibility 9.0.4 - MIT (c) Microsoft Corporation @@ -679,7 +679,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.android-arm.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.android-arm.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -769,7 +769,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-arm64.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.android-arm64.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -859,7 +859,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x64.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.android-x64.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -949,7 +949,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x86.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.android-x86.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -1039,7 +1039,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.linux-arm.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -1129,7 +1129,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -1219,7 +1219,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -1309,7 +1309,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -1399,7 +1399,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -1489,7 +1489,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -1579,7 +1579,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -1669,7 +1669,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-x64.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.linux-x64.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -1759,7 +1759,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -1849,7 +1849,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -1992,7 +1992,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -2082,7 +2082,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -2172,7 +2172,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-x64.runtime.native.System.IO.Ports 9.0.1 - MIT +runtime.osx-x64.runtime.native.System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -2262,7 +2262,7 @@ SOFTWARE. --------------------------------------------------------- -System.CodeDom 9.0.1 - MIT +System.CodeDom 9.0.4 - MIT Copyright (c) 2021 @@ -2438,7 +2438,7 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition 9.0.1 - MIT +System.ComponentModel.Composition 9.0.4 - MIT Copyright (c) 2021 @@ -2528,7 +2528,7 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition.Registration 9.0.1 - MIT +System.ComponentModel.Composition.Registration 9.0.4 - MIT Copyright (c) 2021 @@ -2618,7 +2618,7 @@ SOFTWARE. --------------------------------------------------------- -System.Configuration.ConfigurationManager 9.0.1 - MIT +System.Configuration.ConfigurationManager 9.0.4 - MIT Copyright (c) 2021 @@ -2708,7 +2708,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.Odbc 9.0.1 - MIT +System.Data.Odbc 9.0.4 - MIT Copyright (c) 2021 @@ -2798,7 +2798,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.OleDb 9.0.1 - MIT +System.Data.OleDb 9.0.4 - MIT Copyright (c) 2021 @@ -2941,7 +2941,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.DiagnosticSource 9.0.1 - MIT +System.Diagnostics.DiagnosticSource 9.0.4 - MIT Copyright (c) 2021 @@ -3031,7 +3031,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.EventLog 9.0.1 - MIT +System.Diagnostics.EventLog 9.0.4 - MIT Copyright (c) 2021 @@ -3121,7 +3121,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.PerformanceCounter 9.0.1 - MIT +System.Diagnostics.PerformanceCounter 9.0.4 - MIT Copyright (c) 2021 @@ -3211,7 +3211,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices 9.0.1 - MIT +System.DirectoryServices 9.0.4 - MIT Copyright (c) 2021 @@ -3301,7 +3301,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.AccountManagement 9.0.1 - MIT +System.DirectoryServices.AccountManagement 9.0.4 - MIT Copyright (c) 2021 @@ -3391,7 +3391,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.Protocols 9.0.1 - MIT +System.DirectoryServices.Protocols 9.0.4 - MIT Copyright (c) 2021 @@ -3481,7 +3481,7 @@ SOFTWARE. --------------------------------------------------------- -System.Drawing.Common 9.0.1 - MIT +System.Drawing.Common 9.0.4 - MIT (c) Microsoft Corporation @@ -3516,7 +3516,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Packaging 9.0.1 - MIT +System.IO.Packaging 9.0.4 - MIT Copyright (c) 2021 @@ -3606,7 +3606,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Ports 9.0.1 - MIT +System.IO.Ports 9.0.4 - MIT Copyright (c) 2021 @@ -3696,7 +3696,7 @@ SOFTWARE. --------------------------------------------------------- -System.Management 9.0.1 - MIT +System.Management 9.0.4 - MIT Copyright (c) 2021 @@ -3786,7 +3786,7 @@ SOFTWARE. --------------------------------------------------------- -System.Net.Http.WinHttpHandler 9.0.1 - MIT +System.Net.Http.WinHttpHandler 9.0.4 - MIT Copyright (c) 2021 @@ -3961,7 +3961,7 @@ SOFTWARE. --------------------------------------------------------- -System.Reflection.Context 9.0.1 - MIT +System.Reflection.Context 9.0.4 - MIT Copyright (c) 2021 @@ -4191,7 +4191,7 @@ SOFTWARE. --------------------------------------------------------- -System.Runtime.Caching 9.0.1 - MIT +System.Runtime.Caching 9.0.4 - MIT Copyright (c) 2021 @@ -4356,7 +4356,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Pkcs 9.0.1 - MIT +System.Security.Cryptography.Pkcs 9.0.4 - MIT Copyright (c) 2021 @@ -4446,7 +4446,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.ProtectedData 9.0.1 - MIT +System.Security.Cryptography.ProtectedData 9.0.4 - MIT Copyright (c) 2021 @@ -4536,7 +4536,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Xml 9.0.1 - MIT +System.Security.Cryptography.Xml 9.0.4 - MIT Copyright (c) 2021 @@ -4626,7 +4626,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Permissions 9.0.1 - MIT +System.Security.Permissions 9.0.4 - MIT Copyright (c) 2021 @@ -4965,7 +4965,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Syndication 9.0.1 - MIT +System.ServiceModel.Syndication 9.0.4 - MIT Copyright (c) 2021 @@ -5055,7 +5055,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceProcess.ServiceController 9.0.1 - MIT +System.ServiceProcess.ServiceController 9.0.4 - MIT Copyright (c) 2021 @@ -5145,7 +5145,7 @@ SOFTWARE. --------------------------------------------------------- -System.Speech 9.0.1 - MIT +System.Speech 9.0.4 - MIT Copyright (c) 2021 @@ -5235,7 +5235,7 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encoding.CodePages 9.0.1 - MIT +System.Text.Encoding.CodePages 9.0.4 - MIT Copyright (c) 2021 @@ -5325,7 +5325,7 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encodings.Web 9.0.1 - MIT +System.Text.Encodings.Web 9.0.4 - MIT Copyright (c) 2021 @@ -5415,7 +5415,7 @@ SOFTWARE. --------------------------------------------------------- -System.Threading.AccessControl 9.0.1 - MIT +System.Threading.AccessControl 9.0.4 - MIT Copyright (c) 2021 @@ -5541,7 +5541,7 @@ SOFTWARE. --------------------------------------------------------- -System.Windows.Extensions 9.0.1 - MIT +System.Windows.Extensions 9.0.4 - MIT Copyright (c) 2021 From 00a041754bc7555cbfdfb1bef4ba101b79772d37 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 23 Apr 2025 12:33:42 -0700 Subject: [PATCH 120/275] [release/v7.5] Add 7.5.1 Change log (#25424) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Dongbo Wang --- CHANGELOG/7.5.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index 702c60346e7..37aa3e27995 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -1,5 +1,84 @@ # 7.5 Changelog +## [7.5.1] + +### Engine Updates and Fixes + +- Fallback to AppLocker after `WldpCanExecuteFile` (#25305) + +### Code Cleanup + +
+ +
    +
  • Cleanup old release pipelines (#25236)
  • +
+ +
+ +### Tools + +- Do not run labels workflow in the internal repository (#25343) +- Update `CODEOWNERS` (#25321) +- Check GitHub token availability for `Get-Changelog` (#25328) +- Update PowerShell team members in `releaseTools.psm1` (#25302) + +### Build and Packaging Improvements + +
+ + + +

Update to .NET SDK 9.0.203

+ +
+ +
    +
  • Finish 7.5.0 release (#24855)
  • +
  • Add CodeQL suppressions for PowerShell intended behavior (#25375)
  • +
  • Update to .NET SDK 9.0.203 (#25373)
  • +
  • Switch to ubuntu-lastest for CI (#25374)
  • +
  • Add default .NET install path for SDK validation (#25338)
  • +
  • Combine GitHub and Nuget Release Stage (#25371)
  • +
  • Add Windows Store Signing to MSIX bundle (#25370)
  • +
  • Update test result processing to use NUnitXml format and enhance logging for better clarity (#25344)
  • +
  • Fix MSIX stage in release pipeline (#25345)
  • +
  • Make GitHub Workflows work in the internal mirror (#25342)
  • +
  • Update security extensions (#25322)
  • +
  • Disable SBOM generation on set variables job in release build (#25340)
  • +
  • Update GitHub Actions to work in private GitHub repo (#25332)
  • +
  • Revert "Cleanup old release pipelines (#25201)" (#25335)
  • +
  • Remove call to NuGet (#25334)
  • +
  • Simplify PR Template (#25333)
  • +
  • Update package pipeline windows image version (#25331)
  • +
  • Skip additional packages when generating component manifest (#25329)
  • +
  • Only build Linux for packaging changes (#25326)
  • +
  • Make Component Manifest Updater use neutral target in addition to RID target (#25325)
  • +
  • Remove Az module installs and AzureRM uninstalls in pipeline (#25327)
  • +
  • Make sure the vPack pipeline does not produce an empty package (#25320)
  • +
  • Add *.props and sort path filters for windows CI (#25316)
  • +
  • Fix V-Pack download package name (#25314)
  • +
  • Update path filters for Windows CI (#25312)
  • +
  • Give the pipeline runs meaningful names (#25309)
  • +
  • Migrate MacOS Signing to OneBranch (#25304)
  • +
  • Add UseDotnet task for installing dotnet (#25281)
  • +
  • Remove obsolete template from Windows Packaging CI (#25237)
  • +
  • Add setup dotnet action to the build composite action (#25235)
  • +
  • Add GitHub Actions workflow to verify PR labels (#25159)
  • +
  • Update branch for release - Transitive - true - minor (#24994)
  • +
  • Fix GitHub Action filter overmatching (#24958)
  • +
  • Fix release branch filters (#24959)
  • +
  • Convert powershell/PowerShell-CI-macos to GitHub Actions (#24954)
  • +
  • Convert powershell/PowerShell-CI-linux to GitHub Actions (#24946)
  • +
  • Convert powershell/PowerShell-Windows-CI to GitHub Actions (#24931)
  • +
  • PMC parse state correctly from update command's response (#24859)
  • +
  • Add EV2 support for publishing PowerShell packages to PMC (#24856)
  • +
+ +
+ +[7.5.1]: https://github.com/PowerShell/PowerShell/compare/v7.5.0...v7.5.1 + ## [7.5.0] ### Build and Packaging Improvements From 85a60f332237baa6bc059dacc88b0913de24053e Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 23 Apr 2025 13:36:04 -0700 Subject: [PATCH 121/275] [release/v7.5] Fix the expected path of .NET after using UseDotnet 2 task to install (#25425) Co-authored-by: Aditya Patwardhan --- .pipelines/templates/release-validate-sdk.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index bba29ee0c34..d879ab7f06e 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -86,19 +86,6 @@ jobs: Get-Content $nugetPath - # Add workaround to unblock xUnit testing see issue: https://github.com/dotnet/sdk/issues/26462 - - $possibleDotnetLocation = "$env:ProgramFiles\dotnet" - - $dotnetPath = if ($IsWindows) { - if (Test-Path $possibleDotnetLocation) { $possibleDotnetLocation } else { "$env:LocalAppData\Microsoft\dotnet" } - } - else { - "$env:HOME/.dotnet" - } - - $env:DOTNET_ROOT = $dotnetPath - dotnet --info dotnet restore dotnet test /property:RELEASE_VERSION=$releaseVersion --test-adapter-path:. "--logger:xunit;LogFilePath=$(System.DefaultWorkingDirectory)/test-hosting.xml" From 3a9ea0db0615010f68c3604b74a1a5c77af3b58a Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 24 Apr 2025 15:13:26 -0700 Subject: [PATCH 122/275] [release/v7.5] Use new variables template for vPack (#25435) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> --- .pipelines/PowerShell-vPack-Official.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 33c72f8963f..829e374e606 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -118,7 +118,7 @@ extends: ob_createvpack_verbose: true steps: - - template: tools/releaseBuild/azureDevOps/templates/SetVersionVariables.yml@self + - template: ./templates/SetVersionVariables.yml parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes From 2bab6df66a959e1dfe399045ba2820b81df08d6e Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 14 May 2025 14:56:12 -0700 Subject: [PATCH 123/275] [release/v7.5] Fix PSMethodInvocationConstraints.GetHashCode method (#25306) Co-authored-by: crazyjncsu --- src/System.Management.Automation/engine/MshMemberInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/MshMemberInfo.cs b/src/System.Management.Automation/engine/MshMemberInfo.cs index 369e0f3fcd6..7474ae8d645 100644 --- a/src/System.Management.Automation/engine/MshMemberInfo.cs +++ b/src/System.Management.Automation/engine/MshMemberInfo.cs @@ -2009,7 +2009,7 @@ public override bool Equals(object obj) } public override int GetHashCode() - => HashCode.Combine(MethodTargetType, ParameterTypes, GenericTypeParameters); + => HashCode.Combine(MethodTargetType, ParameterTypes.SequenceGetHashCode(), GenericTypeParameters.SequenceGetHashCode()); public override string ToString() { From 3ad624280bc2afb24189002f5a29d51dee7e76c0 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 3 Jun 2025 13:05:54 -0700 Subject: [PATCH 124/275] [release/v7.5] Remove the old fuzzy suggestion and fix the local script file name suggestion (#25330) Co-authored-by: Dongbo Wang --- .../FeedbackSubsystem/IFeedbackProvider.cs | 2 +- .../engine/hostifaces/HostUtilities.cs | 37 +++++-------------- .../resources/SuggestionStrings.resx | 3 ++ .../utils/Telemetry.cs | 2 +- test/xUnit/csharp/test_Feedback.cs | 4 +- 5 files changed, 16 insertions(+), 32 deletions(-) diff --git a/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs b/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs index 328eb4eee87..0af184f4e99 100644 --- a/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs +++ b/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs @@ -243,7 +243,7 @@ internal GeneralCommandErrorFeedback() public Guid Id => _guid; - public string Name => "general"; + public string Name => "General Feedback"; public string Description => "The built-in general feedback source for command errors."; diff --git a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs index 9e5612189fa..003625791b1 100644 --- a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs +++ b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs @@ -8,7 +8,6 @@ using System.Globalization; using System.Management.Automation.Host; using System.Management.Automation.Internal; -using System.Management.Automation.Language; using System.Management.Automation.Runspaces; using System.Management.Automation.Subsystem.Feedback; using System.Runtime.InteropServices; @@ -67,13 +66,6 @@ public static class HostUtilities $formatString -f $lastError.TargetObject,"".\$($lastError.TargetObject)"" "; - private static readonly string s_getFuzzyMatchedCommands = @" - [System.Diagnostics.DebuggerHidden()] - param([string] $formatString) - - $formatString -f [string]::Join(', ', (Get-Command $lastError.TargetObject -UseFuzzyMatching -FuzzyMinimumDistance 1 | Select-Object -First 5 -Unique -ExpandProperty Name)) - "; - private static readonly List s_suggestions = InitializeSuggestions(); private static bool HostSupportUnicode() @@ -97,28 +89,17 @@ private static bool HostSupportUnicode() private static List InitializeSuggestions() { - var suggestions = new List( - new Hashtable[] - { - NewSuggestion( - id: 3, - category: "General", - matchType: SuggestionMatchType.Dynamic, - rule: ScriptBlock.CreateDelayParsedScriptBlock(s_checkForCommandInCurrentDirectoryScript, isProductCode: true), - suggestion: ScriptBlock.CreateDelayParsedScriptBlock(s_createCommandExistsInCurrentDirectoryScript, isProductCode: true), - suggestionArgs: new object[] { CodeGeneration.EscapeSingleQuotedStringContent(SuggestionStrings.Suggestion_CommandExistsInCurrentDirectory) }, - enabled: true) - }); - - suggestions.Add( + var suggestions = new List() + { NewSuggestion( - id: 4, + id: 3, category: "General", - matchType: SuggestionMatchType.ErrorId, - rule: "CommandNotFoundException", - suggestion: ScriptBlock.CreateDelayParsedScriptBlock(s_getFuzzyMatchedCommands, isProductCode: true), - suggestionArgs: new object[] { CodeGeneration.EscapeSingleQuotedStringContent(SuggestionStrings.Suggestion_CommandNotFound) }, - enabled: true)); + matchType: SuggestionMatchType.Dynamic, + rule: ScriptBlock.CreateDelayParsedScriptBlock(s_checkForCommandInCurrentDirectoryScript, isProductCode: true), + suggestion: ScriptBlock.CreateDelayParsedScriptBlock(s_createCommandExistsInCurrentDirectoryScript, isProductCode: true), + suggestionArgs: new object[] { SuggestionStrings.Suggestion_CommandExistsInCurrentDirectory_Legacy }, + enabled: true) + }; return suggestions; } diff --git a/src/System.Management.Automation/resources/SuggestionStrings.resx b/src/System.Management.Automation/resources/SuggestionStrings.resx index ea249db55e7..9e325b2616c 100644 --- a/src/System.Management.Automation/resources/SuggestionStrings.resx +++ b/src/System.Management.Automation/resources/SuggestionStrings.resx @@ -123,6 +123,9 @@ PowerShell does not load commands from the current location by default (see 'Get If you trust this command, run the following command instead: + + The command "{0}" was not found, but does exist in the current location. PowerShell does not load commands from the current location by default. If you trust this command, instead type: "{1}". See "get-help about_Command_Precedence" for more details. + The most similar commands are: diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index 9e40e60a4d6..3579401e810 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -635,7 +635,7 @@ static ApplicationInsightsTelemetry() s_knownSubsystemNames = new HashSet(StringComparer.OrdinalIgnoreCase) { "Completion", - "general", + "General Feedback", "Windows Package Manager - WinGet", "Az Predictor" }; diff --git a/test/xUnit/csharp/test_Feedback.cs b/test/xUnit/csharp/test_Feedback.cs index 2c90118be55..eba627f7b0d 100644 --- a/test/xUnit/csharp/test_Feedback.cs +++ b/test/xUnit/csharp/test_Feedback.cs @@ -97,7 +97,7 @@ public static void GetFeedback() // Test the result from the 'general' feedback provider. Assert.Single(feedbacks); - Assert.Equal("general", feedbacks[0].Name); + Assert.Equal("General Feedback", feedbacks[0].Name); Assert.Equal(expectedCmd, feedbacks[0].Item.RecommendedActions[0]); // Expect the result from both 'general' and the 'slow' feedback providers. @@ -107,7 +107,7 @@ public static void GetFeedback() Assert.Equal(2, feedbacks.Count); FeedbackResult entry1 = feedbacks[0]; - Assert.Equal("general", entry1.Name); + Assert.Equal("General Feedback", entry1.Name); Assert.Equal(expectedCmd, entry1.Item.RecommendedActions[0]); FeedbackResult entry2 = feedbacks[1]; From bd83cbabe290b5b2cde4d909e904cdc805178b2a Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 3 Jun 2025 13:07:35 -0700 Subject: [PATCH 125/275] [release/v7.5] Move .NET method invocation logging to after the needed type conversion is done for method arguments (#25357) Co-authored-by: Dongbo Wang Co-authored-by: Travis Plunk Co-authored-by: Travis Plunk --- .../engine/runtime/Binding/Binders.cs | 107 ++++++++++++++---- 1 file changed, 86 insertions(+), 21 deletions(-) diff --git a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs index de36b9d7249..f4020547432 100644 --- a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs +++ b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs @@ -6943,20 +6943,6 @@ internal static DynamicMetaObject InvokeDotNetMethod( expr = Expression.Block(expr, ExpressionCache.AutomationNullConstant); } - // Expression block runs two expressions in order: - // - Log method invocation to AMSI Notifications (can throw PSSecurityException) - // - Invoke method - string targetName = methodInfo.ReflectedType?.FullName ?? string.Empty; - expr = Expression.Block( - Expression.Call( - CachedReflectionInfo.MemberInvocationLoggingOps_LogMemberInvocation, - Expression.Constant(targetName), - Expression.Constant(name), - Expression.NewArrayInit( - typeof(object), - args.Select(static e => e.Expression.Cast(typeof(object))))), - expr); - // If we're calling SteppablePipeline.{Begin|Process|End}, we don't want // to wrap exceptions - this is very much a special case to help error // propagation and ensure errors are attributed to the correct code (the @@ -7119,6 +7105,7 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, invocationType != MethodInvocationType.NonVirtual; var parameters = mi.GetParameters(); var argExprs = new Expression[parameters.Length]; + var argsToLog = new List(Math.Max(parameters.Length, args.Length)); for (int i = 0; i < parameters.Length; ++i) { @@ -7143,16 +7130,21 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, if (expandParameters) { - argExprs[i] = Expression.NewArrayInit( - paramElementType, - args.Skip(i).Select( - a => a.CastOrConvertMethodArgument( + IEnumerable elements = args + .Skip(i) + .Select(a => + a.CastOrConvertMethodArgument( paramElementType, paramName, mi.Name, allowCastingToByRefLikeType: false, temps, - initTemps))); + initTemps)) + .ToList(); + + argExprs[i] = Expression.NewArrayInit(paramElementType, elements); + // User specified the element arguments, so we log them instead of the compiler-created array. + argsToLog.AddRange(elements); } else { @@ -7163,13 +7155,18 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, allowCastingToByRefLikeType: false, temps, initTemps); + argExprs[i] = arg; + argsToLog.Add(arg); } } else if (i >= args.Length) { - Diagnostics.Assert(parameters[i].IsOptional, + // We don't log the default value for an optional parameter, as it's not specified by the user. + Diagnostics.Assert( + parameters[i].IsOptional, "if there are too few arguments, FindBestMethod should only succeed if parameters are optional"); + var argValue = parameters[i].DefaultValue; if (argValue == null) { @@ -7207,17 +7204,25 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, var psRefValue = Expression.Property(args[i].Expression.Cast(typeof(PSReference)), CachedReflectionInfo.PSReference_Value); initTemps.Add(Expression.Assign(temp, psRefValue.Convert(temp.Type))); copyOutTemps.Add(Expression.Assign(psRefValue, temp.Cast(typeof(object)))); + argExprs[i] = temp; + argsToLog.Add(temp); } else { - argExprs[i] = args[i].CastOrConvertMethodArgument( + var convertedArg = args[i].CastOrConvertMethodArgument( parameterType, paramName, mi.Name, allowCastingToByRefLikeType, temps, initTemps); + + argExprs[i] = convertedArg; + // If the converted arg is a byref-like type, then we log the original arg. + argsToLog.Add(convertedArg.Type.IsByRefLike + ? args[i].Expression + : convertedArg); } } } @@ -7263,6 +7268,12 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, } } + // We need to add one expression to log the .NET invocation before actually invoking: + // - Log method invocation to AMSI Notifications (can throw PSSecurityException) + // - Invoke method + string targetName = mi.ReflectedType?.FullName ?? string.Empty; + string methodName = mi.Name is ".ctor" ? "new" : mi.Name; + if (temps.Count > 0) { if (call.Type != typeof(void) && copyOutTemps.Count > 0) @@ -7273,8 +7284,13 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, copyOutTemps.Add(retValue); } + AddMemberInvocationLogging(initTemps, targetName, methodName, argsToLog); call = Expression.Block(call.Type, temps, initTemps.Append(call).Concat(copyOutTemps)); } + else + { + call = AddMemberInvocationLogging(call, targetName, methodName, argsToLog); + } return call; } @@ -7566,6 +7582,55 @@ internal static void InvalidateCache() } } +#nullable enable + private static Expression AddMemberInvocationLogging( + Expression expr, + string targetName, + string name, + List args) + { +#if UNIX + // For efficiency this is a no-op on non-Windows platforms. + return expr; +#else + Expression[] invocationArgs = new Expression[args.Count]; + for (int i = 0; i < args.Count; i++) + { + invocationArgs[i] = args[i].Cast(typeof(object)); + } + + return Expression.Block( + Expression.Call( + CachedReflectionInfo.MemberInvocationLoggingOps_LogMemberInvocation, + Expression.Constant(targetName), + Expression.Constant(name), + Expression.NewArrayInit(typeof(object), invocationArgs)), + expr); +#endif + } + + private static void AddMemberInvocationLogging( + List exprs, + string targetName, + string name, + List args) + { +#if !UNIX + Expression[] invocationArgs = new Expression[args.Count]; + for (int i = 0; i < args.Count; i++) + { + invocationArgs[i] = args[i].Cast(typeof(object)); + } + + exprs.Add(Expression.Call( + CachedReflectionInfo.MemberInvocationLoggingOps_LogMemberInvocation, + Expression.Constant(targetName), + Expression.Constant(name), + Expression.NewArrayInit(typeof(object), invocationArgs))); +#endif + } +#nullable disable + #endregion } From 8e4a10114234083871bf6d087cba8d1635c8b7c9 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 3 Jun 2025 13:08:28 -0700 Subject: [PATCH 126/275] [release/v7.5] Move MSIXBundle to Packages and Release to GitHub (#25517) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> --- .pipelines/PowerShell-Packages-Official.yml | 9 ++- .pipelines/PowerShell-Release-Official.yml | 8 -- ...reate-msix.yml => package-create-msix.yml} | 77 ++++++++----------- .pipelines/templates/uploadToAzure.yml | 35 +++++++++ 4 files changed, 75 insertions(+), 54 deletions(-) rename .pipelines/templates/{release-create-msix.yml => package-create-msix.yml} (60%) diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 30b9e415215..487e8cb9c6a 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -60,6 +60,7 @@ variables: value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] - name: branchCounter value: $[counter(variables['branchCounterKey'], 1)] + - group: MSIXSigningProfile resources: pipelines: @@ -246,7 +247,13 @@ extends: jobs: - template: /.pipelines/templates/nupkg.yml@self + - stage: msixbundle + displayName: 'Create MSIX Bundle' + dependsOn: [windows_package] + jobs: + - template: /.pipelines/templates/package-create-msix.yml@self + - stage: upload - dependsOn: [mac_package, windows_package, linux_package, nupkg] + dependsOn: [mac_package, windows_package, linux_package, nupkg, msixbundle] jobs: - template: /.pipelines/templates/uploadToAzure.yml@self diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 12b2c839c69..71ff540cacd 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -58,7 +58,6 @@ variables: - name: ReleaseTagVar value: ${{ parameters.ReleaseTagVar }} - group: PoolNames - - group: MSIXSigningProfile resources: repositories: @@ -122,12 +121,6 @@ extends: jobs: - template: /.pipelines/templates/release-SetTagAndChangelog.yml@self - - stage: msixbundle - displayName: 'Create MSIX Bundle' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-create-msix.yml@self - - stage: validateSdk displayName: 'Validate SDK' dependsOn: [] @@ -270,7 +263,6 @@ extends: - fxdpackages - gbltool - validateSdk - - msixbundle jobs: - template: /.pipelines/templates/approvalJob.yml@self diff --git a/.pipelines/templates/release-create-msix.yml b/.pipelines/templates/package-create-msix.yml similarity index 60% rename from .pipelines/templates/release-create-msix.yml rename to .pipelines/templates/package-create-msix.yml index 751ce1ec5e2..0ab2408e6a7 100644 --- a/.pipelines/templates/release-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -13,20 +13,32 @@ jobs: steps: - template: release-SetReleaseTagandContainerName.yml@self - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_arm64 - displayName: Download arm64 msix - patterns: '**/*.msix' - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_x64 - displayName: Download x64 msix - patterns: '**/*.msix' - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_x86 - displayName: Download x86 msix - patterns: '**/*.msix' + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_windows_package_package_win_arm64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download windows arm64 packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_windows_package_package_win_x64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download windows x64 packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_windows_package_package_win_x86 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download windows x86 packages # Finds the makeappx tool on the machine with image: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - pwsh: | @@ -53,7 +65,7 @@ jobs: $sourceDir = '$(Pipeline.Workspace)\releasePipeline\msix' $null = New-Item -Path $sourceDir -ItemType Directory -Force - $msixFiles = Get-ChildItem -Path "$(Pipeline.Workspace)/PSPackagesOfficial/*.msix" -Recurse + $msixFiles = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)/downloads/*.msix" -Recurse foreach ($msixFile in $msixFiles) { $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose } @@ -87,37 +99,12 @@ jobs: $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File Write-Verbose -Verbose "Signed bundle: $signedBundle" - Copy-Item -Path $signedBundle -Destination $(ob_outputDirectory) -Verbose + if (-not (Test-Path $(ob_outputDirectory))) { + New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force + } + + Copy-Item -Path $signedBundle.FullName -Destination "$(ob_outputDirectory)" -Verbose Write-Verbose -Verbose "Uploaded Bundle:" Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose displayName: Upload msixbundle to Artifacts - - - task: AzurePowerShell@5 - displayName: Upload msix to blob - inputs: - azureSubscription: az-blob-cicd-infra - scriptType: inlineScript - azurePowerShellVersion: LatestVersion - pwsh: true - inline: | - $containerName = '$(OutputVersion.AzureVersion)-private' - $storageAccount = '$(StorageAccount)' - - $storageContext = New-AzStorageContext -StorageAccountName $storageAccount -UseConnectedAccount - - if ($env:BundleDir) { - $bundleFile = Get-Item "$env:BundleDir\*.msixbundle" - $blobName = $bundleFile | Split-Path -Leaf - $existing = Get-AzStorageBlob -Container $containerName -Blob $blobName -Context $storageContext -ErrorAction Ignore - if ($existing) { - Write-Verbose -Verbose "MSIX bundle already exists at '$storageAccount/$containerName/$blobName', removing first." - $existingBlob | Remove-AzStorageBlob -ErrorAction Stop -Verbose - } - - Write-Verbose -Verbose "Uploading $bundleFile to $containerName/$blobName" - Set-AzStorageBlobContent -File $bundleFile -Container $containerName -Blob $blobName -Context $storageContext -Force - } - else{ - throw "BundleDir not found" - } diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index 0994c7ef2b0..5f43ab4cd7f 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -25,6 +25,7 @@ jobs: value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - name: ob_sdl_codeql_compiled_enabled value: false + - group: 'Azure Blob variable group' steps: - checkout: self @@ -38,6 +39,8 @@ jobs: CreateJson: yes UseJson: no + - template: /.pipelines/templates/release-SetReleaseTagandContainerName.yml@self + - template: /.pipelines/templates/cloneToOfficialPath.yml@self - pwsh: | @@ -231,6 +234,15 @@ jobs: targetPath: '$(Build.ArtifactStagingDirectory)/downloads' displayName: Download macos x64 packages + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_msixbundle_CreateMSIXBundle + itemPattern: | + **/*.msixbundle + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download MSIXBundle + - pwsh: | Get-ChildItem '$(Build.ArtifactStagingDirectory)/downloads' | Select-Object -ExpandProperty FullName displayName: 'Capture downloads' @@ -397,3 +409,26 @@ jobs: Write-Host "File $blobName uploaded to $containerName container." Move-Item -Path $_.FullName -Destination $uploadedDirectory -Force -Verbose } + + $msixbundleFiles = Get-ChildItem -Path $downloadsDirectory -Filter "*.msixbundle" + + $containerName = '$(OutputVersion.AzureVersion)-private' + $storageAccount = '$(StorageAccount)' + + $storageContext = New-AzStorageContext -StorageAccountName $storageAccount -UseConnectedAccount + + if ($msixbundleFiles) { + $bundleFile = $msixbundleFiles[0].FullName + $blobName = $msixbundleFiles[0].Name + + $existing = Get-AzStorageBlob -Container $containerName -Blob $blobName -Context $storageContext -ErrorAction Ignore + if ($existing) { + Write-Verbose -Verbose "MSIX bundle already exists at '$storageAccount/$containerName/$blobName', removing first." + $existing | Remove-AzStorageBlob -ErrorAction Stop -Verbose + } + + Write-Verbose -Verbose "Uploading $bundleFile to $containerName/$blobName" + Set-AzStorageBlobContent -File $bundleFile -Container $containerName -Blob $blobName -Context $storageContext -Force + } else { + throw "MSIXBundle not found in $downloadsDirectory" + } From 2240ac8f5a9dbf1788d7f3b5f6ef2de8778e630d Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 3 Jun 2025 13:09:50 -0700 Subject: [PATCH 127/275] [release/v7.5] Make inherited protected internal instance members accessible in class scope. (#25547) Co-authored-by: Matthias Wolf <78562192+mawosoft@users.noreply.github.com> --- .../engine/CoreAdapter.cs | 4 +- .../engine/runtime/Binding/Binders.cs | 16 +- .../scripting.Classes.inheritance.tests.ps1 | 206 ++++++++++++++++++ 3 files changed, 217 insertions(+), 9 deletions(-) diff --git a/src/System.Management.Automation/engine/CoreAdapter.cs b/src/System.Management.Automation/engine/CoreAdapter.cs index 6183f98a0aa..907060bfe49 100644 --- a/src/System.Management.Automation/engine/CoreAdapter.cs +++ b/src/System.Management.Automation/engine/CoreAdapter.cs @@ -2835,7 +2835,7 @@ internal PropertyCacheEntry(PropertyInfo property) // Get the public or protected getter MethodInfo propertyGetter = property.GetGetMethod(true); - if (propertyGetter != null && (propertyGetter.IsPublic || propertyGetter.IsFamily)) + if (propertyGetter != null && (propertyGetter.IsPublic || propertyGetter.IsFamily || propertyGetter.IsFamilyOrAssembly)) { this.isStatic = propertyGetter.IsStatic; // Delegate is initialized later to avoid jit if it's not called @@ -2847,7 +2847,7 @@ internal PropertyCacheEntry(PropertyInfo property) // Get the public or protected setter MethodInfo propertySetter = property.GetSetMethod(true); - if (propertySetter != null && (propertySetter.IsPublic || propertySetter.IsFamily)) + if (propertySetter != null && (propertySetter.IsPublic || propertySetter.IsFamily || propertySetter.IsFamilyOrAssembly)) { this.isStatic = propertySetter.IsStatic; } diff --git a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs index f4020547432..18dfc8fb429 100644 --- a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs +++ b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs @@ -5297,7 +5297,8 @@ public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, Dy var propertyAccessor = adapterData.member as PropertyInfo; if (propertyAccessor != null) { - if (propertyAccessor.GetMethod.IsFamily && + var propertyGetter = propertyAccessor.GetMethod; + if ((propertyGetter.IsFamily || propertyGetter.IsFamilyOrAssembly) && (_classScope == null || !_classScope.IsSubclassOf(propertyAccessor.DeclaringType))) { return GenerateGetPropertyException(restrictions).WriteToDebugLog(this); @@ -5757,8 +5758,8 @@ internal PSMemberInfo GetPSMemberInfo(DynamicMetaObject target, var getMethod = propertyInfo.GetGetMethod(nonPublic: true); var setMethod = propertyInfo.GetSetMethod(nonPublic: true); - if ((getMethod == null || getMethod.IsFamily || getMethod.IsPublic) && - (setMethod == null || setMethod.IsFamily || setMethod.IsPublic)) + if ((getMethod == null || getMethod.IsPublic || getMethod.IsFamily || getMethod.IsFamilyOrAssembly) && + (setMethod == null || setMethod.IsPublic || setMethod.IsFamily || setMethod.IsFamilyOrAssembly)) { memberInfo = new PSProperty(this.Name, PSObject.DotNetInstanceAdapter, target.Value, new DotNetAdapter.PropertyCacheEntry(propertyInfo)); } @@ -5768,7 +5769,7 @@ internal PSMemberInfo GetPSMemberInfo(DynamicMetaObject target, var fieldInfo = member as FieldInfo; if (fieldInfo != null) { - if (fieldInfo.IsFamily) + if (fieldInfo.IsFamily || fieldInfo.IsFamilyOrAssembly) { memberInfo = new PSProperty(this.Name, PSObject.DotNetInstanceAdapter, target.Value, new DotNetAdapter.PropertyCacheEntry(fieldInfo)); } @@ -5776,7 +5777,7 @@ internal PSMemberInfo GetPSMemberInfo(DynamicMetaObject target, else { var methodInfo = member as MethodInfo; - if (methodInfo != null && (methodInfo.IsPublic || methodInfo.IsFamily)) + if (methodInfo != null && (methodInfo.IsPublic || methodInfo.IsFamily || methodInfo.IsFamilyOrAssembly)) { candidateMethods ??= new List(); @@ -6291,7 +6292,8 @@ public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, Dy var targetExpr = _static ? null : PSGetMemberBinder.GetTargetExpr(target, data.member.DeclaringType); if (propertyInfo != null) { - if (propertyInfo.SetMethod.IsFamily && + var propertySetter = propertyInfo.SetMethod; + if ((propertySetter.IsFamily || propertySetter.IsFamilyOrAssembly) && (_classScope == null || !_classScope.IsSubclassOf(propertyInfo.DeclaringType))) { return GeneratePropertyAssignmentException(restrictions).WriteToDebugLog(this); @@ -7891,7 +7893,7 @@ public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, ? BindingRestrictions.GetTypeRestriction(target.Expression, target.Value.GetType()) : target.PSGetTypeRestriction(); restrictions = args.Aggregate(restrictions, static (current, arg) => current.Merge(arg.PSGetMethodArgumentRestriction())); - var newConstructors = DotNetAdapter.GetMethodInformationArray(ctors.Where(static c => c.IsPublic || c.IsFamily).ToArray()); + var newConstructors = DotNetAdapter.GetMethodInformationArray(ctors.Where(static c => c.IsPublic || c.IsFamily || c.IsFamilyOrAssembly).ToArray()); return PSInvokeMemberBinder.InvokeDotNetMethod(_callInfo, "new", _constraints, PSInvokeMemberBinder.MethodInvocationType.BaseCtor, target, args, restrictions, newConstructors, typeof(MethodException)); } diff --git a/test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1 b/test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1 index af013076029..d10291353cd 100644 --- a/test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1 +++ b/test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1 @@ -672,3 +672,209 @@ Describe 'Base type has abstract properties' -Tags "CI" { $failure.Exception.Message | Should -BeLike "*'get_Exists'*" } } + +Describe 'Classes inheritance with protected and protected internal members in base class' -Tags 'CI' { + + BeforeAll { + Set-StrictMode -Version 3 + $c1DefinitionProtectedInternal = @' + public class C1ProtectedInternal + { + protected internal string InstanceField = "C1_InstanceField"; + protected internal string InstanceProperty { get; set; } = "C1_InstanceProperty"; + protected internal string InstanceMethod() { return "C1_InstanceMethod"; } + + protected internal virtual string VirtualProperty1 { get; set; } = "C1_VirtualProperty1"; + protected internal virtual string VirtualProperty2 { get; set; } = "C1_VirtualProperty2"; + protected internal virtual string VirtualMethod1() { return "C1_VirtualMethod1"; } + protected internal virtual string VirtualMethod2() { return "C1_VirtualMethod2"; } + + public string CtorUsed { get; set; } + public C1ProtectedInternal() { CtorUsed = "default ctor"; } + protected internal C1ProtectedInternal(string p1) { CtorUsed = "C1_ctor_1args:" + p1; } + } +'@ + $c2DefinitionProtectedInternal = @' + class C2ProtectedInternal : C1ProtectedInternal { + C2ProtectedInternal() : base() { $this.VirtualProperty2 = 'C2_VirtualProperty2' } + C2ProtectedInternal([string]$p1) : base($p1) { $this.VirtualProperty2 = 'C2_VirtualProperty2' } + + [string]GetInstanceField() { return $this.InstanceField } + [string]SetInstanceField([string]$value) { $this.InstanceField = $value; return $this.InstanceField } + [string]GetInstanceProperty() { return $this.InstanceProperty } + [string]SetInstanceProperty([string]$value) { $this.InstanceProperty = $value; return $this.InstanceProperty } + [string]CallInstanceMethod() { return $this.InstanceMethod() } + + [string]GetVirtualProperty1() { return $this.VirtualProperty1 } + [string]SetVirtualProperty1([string]$value) { $this.VirtualProperty1 = $value; return $this.VirtualProperty1 } + [string]CallVirtualMethod1() { return $this.VirtualMethod1() } + + [string]$VirtualProperty2 + [string]VirtualMethod2() { return 'C2_VirtualMethod2' } + # Note: Overriding a virtual property in a derived PowerShell class prevents access to the + # base property via simple typecast ([base]$this).VirtualProperty2. + [string]GetVirtualProperty2() { return $this.VirtualProperty2 } + [string]SetVirtualProperty2([string]$value) { $this.VirtualProperty2 = $value; return $this.VirtualProperty2 } + [string]CallVirtualMethod2Base() { return ([C1ProtectedInternal]$this).VirtualMethod2() } + [string]CallVirtualMethod2Derived() { return $this.VirtualMethod2() } + + [string]GetInstanceMemberDynamic([string]$name) { return $this.$name } + [string]SetInstanceMemberDynamic([string]$name, [string]$value) { $this.$name = $value; return $this.$name } + [string]CallInstanceMemberDynamic([string]$name) { return $this.$name() } + } + + [C2ProtectedInternal] +'@ + + Add-Type -TypeDefinition $c1DefinitionProtectedInternal + Add-Type -TypeDefinition (($c1DefinitionProtectedInternal -creplace 'C1ProtectedInternal', 'C1Protected') -creplace 'protected internal', 'protected') + + $testCases = @( + @{ accessType = 'protected'; derivedType = Invoke-Expression ($c2DefinitionProtectedInternal -creplace 'ProtectedInternal', 'Protected') } + @{ accessType = 'protected internal'; derivedType = Invoke-Expression $c2DefinitionProtectedInternal } + ) + } + + AfterAll { + Set-StrictMode -Off + } + + Context 'Derived class can access instance base class members' { + + It 'can call protected internal .NET method Object.MemberwiseClone()' { + class CNetMethod { + [string]$Foo + [object]CloneIt() { return $this.MemberwiseClone() } + } + $c1 = [CNetMethod]::new() + $c1.Foo = 'bar' + $c2 = $c1.CloneIt() + $c2.Foo | Should -Be 'bar' + } + + It 'can call base ctor' -TestCases $testCases { + param($derivedType) + $derivedType::new('foo').CtorUsed | Should -Be 'C1_ctor_1args:foo' + } + + It 'can access base field' -TestCases $testCases { + param($derivedType) + $c2 = $derivedType::new() + $c2.GetInstanceField() | Should -Be 'C1_InstanceField' + $c2.SetInstanceField('foo_InstanceField') | Should -Be 'foo_InstanceField' + } + + It 'can access base property' -TestCases $testCases { + param($derivedType) + $c2 = $derivedType::new() + $c2.GetInstanceProperty() | Should -Be 'C1_InstanceProperty' + $c2.SetInstanceProperty('foo_InstanceProperty') | Should -Be 'foo_InstanceProperty' + } + + It 'can call base method' -TestCases $testCases { + param($derivedType) + $derivedType::new().CallInstanceMethod() | Should -Be 'C1_InstanceMethod' + } + + It 'can access virtual base property' -TestCases $testCases { + param($derivedType) + $c2 = $derivedType::new() + $c2.GetVirtualProperty1() | Should -Be 'C1_VirtualProperty1' + $c2.SetVirtualProperty1('foo_VirtualProperty1') | Should -Be 'foo_VirtualProperty1' + } + + It 'can call virtual base method' -TestCases $testCases { + param($derivedType) + $derivedType::new().CallVirtualMethod1() | Should -Be 'C1_VirtualMethod1' + } + } + + Context 'Derived class can override virtual base class members' { + + It 'can override virtual base property' -TestCases $testCases { + param($derivedType) + $c2 = $derivedType::new() + $c2.GetVirtualProperty2() | Should -Be 'C2_VirtualProperty2' + $c2.SetVirtualProperty2('foo_VirtualProperty2') | Should -Be 'foo_VirtualProperty2' + } + + It 'can override virtual base method' -TestCases $testCases { + param($derivedType) + $c2 = $derivedType::new() + $c2.CallVirtualMethod2Base() | Should -Be 'C1_VirtualMethod2' + $c2.CallVirtualMethod2Derived() | Should -Be 'C2_VirtualMethod2' + } + } + + Context 'Derived class can access instance base class members dynamically' { + + It 'can access base fields and properties' -TestCases $testCases { + param($derivedType) + $c2 = $derivedType::new() + $c2.GetInstanceMemberDynamic('InstanceField') | Should -Be 'C1_InstanceField' + $c2.GetInstanceMemberDynamic('InstanceProperty') | Should -Be 'C1_InstanceProperty' + $c2.GetInstanceMemberDynamic('VirtualProperty1') | Should -Be 'C1_VirtualProperty1' + $c2.SetInstanceMemberDynamic('InstanceField', 'foo1') | Should -Be 'foo1' + $c2.SetInstanceMemberDynamic('InstanceProperty', 'foo2') | Should -Be 'foo2' + $c2.SetInstanceMemberDynamic('VirtualProperty1', 'foo3') | Should -Be 'foo3' + } + + It 'can call base methods' -TestCases $testCases { + param($derivedType) + $c2 = $derivedType::new() + $c2.CallInstanceMemberDynamic('InstanceMethod') | Should -Be 'C1_InstanceMethod' + $c2.CallInstanceMemberDynamic('VirtualMethod1') | Should -Be 'C1_VirtualMethod1' + } + } + + Context 'Base class members are not accessible outside class scope' { + + BeforeAll { + $instanceTest = { + $c2 = $derivedType::new() + { $null = $c2.InstanceField } | Should -Throw -ErrorId 'PropertyNotFoundStrict' + { $null = $c2.InstanceProperty } | Should -Throw -ErrorId 'PropertyNotFoundStrict' + { $null = $c2.VirtualProperty1 } | Should -Throw -ErrorId 'PropertyNotFoundStrict' + { $c2.InstanceField = 'foo' } | Should -Throw -ErrorId 'PropertyAssignmentException' + { $c2.InstanceProperty = 'foo' } | Should -Throw -ErrorId 'PropertyAssignmentException' + { $c2.VirtualProperty1 = 'foo' } | Should -Throw -ErrorId 'PropertyAssignmentException' + { $derivedType::new().InstanceMethod() } | Should -Throw -ErrorId 'MethodNotFound' + { $derivedType::new().VirtualMethod1() } | Should -Throw -ErrorId 'MethodNotFound' + foreach ($name in @('InstanceField', 'InstanceProperty', 'VirtualProperty1')) { + { $null = $c2.$name } | Should -Throw -ErrorId 'PropertyNotFoundStrict' + { $c2.$name = 'foo' } | Should -Throw -ErrorId 'PropertyAssignmentException' + } + foreach ($name in @('InstanceMethod', 'VirtualMethod1')) { + { $c2.$name() } | Should -Throw -ErrorId 'MethodNotFound' + } + } + $c3UnrelatedType = Invoke-Expression @" + class C3Unrelated { + [void]RunInstanceTest([type]`$derivedType) { $instanceTest } + } + [C3Unrelated] +"@ + $negativeTestCases = $testCases.ForEach({ + $item = $_.Clone() + $item['scopeType'] = 'null scope' + $item['classScope'] = $null + $item + $item = $_.Clone() + $item['scopeType'] = 'unrelated class scope' + $item['classScope'] = $c3UnrelatedType + $item + }) + } + + It 'cannot access instance base members in ' -TestCases $negativeTestCases { + param($derivedType, $classScope) + if ($null -eq $classScope) { + $instanceTest.Invoke() + } + else { + $c3 = $classScope::new() + $c3.RunInstanceTest($derivedType) + } + } + } +} From ebbb97c71b26bedec3e1b33300b626474d4c9a58 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 3 Jun 2025 13:20:38 -0700 Subject: [PATCH 128/275] [release/v7.5] Fix MSIX artifact upload, vPack template, changelog hashes, git tag command (#25633) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Travis Plunk --- .pipelines/PowerShell-Release-Official.yml | 13 +--- .pipelines/PowerShell-vPack-Official.yml | 2 +- .pipelines/templates/package-create-msix.yml | 8 +- .pipelines/templates/release-githubNuget.yml | 82 ++++++++++++++------ 4 files changed, 64 insertions(+), 41 deletions(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 71ff540cacd..55c6ec1c486 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -325,17 +325,6 @@ extends: instructions: | Run PowerShell-Release-Official-Azure.yml pipeline to publish to PMC - - stage: ReleaseDocker - dependsOn: PushGitTagAndMakeDraftPublic - displayName: 'Docker Release' - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Start Docker Release - jobName: StartDockerRelease - instructions: | - Kickoff docker release - - stage: UpdateDotnetDocker dependsOn: PushGitTagAndMakeDraftPublic displayName: Update DotNet SDK Docker images @@ -348,7 +337,7 @@ extends: Create PR for updating dotnet-docker images to use latest PowerShell version. 1. Fork and clone https://github.com/dotnet/dotnet-docker.git 2. git checkout upstream/nightly -b updatePS - 3. dotnet run --project .\eng\update-dependencies\ -- --product-version powershell= --compute-shas + 3. dotnet run --project .\eng\update-dependencies\ specific --product-version powershell= --compute-shas 4. create PR targeting nightly branch - stage: UpdateWinGet diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 829e374e606..9a9aceed387 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -118,7 +118,7 @@ extends: ob_createvpack_verbose: true steps: - - template: ./templates/SetVersionVariables.yml + - template: .pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 0ab2408e6a7..c8312ad926e 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -99,11 +99,13 @@ jobs: $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File Write-Verbose -Verbose "Signed bundle: $signedBundle" - if (-not (Test-Path $(ob_outputDirectory))) { - New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force + # Ensure the destination directory exists + if (-not (Test-Path -Path "$(ob_outputDirectory)")) { + Write-Verbose -Verbose "Creating destination directory: $(ob_outputDirectory)" + New-Item -Path "$(ob_outputDirectory)" -ItemType Directory -Force | Out-Null } - Copy-Item -Path $signedBundle.FullName -Destination "$(ob_outputDirectory)" -Verbose + Copy-Item -Path $signedBundle.FullName -Destination "$(ob_outputDirectory)\$($signedBundle.Name)" -Verbose Write-Verbose -Verbose "Uploaded Bundle:" Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index 8aca980eff2..ba0db845bfd 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -30,12 +30,9 @@ jobs: Get-ChildItem Env: | Out-String -Stream | Write-Verbose -Verbose displayName: 'Capture Environment Variables' - - template: release-install-pwsh.yml - - task: PowerShell@2 inputs: targetType: inline - pwsh: true script: | $Path = "$(Pipeline.Workspace)/GitHubPackages" $OutputPath = Join-Path $Path 'hashes.sha256' @@ -56,7 +53,6 @@ jobs: - task: PowerShell@2 inputs: targetType: inline - pwsh: true script: | Get-ChildItem $(Pipeline.Workspace) -recurse | Select-Object -ExpandProperty FullName displayName: List all files in the workspace @@ -64,7 +60,6 @@ jobs: - task: PowerShell@2 inputs: targetType: inline - pwsh: true script: | $releaseVersion = '$(ReleaseTag)' -replace '^v','' Write-Verbose -Verbose "Available modules: " @@ -85,6 +80,17 @@ jobs: $clContent = $changelog | Select-Object -Skip ($startLine-1) -First ($endLine - $startLine) | Out-String + $StringBuilder = [System.Text.StringBuilder]::new($clContent, $clContent.Length + 2kb) + $StringBuilder.AppendLine().AppendLine() > $null + $StringBuilder.AppendLine("### SHA256 Hashes of the release artifacts").AppendLine() > $null + Get-ChildItem -Path "$(Pipeline.Workspace)/GitHubPackages/" -File | ForEach-Object { + $PackageName = $_.Name + $SHA256 = (Get-FileHash -Path $_.FullName -Algorithm SHA256).Hash + $StringBuilder.AppendLine("- $PackageName").AppendLine(" - $SHA256") > $null + } + + $clContent = $StringBuilder.ToString() + Write-Verbose -Verbose "Selected content: `n$clContent" $releaseNotesFilePath = "$(Pipeline.Workspace)/release-notes.md" @@ -100,11 +106,32 @@ jobs: } displayName: Set variables for GitHub release task - - pwsh: | - Write-Host "ReleaseNotes content:" - Get-Content "$(Pipeline.Workspace)/release-notes.md" -Raw | Out-String -width 9999 | Write-Host + - task: PowerShell@2 + inputs: + targetType: inline + script: | + Write-Host "ReleaseNotes content:" + Get-Content "$(Pipeline.Workspace)/release-notes.md" -Raw | Out-String -width 9999 | Write-Host displayName: Verify Release Notes + - task: PowerShell@2 + inputs: + targetType: inline + script: | + $middleURL = '' + $tagString = "$(ReleaseTag)" + Write-Verbose -Verbose "Use the following command to push the tag:" + if ($tagString -match '-') { + $middleURL = "preview" + } + elseif ($tagString -match '(\d+\.\d+)') { + $middleURL = $matches[1] + } + $endURL = $tagString -replace '[v\.]','' + $message = "https://github.com/PowerShell/PowerShell/blob/master/CHANGELOG/$middleURL.md#$endURL" + Write-Verbose -Verbose "git tag -a $(ReleaseTag) $env:BUILD_SOURCEVERSION -m $message" + displayName: Git Push Tag Command + - task: GitHubRelease@1 inputs: gitHubConnection: GitHubReleasePAT @@ -113,6 +140,7 @@ jobs: assets: '$(Pipeline.Workspace)/GitHubPackages/*' tagSource: 'userSpecifiedTag' tag: '$(ReleaseTag)' + title: "$(ReleaseTag) Release of PowerShell" isDraft: true addChangeLog: false action: 'create' @@ -136,28 +164,32 @@ jobs: VERSION: $[ stageDependencies.setReleaseTagAndChangelog.SetTagAndChangelog.outputs['OutputVersion.Version'] ] steps: - - template: release-install-pwsh.yml - - - pwsh: | - Write-Verbose -Verbose "Version: $(Version)" - Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + - task: PowerShell@2 + inputs: + targetType: inline + script: | + Write-Verbose -Verbose "Version: $(Version)" + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: 'Capture Environment Variables' - - pwsh: | - #Exclude all global tool packages. Their names start with 'PowerShell.' - $null = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/release" - Copy-Item "$(Pipeline.Workspace)/NuGetPackages/*.nupkg" -Destination "$(Pipeline.Workspace)/release" -Exclude "PowerShell.*.nupkg" -Force -Verbose + - task: PowerShell@2 + inputs: + targetType: inline + script: | + #Exclude all global tool packages. Their names start with 'PowerShell.' + $null = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/release" + Copy-Item "$(Pipeline.Workspace)/NuGetPackages/*.nupkg" -Destination "$(Pipeline.Workspace)/release" -Exclude "PowerShell.*.nupkg" -Force -Verbose - $releaseVersion = '$(Version)' - $globalToolPath = "$(Pipeline.Workspace)/NuGetPackages/PowerShell.$releaseVersion.nupkg" + $releaseVersion = '$(Version)' + $globalToolPath = "$(Pipeline.Workspace)/NuGetPackages/PowerShell.$releaseVersion.nupkg" - if ($releaseVersion -notlike '*-*') { - # Copy the global tool package for stable releases - Copy-Item $globalToolPath -Destination "$(Pipeline.Workspace)/release" - } + if ($releaseVersion -notlike '*-*') { + # Copy the global tool package for stable releases + Copy-Item $globalToolPath -Destination "$(Pipeline.Workspace)/release" + } - Write-Verbose -Verbose "The .nupkgs below will be pushed:" - Get-ChildItem "$(Pipeline.Workspace)/release" -recurse + Write-Verbose -Verbose "The .nupkgs below will be pushed:" + Get-ChildItem "$(Pipeline.Workspace)/release" -recurse displayName: Download and capture nupkgs condition: and(ne('${{ parameters.skipPublish }}', 'false'), succeeded()) From 8249040f1ee1be3b76705034ea94b45b4c8e8716 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 4 Jun 2025 15:22:16 -0700 Subject: [PATCH 129/275] [release/v7.5] Change linux packaging tests to ubuntu latest (#25639) Co-authored-by: Travis Plunk --- .vsts-ci/linux.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vsts-ci/linux.yml b/.vsts-ci/linux.yml index 338821e37dd..b386b9c7eb3 100644 --- a/.vsts-ci/linux.yml +++ b/.vsts-ci/linux.yml @@ -67,7 +67,7 @@ stages: jobs: - template: templates/ci-build.yml parameters: - pool: ubuntu-20.04 + pool: ubuntu-latest jobName: linux_build displayName: linux Build @@ -77,4 +77,4 @@ stages: jobs: - template: linux/templates/packaging.yml parameters: - pool: ubuntu-20.04 + pool: ubuntu-latest From cd6b4d8f53f111fb27dc5fefba4af64e7d1de3c0 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:04:40 -0700 Subject: [PATCH 130/275] [release/v7.5] Set standard handles explicitly when starting a process with `-NoNewWindow` (#25324) Co-authored-by: Dongbo Wang Co-authored-by: Travis Plunk --- .../commands/management/Process.cs | 44 ++++++++++++++++--- .../Start-Process.Tests.ps1 | 14 ++++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs index 73f00b5acc6..4ca7d9aaa5b 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs @@ -1677,7 +1677,7 @@ public SwitchParameter LoadUserProfile private SwitchParameter _loaduserprofile = SwitchParameter.Present; /// - /// Starts process in a new window. + /// Starts process in the current console window. /// [Parameter(ParameterSetName = "Default")] [Alias("nnw")] @@ -1965,7 +1965,9 @@ protected override void BeginProcessing() startInfo.WindowStyle = _windowstyle; - if (_nonewwindow) + // When starting a process as another user, the 'CreateNoWindow' property value is ignored and a new window is created. + // See details at https://learn.microsoft.com/dotnet/api/system.diagnostics.processstartinfo.createnowindow?view=net-9.0#remarks + if (_nonewwindow && _credential is null) { startInfo.CreateNoWindow = _nonewwindow; } @@ -2413,33 +2415,60 @@ private static byte[] ConvertEnvVarsToByteArray(StringDictionary sd) private void SetStartupInfo(ProcessStartInfo startinfo, ref ProcessNativeMethods.STARTUPINFO lpStartupInfo, ref int creationFlags) { - bool hasRedirection = false; + // If we are starting a process using the current console window, we need to set its standard handles + // explicitly when they are not redirected because otherwise they won't be set and the new process will + // fail with the "invalid handle" error. + // + // However, if we are starting a process with a new console window, we should not explicitly set those + // standard handles when they are not redirected, but instead let Windows figure out the default to use + // when creating the process. Otherwise, the standard input handles of the current window and the new + // window will get weirdly tied together and cause problems. + bool hasRedirection = startinfo.CreateNoWindow + || _redirectstandardinput is not null + || _redirectstandardoutput is not null + || _redirectstandarderror is not null; + // RedirectionStandardInput if (_redirectstandardinput != null) { - hasRedirection = true; startinfo.RedirectStandardInput = true; _redirectstandardinput = ResolveFilePath(_redirectstandardinput); lpStartupInfo.hStdInput = GetSafeFileHandleForRedirection(_redirectstandardinput, FileMode.Open); } + else if (startinfo.CreateNoWindow) + { + lpStartupInfo.hStdInput = new SafeFileHandle( + ProcessNativeMethods.GetStdHandle(-10), + ownsHandle: false); + } // RedirectionStandardOutput if (_redirectstandardoutput != null) { - hasRedirection = true; startinfo.RedirectStandardOutput = true; _redirectstandardoutput = ResolveFilePath(_redirectstandardoutput); lpStartupInfo.hStdOutput = GetSafeFileHandleForRedirection(_redirectstandardoutput, FileMode.Create); } + else if (startinfo.CreateNoWindow) + { + lpStartupInfo.hStdOutput = new SafeFileHandle( + ProcessNativeMethods.GetStdHandle(-11), + ownsHandle: false); + } // RedirectionStandardError if (_redirectstandarderror != null) { - hasRedirection = true; startinfo.RedirectStandardError = true; _redirectstandarderror = ResolveFilePath(_redirectstandarderror); lpStartupInfo.hStdError = GetSafeFileHandleForRedirection(_redirectstandarderror, FileMode.Create); } + else if (startinfo.CreateNoWindow) + { + lpStartupInfo.hStdError = new SafeFileHandle( + ProcessNativeMethods.GetStdHandle(-12), + ownsHandle: false); + } if (hasRedirection) { @@ -2881,6 +2910,9 @@ internal struct JOBOBJECT_BASIC_PROCESS_ID_LIST internal static class ProcessNativeMethods { + [DllImport(PinvokeDllNames.GetStdHandleDllName, SetLastError = true)] + public static extern IntPtr GetStdHandle(int whichHandle); + [DllImport(PinvokeDllNames.CreateProcessWithLogonWDllName, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool CreateProcessWithLogonW(string userName, diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Start-Process.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Start-Process.Tests.ps1 index 50cde0bae6e..65dd74e1b94 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Start-Process.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Start-Process.Tests.ps1 @@ -241,3 +241,17 @@ Describe "Environment Tests" -Tags "Feature" { } } } + +Describe "Bug fixes" -Tags "CI" { + + ## https://github.com/PowerShell/PowerShell/issues/24986 + It "Error redirection along with '-NoNewWindow' should work for Start-Process" -Skip:(!$IsWindows) { + $errorFile = Join-Path -Path $TestDrive -ChildPath error.txt + $out = pwsh -noprofile -c "Start-Process -Wait -NoNewWindow -RedirectStandardError $errorFile -FilePath cmd -ArgumentList '/C echo Hello'" + + ## 'Hello' should be sent to standard output; 'error.txt' file should be created but empty. + $out | Should -BeExactly "Hello" + Test-Path -Path $errorFile | Should -BeTrue + (Get-Item $errorFile).Length | Should -Be 0 + } +} From 366625448efe12351e9bda85cc3f6f545abc927b Mon Sep 17 00:00:00 2001 From: PowerShell GitHub Bot Date: Tue, 10 Jun 2025 22:11:43 +0000 Subject: [PATCH 131/275] Update .NET SDK to latest version --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index f78f43e709b..a97818844d0 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "9.0.203", + "sdkImageVersion": "9.0.301", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index e4da652c648..2808b362fea 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.203" + "version": "9.0.301" } } From b8ff7f903984d1f66741a0903fc1915a30ca63c1 Mon Sep 17 00:00:00 2001 From: PowerShell GitHub Bot Date: Tue, 10 Jun 2025 22:21:41 +0000 Subject: [PATCH 132/275] Update package references --- ...oft.PowerShell.Commands.Diagnostics.csproj | 8 +- ...soft.PowerShell.Commands.Management.csproj | 4 +- ...crosoft.PowerShell.Commands.Utility.csproj | 6 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 100 +++++++++--------- .../Microsoft.WSMan.Management.csproj | 4 +- .../System.Management.Automation.csproj | 24 ++--- .../BenchmarkDotNet.Extensions.csproj | 2 +- .../ResultsComparer/ResultsComparer.csproj | 2 +- ...soft.PowerShell.NamedPipeConnection.csproj | 26 ++--- test/tools/TestService/TestService.csproj | 94 ++++++++-------- test/tools/WebListener/WebListener.csproj | 6 +- 12 files changed, 139 insertions(+), 139 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 4952c8f6ad4..af93c4c2bf4 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,11 +7,11 @@ - - - + + + - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 4fe6ed61803..d4c5da64bae 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 1cc347541a2..8fe2b24b05f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -13,7 +13,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + @@ -41,8 +41,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index e5f5b849645..b88db6c5e62 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 1d1fc2f1291..f1feac7c371 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -17,55 +17,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index db972fa45c8..087d4562069 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,11 +7,11 @@ - + - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index afc4c178cb3..030f6654237 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,25 +32,25 @@ - - - - - - + + + + + + - + - - - - + + + + - + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 6f6ef0087ab..b8568a0e373 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -13,7 +13,7 @@ - + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 164023a0f62..a7ec51fdcf7 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -13,7 +13,7 @@ - + diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index aa15f08cb56..a813503467c 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -17,21 +17,21 @@ - + - - - - - - - + + + + + + + - - - - - + + + + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 31a95e0b875..8215dfb01d1 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,56 +15,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index b609555c9ad..9f6fb2ce79a 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,9 +7,9 @@ - - + + - + From eea41ea52e0bbcd2339b0fe7704221dd4eb0d8f9 Mon Sep 17 00:00:00 2001 From: PowerShell GitHub Bot Date: Tue, 10 Jun 2025 22:23:19 +0000 Subject: [PATCH 133/275] Update cgmanifest --- tools/cgmanifest.json | 116 +++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 63 deletions(-) diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index e64601d8eaf..13f35eb8dd2 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -115,7 +115,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "8.0.15" + "Version": "8.0.17" } }, "DevelopmentDependency": false @@ -155,17 +155,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.4" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "Microsoft.Win32.Registry", - "Version": "5.0.0" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -175,7 +165,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -185,7 +175,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -205,7 +195,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -215,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -225,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -235,7 +225,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -245,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -255,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -265,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -275,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -285,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -295,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -305,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -315,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -325,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -335,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -345,7 +335,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.Data.SqlClient.sni", - "Version": "4.7.0" + "Version": "4.4.0" } }, "DevelopmentDependency": false @@ -355,7 +345,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -365,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -375,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -435,7 +425,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -455,7 +445,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -465,7 +455,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -475,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -485,7 +475,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -495,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -505,7 +495,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.SqlClient", - "Version": "4.8.6" + "Version": "4.9.0" } }, "DevelopmentDependency": false @@ -515,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.DiagnosticSource", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -525,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -535,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -545,7 +535,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -555,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -565,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -575,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -585,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -595,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -605,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -615,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -645,7 +635,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -675,7 +665,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -695,7 +685,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -705,7 +695,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -715,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -725,7 +715,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -795,7 +785,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -805,7 +795,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -815,7 +805,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -825,7 +815,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encoding.CodePages", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -835,7 +825,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encodings.Web", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -845,7 +835,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false @@ -865,7 +855,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.4" + "Version": "9.0.6" } }, "DevelopmentDependency": false From ff78f2582d3d107a0ea09b97f2b637848434d1a0 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Tue, 10 Jun 2025 19:09:24 -0400 Subject: [PATCH 134/275] Manually update SqlClient in TestService The version bump from 4.8.6 to 4.9.0 is required for Microsoft.Windows.Compatibility 9.0.6 --- test/tools/TestService/TestService.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 8215dfb01d1..cae146e8f5e 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -48,7 +48,7 @@ - + From 63cccc6ca24e07aa598930f02d51af780f57201c Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Mon, 16 Jun 2025 12:15:39 -0400 Subject: [PATCH 135/275] Update ThirdPartyNotices for v7.5.2 (#25658) --- ThirdPartyNotices.txt | 246 ++++++++++++------------------------------ 1 file changed, 66 insertions(+), 180 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index d48be300df3..c97524423aa 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -284,7 +284,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 8.0.15 - MIT +Microsoft.Extensions.ObjectPool 8.0.17 - MIT Copyright Jorn Zaefferer @@ -374,79 +374,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Win32.Registry 5.0.0 - MIT - - -(c) Microsoft Corporation -Copyright (c) Andrew Arnott -Copyright 2018 Daniel Lemire -Copyright (c) .NET Foundation -Copyright (c) 2011, Google Inc. -Copyright (c) 2020 Dan Shechter -(c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) Microsoft Corporation -Copyright (c) 2007 James Newton-King -Copyright (c) 2012-2014, Yann Collet -Copyright (c) 1991-2020 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -Copyright 2012 the V8 project authors -Copyright (c) 2011-2020 Microsoft Corp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2005-2007, Nick Galbreath -Copyright (c) 2015 The Chromium Authors -Copyright (c) 2018 Alexander Chermyanin -Copyright (c) The Internet Society 1997 -Portions (c) International Organization -Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2013-2017, Milosz Krajewski -Copyright (c) 2016-2017, Matthieu Darbois -Copyright (c) The Internet Society (2003) -Copyright (c) .NET Foundation Contributors -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler -Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors -Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com -Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To - -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), 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 "AS IS", 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. - - ---------------------------------------------------------- - ---------------------------------------------------------- - -Microsoft.Win32.Registry.AccessControl 9.0.4 - MIT +Microsoft.Win32.Registry.AccessControl 9.0.6 - MIT Copyright (c) 2021 @@ -536,7 +464,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Win32.SystemEvents 9.0.4 - MIT +Microsoft.Win32.SystemEvents 9.0.6 - MIT Copyright (c) 2021 @@ -626,7 +554,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Windows.Compatibility 9.0.4 - MIT +Microsoft.Windows.Compatibility 9.0.6 - MIT (c) Microsoft Corporation @@ -679,7 +607,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.android-arm.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.android-arm.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -769,7 +697,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-arm64.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.android-arm64.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -859,7 +787,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x64.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.android-x64.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -949,7 +877,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x86.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.android-x86.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -1039,7 +967,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.linux-arm.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -1129,7 +1057,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -1219,7 +1147,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -1309,7 +1237,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -1399,7 +1327,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -1489,7 +1417,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -1579,7 +1507,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -1669,7 +1597,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-x64.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.linux-x64.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -1759,7 +1687,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -1849,7 +1777,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -1939,29 +1867,21 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.Data.SqlClient.sni 4.7.0 - MIT +runtime.native.System.Data.SqlClient.sni 4.4.0 - MIT -(c) Microsoft Corporation. -Copyright (c) .NET Foundation. -Copyright (c) 2011, Google Inc. -(c) 1997-2005 Sean Eron Anderson. -Copyright (c) 2007 James Newton-King +(c) 2022 GitHub, Inc. +(c) Microsoft Corporation +(c) 1997-2005 Sean Eron Anderson Copyright (c) 1991-2017 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2005-2007, Nick Galbreath Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) .NET Foundation Contributors Copyright (c) .NET Foundation and Contributors Copyright (c) 2011 Novell, Inc (http://www.novell.com) Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers The MIT License (MIT) @@ -1992,7 +1912,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -2082,7 +2002,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -2172,7 +2092,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-x64.runtime.native.System.IO.Ports 9.0.4 - MIT +runtime.osx-x64.runtime.native.System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -2262,7 +2182,7 @@ SOFTWARE. --------------------------------------------------------- -System.CodeDom 9.0.4 - MIT +System.CodeDom 9.0.6 - MIT Copyright (c) 2021 @@ -2355,16 +2275,17 @@ SOFTWARE. System.Collections.Immutable 8.0.0 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -2379,12 +2300,10 @@ Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski @@ -2403,7 +2322,8 @@ Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -2438,7 +2358,7 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition 9.0.4 - MIT +System.ComponentModel.Composition 9.0.6 - MIT Copyright (c) 2021 @@ -2528,7 +2448,7 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition.Registration 9.0.4 - MIT +System.ComponentModel.Composition.Registration 9.0.6 - MIT Copyright (c) 2021 @@ -2618,7 +2538,7 @@ SOFTWARE. --------------------------------------------------------- -System.Configuration.ConfigurationManager 9.0.4 - MIT +System.Configuration.ConfigurationManager 9.0.6 - MIT Copyright (c) 2021 @@ -2708,7 +2628,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.Odbc 9.0.4 - MIT +System.Data.Odbc 9.0.6 - MIT Copyright (c) 2021 @@ -2798,7 +2718,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.OleDb 9.0.4 - MIT +System.Data.OleDb 9.0.6 - MIT Copyright (c) 2021 @@ -2888,60 +2808,26 @@ SOFTWARE. --------------------------------------------------------- -System.Data.SqlClient 4.8.6 - MIT +System.Data.SqlClient 4.9.0 - MIT (c) Microsoft Corporation -Copyright (c) .NET Foundation -Copyright (c) 2011, Google Inc. -(c) 1997-2005 Sean Eron Anderson -Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2017 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2005-2007, Nick Galbreath -Copyright (c) 2015 The Chromium Authors -Portions (c) International Organization -Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2016-2017, Matthieu Darbois -Copyright (c) .NET Foundation Contributors -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler -Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), 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: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 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 SOFTWARE IS PROVIDED "AS IS", 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. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", 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. --------------------------------------------------------- --------------------------------------------------------- -System.Diagnostics.DiagnosticSource 9.0.4 - MIT +System.Diagnostics.DiagnosticSource 9.0.6 - MIT Copyright (c) 2021 @@ -3031,7 +2917,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.EventLog 9.0.4 - MIT +System.Diagnostics.EventLog 9.0.6 - MIT Copyright (c) 2021 @@ -3121,7 +3007,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.PerformanceCounter 9.0.4 - MIT +System.Diagnostics.PerformanceCounter 9.0.6 - MIT Copyright (c) 2021 @@ -3211,7 +3097,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices 9.0.4 - MIT +System.DirectoryServices 9.0.6 - MIT Copyright (c) 2021 @@ -3301,7 +3187,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.AccountManagement 9.0.4 - MIT +System.DirectoryServices.AccountManagement 9.0.6 - MIT Copyright (c) 2021 @@ -3391,7 +3277,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.Protocols 9.0.4 - MIT +System.DirectoryServices.Protocols 9.0.6 - MIT Copyright (c) 2021 @@ -3481,7 +3367,7 @@ SOFTWARE. --------------------------------------------------------- -System.Drawing.Common 9.0.4 - MIT +System.Drawing.Common 9.0.6 - MIT (c) Microsoft Corporation @@ -3516,7 +3402,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Packaging 9.0.4 - MIT +System.IO.Packaging 9.0.6 - MIT Copyright (c) 2021 @@ -3606,7 +3492,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Ports 9.0.4 - MIT +System.IO.Ports 9.0.6 - MIT Copyright (c) 2021 @@ -3696,7 +3582,7 @@ SOFTWARE. --------------------------------------------------------- -System.Management 9.0.4 - MIT +System.Management 9.0.6 - MIT Copyright (c) 2021 @@ -3786,7 +3672,7 @@ SOFTWARE. --------------------------------------------------------- -System.Net.Http.WinHttpHandler 9.0.4 - MIT +System.Net.Http.WinHttpHandler 9.0.6 - MIT Copyright (c) 2021 @@ -3961,7 +3847,7 @@ SOFTWARE. --------------------------------------------------------- -System.Reflection.Context 9.0.4 - MIT +System.Reflection.Context 9.0.6 - MIT Copyright (c) 2021 @@ -4191,7 +4077,7 @@ SOFTWARE. --------------------------------------------------------- -System.Runtime.Caching 9.0.4 - MIT +System.Runtime.Caching 9.0.6 - MIT Copyright (c) 2021 @@ -4356,7 +4242,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Pkcs 9.0.4 - MIT +System.Security.Cryptography.Pkcs 9.0.6 - MIT Copyright (c) 2021 @@ -4446,7 +4332,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.ProtectedData 9.0.4 - MIT +System.Security.Cryptography.ProtectedData 9.0.6 - MIT Copyright (c) 2021 @@ -4536,7 +4422,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Xml 9.0.4 - MIT +System.Security.Cryptography.Xml 9.0.6 - MIT Copyright (c) 2021 @@ -4626,7 +4512,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Permissions 9.0.4 - MIT +System.Security.Permissions 9.0.6 - MIT Copyright (c) 2021 @@ -4965,7 +4851,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Syndication 9.0.4 - MIT +System.ServiceModel.Syndication 9.0.6 - MIT Copyright (c) 2021 @@ -5055,7 +4941,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceProcess.ServiceController 9.0.4 - MIT +System.ServiceProcess.ServiceController 9.0.6 - MIT Copyright (c) 2021 @@ -5145,7 +5031,7 @@ SOFTWARE. --------------------------------------------------------- -System.Speech 9.0.4 - MIT +System.Speech 9.0.6 - MIT Copyright (c) 2021 @@ -5235,7 +5121,7 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encoding.CodePages 9.0.4 - MIT +System.Text.Encoding.CodePages 9.0.6 - MIT Copyright (c) 2021 @@ -5325,7 +5211,7 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encodings.Web 9.0.4 - MIT +System.Text.Encodings.Web 9.0.6 - MIT Copyright (c) 2021 @@ -5415,7 +5301,7 @@ SOFTWARE. --------------------------------------------------------- -System.Threading.AccessControl 9.0.4 - MIT +System.Threading.AccessControl 9.0.6 - MIT Copyright (c) 2021 @@ -5541,7 +5427,7 @@ SOFTWARE. --------------------------------------------------------- -System.Windows.Extensions 9.0.4 - MIT +System.Windows.Extensions 9.0.6 - MIT Copyright (c) 2021 From 74af3bfef50d03b1bc41932b54faeff954ef4d52 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 16 Jun 2025 10:39:35 -0700 Subject: [PATCH 136/275] [release/v7.5] Publish `.msixbundle` package as a VPack (#25621) Co-authored-by: Dongbo Wang Co-authored-by: Travis Plunk --- .pipelines/MSIXBundle-vPack-Official.yml | 147 +++++++++++++++++++ .pipelines/PowerShell-Release-Official.yml | 5 +- .pipelines/templates/SetVersionVariables.yml | 6 +- assets/AppxManifest.xml | 1 + tools/packaging/packaging.psm1 | 18 ++- 5 files changed, 171 insertions(+), 6 deletions(-) create mode 100644 .pipelines/MSIXBundle-vPack-Official.yml diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml new file mode 100644 index 00000000000..f20e8a31114 --- /dev/null +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -0,0 +1,147 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time +- name: 'createVPack' + displayName: 'Create and Submit VPack' + type: boolean + default: true +- name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false +- name: 'ReleaseTagVar' + type: string + displayName: 'Release Tag Var:' + default: 'fromBranch' + +name: msixbundle_vPack_$(date:yyMM).$(date:dd)$(rev:rrr) + +variables: + CDP_DEFINITION_BUILD_COUNT: $[counter('', 0)] + system.debug: ${{ parameters.debug }} + BuildSolution: $(Build.SourcesDirectory)\dirs.proj + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + BuildConfiguration: Release + WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + Codeql.Enabled: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + +resources: + repositories: + - repository: templates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + + pipelines: + - pipeline: PSPackagesOfficial + source: 'PowerShell-Packages-Official' + trigger: + branches: + include: + - master + - releases/* + +extends: + template: v2/Microsoft.Official.yml@templates + parameters: + platform: + name: 'windows_undocked' # windows undocked + + cloudvault: + enabled: false + + globalSdl: + useCustomPolicy: true # for signing code + disableLegacyManifest: true + # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + sbom: + enabled: true + compiled: + enabled: false + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + enabled: false + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + asyncSDL: + enabled: false + tsaOptionsFile: .config/tsaoptions.json + + stages: + - stage: build + jobs: + - job: main + pool: + type: windows + + variables: + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_createvpack_enabled: ${{ parameters.createVPack }} + ob_createvpack_packagename: 'PowerShell.app' + ob_createvpack_owneralias: 'dongbow' + ob_createvpack_description: 'VPack for the PowerShell Application' + ob_createvpack_targetDestinationDirectory: '$(Destination)' + ob_createvpack_propsFile: false + ob_createvpack_provData: true + ob_createvpack_metadata: '$(Build.SourceVersion)' + ob_createvpack_versionAs: string + ob_createvpack_version: '$(version)' + ob_createvpack_verbose: true + + steps: + - template: .pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + UseJson: no + + - pwsh: | + Write-Verbose -Verbose 'PowerShell Version: $(version)' + if('$(version)' -match '-') { + throw "Don't release a preview build msixbundle package" + } + displayName: Stop any preview release + + - download: PSPackagesOfficial + artifact: 'drop_msixbundle_CreateMSIXBundle' + displayName: Download package + + - pwsh: | + $payloadDir = '$(Pipeline.Workspace)\PSPackagesOfficial\drop_msixbundle_CreateMSIXBundle' + Get-ChildItem $payloadDir -Recurse | Out-String -Width 150 + $vstsCommandString = "vso[task.setvariable variable=PayloadDir]$payloadDir" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: 'Capture Artifact Listing' + + - pwsh: | + $bundlePackage = Get-ChildItem '$(PayloadDir)\*.msixbundle' + Write-Verbose -Verbose ("MSIX bundle package: " + $bundlePackage.FullName -join ', ') + if ($bundlePackage.Count -ne 1) { + throw "Expected to find 1 MSIX bundle package, but found $($bundlePackage.Count)" + } + + if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { + $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop + } + + $targetPath = Join-Path '$(ob_outputDirectory)' 'Microsoft.PowerShell_8wekyb3d8bbwe.msixbundle' + Copy-Item -Verbose -Path $bundlePackage.FullName -Destination $targetPath + displayName: 'Stage msixbundle for vpack' + + - pwsh: | + Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose + $vpackFiles = Get-ChildItem -Path $(ob_outputDirectory)\* -Recurse + if($vpackFiles.Count -eq 0) { + throw "No files found in $(ob_outputDirectory)" + } + $vpackFiles | Out-String -Width 150 + displayName: Debug Output Directory and Version + condition: succeededOrFailed() diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 55c6ec1c486..c073b9e1223 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -368,10 +368,11 @@ extends: jobs: - template: /.pipelines/templates/approvalJob.yml@self parameters: - displayName: Start vPack Release pipeline + displayName: Start 2 vPack Release pipelines jobName: PublishVPack instructions: | - Kick off vPack release pipeline + 1. Kick off PowerShell-vPack-Official pipeline + 2. Kick off PowerShell-MSIXBundle-VPack pipeline # Need to verify if the Az PS / CLI team still uses this. Skippinng for this release. # - stage: ReleaseDeps diff --git a/.pipelines/templates/SetVersionVariables.yml b/.pipelines/templates/SetVersionVariables.yml index 9894f9d53f6..9f692373f6c 100644 --- a/.pipelines/templates/SetVersionVariables.yml +++ b/.pipelines/templates/SetVersionVariables.yml @@ -23,7 +23,7 @@ steps: } if(Test-Path -Path $path) { - Write-Verbose "reporoot detect at: ." -Verbose + Write-Verbose "reporoot detected at: ." -Verbose $repoRoot = '.' } else{ @@ -51,7 +51,7 @@ steps: $REPOROOT = $env:REPOROOT if (-not (Test-Path $REPOROOT/tools/releaseBuild/setReleaseTag.ps1)) { - if ((Test-Path "$REPOROOT/PowerShell/tools/releaseBuild/setReleaseTag.ps1")) { + if (Test-Path "$REPOROOT/PowerShell/tools/releaseBuild/setReleaseTag.ps1") { $REPOROOT = "$REPOROOT/PowerShell" } else { throw "Could not find setReleaseTag.ps1 in $REPOROOT/tools/releaseBuild or $REPOROOT/PowerShell/tools/releaseBuild" @@ -72,7 +72,7 @@ steps: ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - powershell: | - Get-ChildItem -Path env: + Get-ChildItem -Path Env: | Out-String -Width 150 displayName: Capture environment condition: succeededOrFailed() env: diff --git a/assets/AppxManifest.xml b/assets/AppxManifest.xml index c646bcdf94b..50a8c7af45d 100644 --- a/assets/AppxManifest.xml +++ b/assets/AppxManifest.xml @@ -48,4 +48,5 @@ + diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 43a8d5d8dd4..782a4ecadc8 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -3702,8 +3702,17 @@ function New-MSIXPackage $ProductVersion = Get-WindowsVersion -PackageName $packageName + # Any app that is submitted to the Store must have a PhoneIdentity in its appxmanifest. + # If you submit a package without this information to the Store, the Store will silently modify your package to include it. + # To find the PhoneProductId value, you need to run a package through the Store certification process, + # and use the PhoneProductId value from the Store certified package to update the manifest in your source code. + # This is the PhoneProductId for the "Microsoft.PowerShell" package. + $PhoneProductId = "5b3ae196-2df7-446e-8060-94b4ad878387" + $isPreview = Test-IsPreview -Version $ProductSemanticVersion if ($isPreview) { + # This is the PhoneProductId for the "Microsoft.PowerShellPreview" package. + $PhoneProductId = "67859fd2-b02a-45be-8fb5-62c569a3e8bf" Write-Verbose "Using Preview assets" -Verbose } @@ -3713,7 +3722,14 @@ function New-MSIXPackage $releasePublisher = 'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US' $appxManifest = Get-Content "$RepoRoot\assets\AppxManifest.xml" -Raw - $appxManifest = $appxManifest.Replace('$VERSION$', $ProductVersion).Replace('$ARCH$', $Architecture).Replace('$PRODUCTNAME$', $productName).Replace('$DISPLAYNAME$', $displayName).Replace('$PUBLISHER$', $releasePublisher) + $appxManifest = $appxManifest. + Replace('$VERSION$', $ProductVersion). + Replace('$ARCH$', $Architecture). + Replace('$PRODUCTNAME$', $productName). + Replace('$DISPLAYNAME$', $displayName). + Replace('$PUBLISHER$', $releasePublisher). + Replace('$PHONEPRODUCTID$', $PhoneProductId) + $xml = [xml]$appxManifest if ($isPreview) { Write-Verbose -Verbose "Adding pwsh-preview.exe alias" From d1a57af02c719f2f1695425f5124bbbf218dbf77 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 17 Jun 2025 09:46:11 -0700 Subject: [PATCH 137/275] [release/v7.5] Correct Capitalization Referencing Templates (#25673) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> --- .pipelines/templates/release-symbols.yml | 2 +- .pipelines/templates/release-upload-buildinfo.yml | 2 +- .pipelines/templates/release-validate-packagenames.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pipelines/templates/release-symbols.yml b/.pipelines/templates/release-symbols.yml index 6b728a75b02..68b8dd4324d 100644 --- a/.pipelines/templates/release-symbols.yml +++ b/.pipelines/templates/release-symbols.yml @@ -33,7 +33,7 @@ jobs: env: ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - - template: release-SetReleaseTagAndContainerName.yml + - template: release-SetReleaseTagandContainerName.yml - pwsh: | Get-ChildItem Env: diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index d35630168a0..1134e1cc016 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -38,7 +38,7 @@ jobs: env: ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - - template: release-SetReleaseTagAndContainerName.yml + - template: release-SetReleaseTagandContainerName.yml - pwsh: | Get-ChildItem Env: diff --git a/.pipelines/templates/release-validate-packagenames.yml b/.pipelines/templates/release-validate-packagenames.yml index 1eaf9c070ee..dbbd5c9f742 100644 --- a/.pipelines/templates/release-validate-packagenames.yml +++ b/.pipelines/templates/release-validate-packagenames.yml @@ -16,7 +16,7 @@ jobs: - checkout: self clean: true - - template: release-SetReleaseTagAndContainerName.yml + - template: release-SetReleaseTagandContainerName.yml - pwsh: | Get-ChildItem ENV: From ee140c433c5b0319c3522ca1263ba18045dfbd2f Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 24 Jun 2025 09:54:30 -0700 Subject: [PATCH 138/275] [release/v7.5] Update CHANGELOG for v7.5.2 (#25686) Co-authored-by: Patrick Meinecke --- CHANGELOG/7.5.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index 37aa3e27995..8cf3dba6282 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -1,5 +1,47 @@ # 7.5 Changelog +## [7.5.2] - 2025-06-24 + +### Engine Updates and Fixes + +- Move .NET method invocation logging to after the needed type conversion is done for method arguments (#25357) + +### General Cmdlet Updates and Fixes + +- Set standard handles explicitly when starting a process with `-NoNewWindow` (#25324) +- Make inherited protected internal instance members accessible in class scope. (#25547) (Thanks @mawosoft!) +- Remove the old fuzzy suggestion and fix the local script file name suggestion (#25330) +- Fix `PSMethodInvocationConstraints.GetHashCode` method (#25306) (Thanks @crazyjncsu!) + +### Build and Packaging Improvements + +
+ + + +

Update to .NET SDK 9.0.301

+ +
+ +
    +
  • Correct Capitalization Referencing Templates (#25673)
  • +
  • Publish .msixbundle package as a VPack (#25621)
  • +
  • Update ThirdPartyNotices for v7.5.2 (#25658)
  • +
  • Manually update SqlClient in TestService
  • +
  • Update cgmanifest
  • +
  • Update package references
  • +
  • Update .NET SDK to latest version
  • +
  • Change linux packaging tests to ubuntu latest (#25639)
  • +
  • Fix MSIX artifact upload, vPack template, changelog hashes, git tag command (#25633)
  • +
  • Move MSIXBundle to Packages and Release to GitHub (#25517)
  • +
  • Use new variables template for vPack (#25435)
  • +
+ +
+ +[7.5.2]: https://github.com/PowerShell/PowerShell/compare/v7.5.1...v7.5.2 + + ## [7.5.1] ### Engine Updates and Fixes From 411d5fee10110d9881a909804f9d4eb1a06052ea Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:20:39 -0700 Subject: [PATCH 139/275] [release/v7.5] Fix Conditional Parameter to Skip NuGet Publish (#25688) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> --- .pipelines/PowerShell-Release-Official.yml | 2 +- .pipelines/templates/release-githubNuget.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index c073b9e1223..bfc475785aa 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -18,7 +18,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: string default: 'NO' - name: SkipPublish - displayName: Skip Publishing to GitHub and Nuget + displayName: Skip Publishing to Nuget type: boolean default: false - name: SkipPSInfraInstallers diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index ba0db845bfd..5a053514d6b 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -191,11 +191,11 @@ jobs: Write-Verbose -Verbose "The .nupkgs below will be pushed:" Get-ChildItem "$(Pipeline.Workspace)/release" -recurse displayName: Download and capture nupkgs - condition: and(ne('${{ parameters.skipPublish }}', 'false'), succeeded()) + condition: and(ne('${{ parameters.skipPublish }}', 'true'), succeeded()) - task: NuGetCommand@2 displayName: 'NuGet push' - condition: and(ne('${{ parameters.skipPublish }}', 'false'), succeeded()) + condition: and(ne('${{ parameters.skipPublish }}', 'true'), succeeded()) inputs: command: push packagesToPush: '$(Pipeline.Workspace)/release/*.nupkg' From 0bc793fc1341a5930e2a0efd4a66c200a9f2a4ab Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 6 Aug 2025 14:25:19 -0700 Subject: [PATCH 140/275] [release/v7.5] Fix Out-GridView by replacing use of obsolete BinaryFormatter with custom implementation. (#25559) Co-authored-by: Matthias Wolf <78562192+mawosoft@users.noreply.github.com> Co-authored-by: Travis Plunk --- .../FilterRules/ComparableValueFilterRule.cs | 17 +++++++++ .../FilterRules/DoesNotEqualFilterRule.cs | 11 +++++- .../FilterRules/EqualsFilterRule.cs | 11 +++++- .../FilterCore/FilterRules/FilterRule.cs | 20 +++++++++- .../FilterRules/FilterRuleExtensions.cs | 28 +------------- .../FilterRules/IsBetweenFilterRule.cs | 16 +++++++- .../FilterRules/IsEmptyFilterRule.cs | 11 +++++- .../FilterRules/IsGreaterThanFilterRule.cs | 11 +++++- .../FilterRules/IsLessThanFilterRule.cs | 11 +++++- .../FilterRules/IsNotEmptyFilterRule.cs | 11 +++++- .../FilterRules/IsNotEmptyValidationRule.cs | 8 ++++ .../PropertiesTextContainsFilterRule.cs | 11 ++++++ .../PropertyValueSelectorFilterRule.cs | 11 ++++++ .../FilterRules/SelectorFilterRule.cs | 16 +++++++- .../SingleValueComparableValueFilterRule.cs | 13 ++++++- .../FilterRules/TextContainsFilterRule.cs | 11 +++++- .../TextDoesNotContainFilterRule.cs | 11 +++++- .../FilterRules/TextDoesNotEqualFilterRule.cs | 11 +++++- .../FilterRules/TextEndsWithFilterRule.cs | 11 +++++- .../FilterRules/TextEqualsFilterRule.cs | 11 +++++- .../FilterCore/FilterRules/TextFilterRule.cs | 13 ++++++- .../FilterRules/TextStartsWithFilterRule.cs | 11 +++++- .../FilterCore/IDeepCloneable.cs | 18 +++++++++ .../FilterCore/ValidatingSelectorValue.cs | 37 +++++++++++++++++++ .../FilterCore/ValidatingValue.cs | 23 ++++++++++++ .../FilterCore/ValidatingValueBase.cs | 26 ++++++++++++- .../DataErrorInfoValidationRule.cs | 5 ++- 27 files changed, 346 insertions(+), 48 deletions(-) create mode 100644 src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/IDeepCloneable.cs diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/ComparableValueFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/ComparableValueFilterRule.cs index e7ef648e3fe..dca6c08d535 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/ComparableValueFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/ComparableValueFilterRule.cs @@ -16,6 +16,23 @@ namespace Microsoft.Management.UI.Internal [Serializable] public abstract class ComparableValueFilterRule : FilterRule where T : IComparable { + /// + /// Initializes a new instance of the class. + /// + protected ComparableValueFilterRule() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + protected ComparableValueFilterRule(ComparableValueFilterRule source) + : base(source) + { + this.DefaultNullValueEvaluation = source.DefaultNullValueEvaluation; + } + #region Properties /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/DoesNotEqualFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/DoesNotEqualFilterRule.cs index ae209d0e60f..94451623c3a 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/DoesNotEqualFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/DoesNotEqualFilterRule.cs @@ -17,7 +17,7 @@ namespace Microsoft.Management.UI.Internal public class DoesNotEqualFilterRule : EqualsFilterRule where T : IComparable { /// - /// Initializes a new instance of the DoesNotEqualFilterRule class. + /// Initializes a new instance of the class. /// public DoesNotEqualFilterRule() { @@ -25,6 +25,15 @@ public DoesNotEqualFilterRule() this.DefaultNullValueEvaluation = true; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public DoesNotEqualFilterRule(DoesNotEqualFilterRule source) + : base(source) + { + } + /// /// Determines if item is not equal to Value. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/EqualsFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/EqualsFilterRule.cs index 7bafd53e411..eaf647f0030 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/EqualsFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/EqualsFilterRule.cs @@ -18,13 +18,22 @@ namespace Microsoft.Management.UI.Internal public class EqualsFilterRule : SingleValueComparableValueFilterRule where T : IComparable { /// - /// Initializes a new instance of the EqualsFilterRule class. + /// Initializes a new instance of the class. /// public EqualsFilterRule() { this.DisplayName = UICultureResources.FilterRule_Equals; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public EqualsFilterRule(EqualsFilterRule source) + : base(source) + { + } + /// /// Determines if item is equal to Value. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/FilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/FilterRule.cs index 800812cdba5..7f72f33eb2d 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/FilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/FilterRule.cs @@ -10,7 +10,7 @@ namespace Microsoft.Management.UI.Internal /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] [Serializable] - public abstract class FilterRule : IEvaluate + public abstract class FilterRule : IEvaluate, IDeepCloneable { /// /// Gets a value indicating whether the FilterRule can be @@ -34,12 +34,28 @@ public string DisplayName } /// - /// Initializes a new instance of the FilterRule class. + /// Initializes a new instance of the class. /// protected FilterRule() { } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + protected FilterRule(FilterRule source) + { + ArgumentNullException.ThrowIfNull(source); + this.DisplayName = source.DisplayName; + } + + /// + public object DeepClone() + { + return Activator.CreateInstance(this.GetType(), new object[] { this }); + } + /// /// Gets a value indicating whether the supplied item meets the /// criteria specified by this rule. diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/FilterRuleExtensions.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/FilterRuleExtensions.cs index bc8e0b02ca6..4a3f8dc2975 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/FilterRuleExtensions.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/FilterRuleExtensions.cs @@ -2,10 +2,6 @@ // Licensed under the MIT License. using System; -using System.Diagnostics; -using System.IO; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; namespace Microsoft.Management.UI.Internal { @@ -28,29 +24,7 @@ public static class FilterRuleExtensions public static FilterRule DeepCopy(this FilterRule rule) { ArgumentNullException.ThrowIfNull(rule); - -#pragma warning disable SYSLIB0050 - Debug.Assert(rule.GetType().IsSerializable, "rule is serializable"); -#pragma warning disable SYSLIB0011 - BinaryFormatter formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone)); -#pragma warning restore SYSLIB0011 - MemoryStream ms = new MemoryStream(); - - FilterRule copy = null; - try - { - formatter.Serialize(ms, rule); - - ms.Position = 0; - copy = (FilterRule)formatter.Deserialize(ms); -#pragma warning restore SYSLIB0050 - } - finally - { - ms.Close(); - } - - return copy; + return (FilterRule)rule.DeepClone(); } } } diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsBetweenFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsBetweenFilterRule.cs index cbe4a875dd0..d8c4a263c61 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsBetweenFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsBetweenFilterRule.cs @@ -56,7 +56,7 @@ public ValidatingValue EndValue #region Ctor /// - /// Initializes a new instance of the IsBetweenFilterRule class. + /// Initializes a new instance of the class. /// public IsBetweenFilterRule() { @@ -69,6 +69,20 @@ public IsBetweenFilterRule() this.EndValue.PropertyChanged += this.Value_PropertyChanged; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public IsBetweenFilterRule(IsBetweenFilterRule source) + : base(source) + { + this.StartValue = (ValidatingValue)source.StartValue.DeepClone(); + this.StartValue.PropertyChanged += this.Value_PropertyChanged; + + this.EndValue = (ValidatingValue)source.EndValue.DeepClone(); + this.EndValue.PropertyChanged += this.Value_PropertyChanged; + } + #endregion Ctor #region Public Methods diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsEmptyFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsEmptyFilterRule.cs index 5ad2ae1247e..a3add25eae5 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsEmptyFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsEmptyFilterRule.cs @@ -14,13 +14,22 @@ namespace Microsoft.Management.UI.Internal public class IsEmptyFilterRule : FilterRule { /// - /// Initializes a new instance of the IsEmptyFilterRule class. + /// Initializes a new instance of the class. /// public IsEmptyFilterRule() { this.DisplayName = UICultureResources.FilterRule_IsEmpty; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public IsEmptyFilterRule(IsEmptyFilterRule source) + : base(source) + { + } + /// /// Gets a values indicating whether the supplied item is empty. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsGreaterThanFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsGreaterThanFilterRule.cs index d098d2a9383..c6d9ef762b4 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsGreaterThanFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsGreaterThanFilterRule.cs @@ -18,13 +18,22 @@ namespace Microsoft.Management.UI.Internal public class IsGreaterThanFilterRule : SingleValueComparableValueFilterRule where T : IComparable { /// - /// Initializes a new instance of the IsGreaterThanFilterRule class. + /// Initializes a new instance of the class. /// public IsGreaterThanFilterRule() { this.DisplayName = UICultureResources.FilterRule_GreaterThanOrEqual; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public IsGreaterThanFilterRule(IsGreaterThanFilterRule source) + : base(source) + { + } + /// /// Determines if item is greater than Value. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsLessThanFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsLessThanFilterRule.cs index 8539d6edf0e..a90dcdc8a82 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsLessThanFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsLessThanFilterRule.cs @@ -18,13 +18,22 @@ namespace Microsoft.Management.UI.Internal public class IsLessThanFilterRule : SingleValueComparableValueFilterRule where T : IComparable { /// - /// Initializes a new instance of the IsLessThanFilterRule class. + /// Initializes a new instance of the class. /// public IsLessThanFilterRule() { this.DisplayName = UICultureResources.FilterRule_LessThanOrEqual; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public IsLessThanFilterRule(IsLessThanFilterRule source) + : base(source) + { + } + /// /// Determines if item is less than Value. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyFilterRule.cs index 68e501d1f68..450a1237a97 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyFilterRule.cs @@ -14,13 +14,22 @@ namespace Microsoft.Management.UI.Internal public class IsNotEmptyFilterRule : IsEmptyFilterRule { /// - /// Initializes a new instance of the IsNotEmptyFilterRule class. + /// Initializes a new instance of the class. /// public IsNotEmptyFilterRule() { this.DisplayName = UICultureResources.FilterRule_IsNotEmpty; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public IsNotEmptyFilterRule(IsNotEmptyFilterRule source) + : base(source) + { + } + /// /// Gets a values indicating whether the supplied item is not empty. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyValidationRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyValidationRule.cs index 31722bfe1f7..98534aca0ad 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyValidationRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyValidationRule.cs @@ -51,6 +51,14 @@ public override DataErrorInfoValidationResult Validate(object value, System.Glob } } + /// + public override object DeepClone() + { + // Instance is stateless. + // return this; + return new IsNotEmptyValidationRule(); + } + #endregion Public Methods internal static bool IsStringNotEmpty(string value) diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertiesTextContainsFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertiesTextContainsFilterRule.cs index 2a1cc576b39..54532335835 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertiesTextContainsFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertiesTextContainsFilterRule.cs @@ -29,6 +29,17 @@ public PropertiesTextContainsFilterRule() this.EvaluationResultInvalidated += this.PropertiesTextContainsFilterRule_EvaluationResultInvalidated; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public PropertiesTextContainsFilterRule(PropertiesTextContainsFilterRule source) + : base(source) + { + this.PropertyNames = new List(source.PropertyNames); + this.EvaluationResultInvalidated += this.PropertiesTextContainsFilterRule_EvaluationResultInvalidated; + } + /// /// Gets a collection of the names of properties to search in. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertyValueSelectorFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertyValueSelectorFilterRule.cs index 158ab4e0229..6699cb0e698 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertyValueSelectorFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertyValueSelectorFilterRule.cs @@ -82,6 +82,17 @@ public PropertyValueSelectorFilterRule(string propertyName, string propertyDispl this.AvailableRules.DisplayNameConverter = new FilterRuleToDisplayNameConverter(); } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public PropertyValueSelectorFilterRule(PropertyValueSelectorFilterRule source) + : base(source) + { + this.PropertyName = source.PropertyName; + this.AvailableRules.DisplayNameConverter = new FilterRuleToDisplayNameConverter(); + } + #endregion Ctor #region Public Methods diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SelectorFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SelectorFilterRule.cs index da4a62b6f66..d7451bbd21f 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SelectorFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SelectorFilterRule.cs @@ -40,7 +40,7 @@ public ValidatingSelectorValue AvailableRules #region Ctor /// - /// Creates a new SelectorFilterRule instance. + /// Initializes a new instance of the class. /// public SelectorFilterRule() { @@ -48,6 +48,18 @@ public SelectorFilterRule() this.AvailableRules.SelectedValueChanged += this.AvailableRules_SelectedValueChanged; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public SelectorFilterRule(SelectorFilterRule source) + : base(source) + { + this.AvailableRules = (ValidatingSelectorValue)source.AvailableRules.DeepClone(); + this.AvailableRules.SelectedValueChanged += this.AvailableRules_SelectedValueChanged; + this.AvailableRules.SelectedValue.EvaluationResultInvalidated += this.SelectedValue_EvaluationResultInvalidated; + } + #endregion Ctor #region Public Methods @@ -86,8 +98,8 @@ protected void OnSelectedValueChanged(FilterRule oldValue, FilterRule newValue) FilterRuleCustomizationFactory.FactoryInstance.TransferValues(oldValue, newValue); FilterRuleCustomizationFactory.FactoryInstance.ClearValues(oldValue); - newValue.EvaluationResultInvalidated += this.SelectedValue_EvaluationResultInvalidated; oldValue.EvaluationResultInvalidated -= this.SelectedValue_EvaluationResultInvalidated; + newValue.EvaluationResultInvalidated += this.SelectedValue_EvaluationResultInvalidated; this.NotifyEvaluationResultInvalidated(); } diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SingleValueComparableValueFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SingleValueComparableValueFilterRule.cs index 9486a126820..a34288a6530 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SingleValueComparableValueFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SingleValueComparableValueFilterRule.cs @@ -44,7 +44,7 @@ public override bool IsValid #region Ctor /// - /// Initializes a new instance of the SingleValueComparableValueFilterRule class. + /// Initializes a new instance of the class. /// protected SingleValueComparableValueFilterRule() { @@ -52,6 +52,17 @@ protected SingleValueComparableValueFilterRule() this.Value.PropertyChanged += this.Value_PropertyChanged; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + protected SingleValueComparableValueFilterRule(SingleValueComparableValueFilterRule source) + : base(source) + { + this.Value = (ValidatingValue)source.Value.DeepClone(); + this.Value.PropertyChanged += this.Value_PropertyChanged; + } + #endregion Ctor private void Value_PropertyChanged(object sender, PropertyChangedEventArgs e) diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextContainsFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextContainsFilterRule.cs index fe581ca2031..acd52555498 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextContainsFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextContainsFilterRule.cs @@ -18,13 +18,22 @@ public class TextContainsFilterRule : TextFilterRule private static readonly string TextContainsWordsRegexPattern = WordBoundaryRegexPattern + TextContainsCharactersRegexPattern + WordBoundaryRegexPattern; /// - /// Initializes a new instance of the TextContainsFilterRule class. + /// Initializes a new instance of the class. /// public TextContainsFilterRule() { this.DisplayName = UICultureResources.FilterRule_Contains; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public TextContainsFilterRule(TextContainsFilterRule source) + : base(source) + { + } + /// /// Determines if Value is contained within data. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotContainFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotContainFilterRule.cs index 29bec9b4bbf..f85ca1bd125 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotContainFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotContainFilterRule.cs @@ -14,7 +14,7 @@ namespace Microsoft.Management.UI.Internal public class TextDoesNotContainFilterRule : TextContainsFilterRule { /// - /// Initializes a new instance of the TextDoesNotContainFilterRule class. + /// Initializes a new instance of the class. /// public TextDoesNotContainFilterRule() { @@ -22,6 +22,15 @@ public TextDoesNotContainFilterRule() this.DefaultNullValueEvaluation = true; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public TextDoesNotContainFilterRule(TextDoesNotContainFilterRule source) + : base(source) + { + } + /// /// Determines if Value is not contained within data. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotEqualFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotEqualFilterRule.cs index 4e72fe16e67..0c7bb96532c 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotEqualFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotEqualFilterRule.cs @@ -14,7 +14,7 @@ namespace Microsoft.Management.UI.Internal public class TextDoesNotEqualFilterRule : TextEqualsFilterRule { /// - /// Initializes a new instance of the TextDoesNotEqualFilterRule class. + /// Initializes a new instance of the class. /// public TextDoesNotEqualFilterRule() { @@ -22,6 +22,15 @@ public TextDoesNotEqualFilterRule() this.DefaultNullValueEvaluation = true; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public TextDoesNotEqualFilterRule(TextDoesNotEqualFilterRule source) + : base(source) + { + } + /// /// Determines if data is not equal to Value. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEndsWithFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEndsWithFilterRule.cs index baca67801bf..2d4febe058d 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEndsWithFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEndsWithFilterRule.cs @@ -18,13 +18,22 @@ public class TextEndsWithFilterRule : TextFilterRule private static readonly string TextEndsWithWordsRegexPattern = WordBoundaryRegexPattern + TextEndsWithCharactersRegexPattern; /// - /// Initializes a new instance of the TextEndsWithFilterRule class. + /// Initializes a new instance of the class. /// public TextEndsWithFilterRule() { this.DisplayName = UICultureResources.FilterRule_TextEndsWith; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public TextEndsWithFilterRule(TextEndsWithFilterRule source) + : base(source) + { + } + /// /// Determines if data ends with Value. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEqualsFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEqualsFilterRule.cs index e49dd9b4a0d..a6e74dca622 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEqualsFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEqualsFilterRule.cs @@ -17,13 +17,22 @@ public class TextEqualsFilterRule : TextFilterRule private static readonly string TextEqualsCharactersRegexPattern = "^{0}$"; /// - /// Initializes a new instance of the TextEqualsFilterRule class. + /// Initializes a new instance of the class. /// public TextEqualsFilterRule() { this.DisplayName = UICultureResources.FilterRule_Equals; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public TextEqualsFilterRule(TextEqualsFilterRule source) + : base(source) + { + } + /// /// Determines if data is equal to Value. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextFilterRule.cs index 0dc75cf24e4..c4cd5dba9f7 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextFilterRule.cs @@ -62,7 +62,7 @@ public bool CultureInvariant } /// - /// Initializes a new instance of the TextFilterRule class. + /// Initializes a new instance of the class. /// protected TextFilterRule() { @@ -70,6 +70,17 @@ protected TextFilterRule() this.CultureInvariant = false; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + protected TextFilterRule(TextFilterRule source) + : base(source) + { + this.IgnoreCase = source.IgnoreCase; + this.CultureInvariant = source.CultureInvariant; + } + /// /// Gets the current value and determines whether it should be evaluated as an exact match. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextStartsWithFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextStartsWithFilterRule.cs index e97deb0fd46..3b39d0f5660 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextStartsWithFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextStartsWithFilterRule.cs @@ -18,13 +18,22 @@ public class TextStartsWithFilterRule : TextFilterRule private static readonly string TextStartsWithWordsRegexPattern = TextStartsWithCharactersRegexPattern + WordBoundaryRegexPattern; /// - /// Initializes a new instance of the TextStartsWithFilterRule class. + /// Initializes a new instance of the class. /// public TextStartsWithFilterRule() { this.DisplayName = UICultureResources.FilterRule_TextStartsWith; } + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public TextStartsWithFilterRule(TextStartsWithFilterRule source) + : base(source) + { + } + /// /// Determines if data starts with Value. /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/IDeepCloneable.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/IDeepCloneable.cs new file mode 100644 index 00000000000..3090f93a95c --- /dev/null +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/IDeepCloneable.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Management.UI.Internal +{ + /// + /// Defines a generalized method for creating a deep copy of an instance. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] + public interface IDeepCloneable + { + /// + /// Creates a deep copy of the current instance. + /// + /// A new object that is a deep copy of the current instance. + object DeepClone(); + } +} diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingSelectorValue.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingSelectorValue.cs index 30b2fe8fac1..ff981a74751 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingSelectorValue.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingSelectorValue.cs @@ -19,6 +19,37 @@ namespace Microsoft.Management.UI.Internal [Serializable] public class ValidatingSelectorValue : ValidatingValueBase { + /// + /// Initializes a new instance of the class. + /// + public ValidatingSelectorValue() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public ValidatingSelectorValue(ValidatingSelectorValue source) + : base(source) + { + availableValues.EnsureCapacity(source.availableValues.Count); + if (typeof(IDeepCloneable).IsAssignableFrom(typeof(T))) + { + foreach (var value in source.availableValues) + { + availableValues.Add((T)((IDeepCloneable)value).DeepClone()); + } + } + else + { + availableValues.AddRange(source.availableValues); + } + + selectedIndex = source.selectedIndex; + displayNameConverter = source.displayNameConverter; + } + #region Properties #region Consts @@ -150,6 +181,12 @@ public IValueConverter DisplayNameConverter #region Public Methods + /// + public override object DeepClone() + { + return new ValidatingSelectorValue(this); + } + #region Validate /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValue.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValue.cs index fe21d2fee37..eee8ebc6e4a 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValue.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValue.cs @@ -18,6 +18,23 @@ namespace Microsoft.Management.UI.Internal [Serializable] public class ValidatingValue : ValidatingValueBase { + /// + /// Initializes a new instance of the class. + /// + public ValidatingValue() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + public ValidatingValue(ValidatingValue source) + : base(source) + { + value = source.Value is IDeepCloneable deepClone ? deepClone.DeepClone() : source.Value; + } + #region Properties #region Value @@ -50,6 +67,12 @@ public object Value #region Public Methods + /// + public override object DeepClone() + { + return new ValidatingValue(this); + } + /// /// Gets the raw value cast/transformed into /// type T. diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValueBase.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValueBase.cs index d1c349dc32c..6b4c2daa10d 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValueBase.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValueBase.cs @@ -16,8 +16,29 @@ namespace Microsoft.Management.UI.Internal /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] [Serializable] - public abstract class ValidatingValueBase : IDataErrorInfo, INotifyPropertyChanged + public abstract class ValidatingValueBase : IDataErrorInfo, INotifyPropertyChanged, IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + protected ValidatingValueBase() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The source to initialize from. + protected ValidatingValueBase(ValidatingValueBase source) + { + ArgumentNullException.ThrowIfNull(source); + validationRules.EnsureCapacity(source.validationRules.Count); + foreach (var rule in source.validationRules) + { + validationRules.Add((DataErrorInfoValidationRule)rule.DeepClone()); + } + } + #region Properties #region ValidationRules @@ -129,6 +150,9 @@ public string Error #region Public Methods + /// + public abstract object DeepClone(); + #region AddValidationRule /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidationRules/DataErrorInfoValidationRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidationRules/DataErrorInfoValidationRule.cs index 652592aec04..78b54a9c045 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidationRules/DataErrorInfoValidationRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidationRules/DataErrorInfoValidationRule.cs @@ -10,7 +10,7 @@ namespace Microsoft.Management.UI.Internal /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] [Serializable] - public abstract class DataErrorInfoValidationRule + public abstract class DataErrorInfoValidationRule : IDeepCloneable { /// /// When overridden in a derived class, performs validation checks on a value. @@ -25,5 +25,8 @@ public abstract class DataErrorInfoValidationRule /// A DataErrorInfoValidationResult object. /// public abstract DataErrorInfoValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo); + + /// + public abstract object DeepClone(); } } From b69a4798068fe64bd2aac654b07c41f2999fca50 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 29 Aug 2025 16:47:05 -0700 Subject: [PATCH 141/275] [release/v7.5] Fix updatable help test for new content (#25944) Co-authored-by: Aditya Patwardhan --- .../engine/Help/UpdatableHelpSystem.Tests.ps1 | 6 +++--- ...3e-98dc-74d7b4d63d59_en-US_helpcontent.cab | Bin 202345 -> 198346 bytes ...3e-98dc-74d7b4d63d59_en-US_helpcontent.zip | Bin 203864 -> 198989 bytes 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 index 439dc3be989..d4cbb420066 100644 --- a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 @@ -47,7 +47,7 @@ else } # default values for system modules -[string] $myUICulture = 'en-US' +[string] $myUICulture = 'en-US' [string] $HelpInstallationPath = Join-Path $PSHOME $myUICulture [string] $HelpInstallationPathHome = Join-Path $userHelpRoot $myUICulture @@ -118,7 +118,7 @@ else } "Microsoft.PowerShell.Utility" = @{ - HelpFiles = "Microsoft.PowerShell.Commands.Utility.dll-Help.xml", "Microsoft.PowerShell.Utility-help.xml" + HelpFiles = "Microsoft.PowerShell.Commands.Utility.dll-Help.xml" HelpInfoFiles = "Microsoft.PowerShell.Utility_1da87e53-152b-403e-98dc-74d7b4d63d59_HelpInfo.xml" CompressedFiles = "Microsoft.PowerShell.Utility_1da87e53-152b-403e-98dc-74d7b4d63d59_en-US_helpcontent$extension" HelpInstallationPath = $HelpInstallationPath @@ -216,7 +216,7 @@ function RunUpdateHelpTests # Delete the whole help directory Remove-Item ($moduleHelpPath) -Recurse - + [hashtable] $UICultureParam = $(if ((Get-UICulture).Name -ne $myUICulture) { @{ UICulture = $myUICulture } } else { @{} }) [hashtable] $sourcePathParam = $(if ($useSourcePath) { @{ SourcePath = Join-Path $PSScriptRoot assets } } else { @{} }) Update-Help -Module:$moduleName -Force @UICultureParam @sourcePathParam -Scope:$updateScope diff --git a/test/powershell/engine/Help/assets/Microsoft.PowerShell.Utility_1da87e53-152b-403e-98dc-74d7b4d63d59_en-US_helpcontent.cab b/test/powershell/engine/Help/assets/Microsoft.PowerShell.Utility_1da87e53-152b-403e-98dc-74d7b4d63d59_en-US_helpcontent.cab index 949471140cebe33bf9c372e4ee2b261f131d81f1..ec0d3294f798823316d9c9d11643763c0b29a5c9 100644 GIT binary patch delta 923 zcmV;M17!T^tPIMH3@J@hLq-4q007Dc0{{R3001li00000000940RRC200000003_Q z0029YDMo>%g{1+7r2@630|x_tt)_r-OamhpLrd*l!EW0y480fVKL|by>*jR`(35v4 zd|GqqVI5EeK@P5KYzERKh?V8ij~_`%wB#s~oi*DK;ymcD zVT49~#aQku*CQ)&+Z%c{!ktj4uh!yS2x?BK2fgkKXYET& zH|$Iv^KbX#`>&Y@QagHoXUJkFKarBaU3 zW8n=uNmeqdy=-uJJK$5RM_WyVEg&@lde}y~ya@eUglMDKbwN{q4>H|%9_@RsxO&OT zG2%1UAW)T z*sg&PpM_OeVr27wTI8r{)zO-^SLSv0Ve0b~+z6{H18i7?miK6=QQ})Qh@+|JYk2vq z2ZvSu0Mi)O+mh&RR6Dp~t=D}AWHVw^q5L-%FWlm*5JO^-=@2_2w;&u%x!<(P-NkZR z@AxpqK16+qPcH58g51!ER^#tWCkAY^7whPt(jYoc`5MxHTY*KslbM)+fQV_XegTD* zgKiVkyP3EvU^^O(D5eiH@vvzSGJ`*E;osGKCElBD3qvQ9UCjnAuaEt$C`eDGf#-We)^-_Mj0?ls`7?%HF*Jft{04sFw_N}L delta 4946 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 diff --git a/test/powershell/engine/Help/assets/Microsoft.PowerShell.Utility_1da87e53-152b-403e-98dc-74d7b4d63d59_en-US_helpcontent.zip b/test/powershell/engine/Help/assets/Microsoft.PowerShell.Utility_1da87e53-152b-403e-98dc-74d7b4d63d59_en-US_helpcontent.zip index 47643e90de6000705f6ecb69f4a032253a19e6f9..480f920114fcee4f8339fe5d781f50f1d418b152 100644 GIT binary patch delta 41 rcmcbygXiodo`x327N#xCH#w$Hlx9v4VP#_g0!AQA0Mgevn1Lh!45SG( delta 4952 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 From add10d83e520326b210f6eb1fdb84446b7dfa106 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 2 Sep 2025 14:10:17 -0700 Subject: [PATCH 142/275] [release/v7.5] Update branch for release (#25942) Co-authored-by: Travis Plunk --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 8 +- ...soft.PowerShell.Commands.Management.csproj | 4 +- ...crosoft.PowerShell.Commands.Utility.csproj | 6 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 98 ++++++++--------- .../Microsoft.WSMan.Management.csproj | 4 +- .../System.Management.Automation.csproj | 24 ++--- .../BenchmarkDotNet.Extensions.csproj | 3 +- .../ResultsComparer/ResultsComparer.csproj | 3 +- ...soft.PowerShell.NamedPipeConnection.csproj | 26 ++--- test/tools/TestService/TestService.csproj | 94 ++++++++-------- test/tools/WebListener/WebListener.csproj | 6 +- tools/cgmanifest.json | 102 +++++++++--------- 15 files changed, 193 insertions(+), 191 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index a97818844d0..eb802bfec36 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "9.0.301", + "sdkImageVersion": "9.0.304", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 2808b362fea..4c6e2601f69 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.301" + "version": "9.0.304" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index af93c4c2bf4..0b8a4c35cfc 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,11 +7,11 @@ - - - + + + - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index d4c5da64bae..d9f8e52e762 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 8fe2b24b05f..3e270da4164 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -13,7 +13,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + @@ -41,8 +41,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index b88db6c5e62..a02a0637693 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index f1feac7c371..e951707c28b 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -17,55 +17,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 087d4562069..c820e3f235b 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,11 +7,11 @@ - + - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 030f6654237..f3b62eafb49 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,25 +32,25 @@ - - - - - - + + + + + + - + - - - - + + + + - + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index b8568a0e373..9b5fb753394 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -13,10 +13,11 @@ - + + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index a7ec51fdcf7..3eacb22eb51 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -13,11 +13,12 @@ - + + diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index a813503467c..7fa3f53c83d 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -17,21 +17,21 @@ - + - - - - - - - + + + + + + + - - - - - + + + + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index cae146e8f5e..5508aa6cd9b 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,56 +15,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 9f6fb2ce79a..c65c90a3ff7 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,9 +7,9 @@ - - + + - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index 13f35eb8dd2..9b00c6ac230 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -115,7 +115,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "8.0.17" + "Version": "8.0.19" } }, "DevelopmentDependency": false @@ -155,7 +155,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -165,7 +165,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -175,7 +175,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -195,7 +195,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -205,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -215,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -225,7 +225,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -235,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -245,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -255,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -265,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -275,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -285,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -295,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -305,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -315,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -325,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -345,7 +345,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -355,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -365,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -425,7 +425,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -445,7 +445,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -455,7 +455,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -465,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -475,7 +475,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -485,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -505,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.DiagnosticSource", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -515,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -525,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -535,7 +535,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -545,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -555,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -565,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -575,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -585,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -595,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -605,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -635,7 +635,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -665,7 +665,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -685,7 +685,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -695,7 +695,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -705,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -715,7 +715,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -785,7 +785,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -795,7 +795,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -805,7 +805,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -815,7 +815,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encoding.CodePages", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -825,7 +825,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encodings.Web", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -835,7 +835,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false @@ -855,7 +855,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.6" + "Version": "9.0.8" } }, "DevelopmentDependency": false From 18fa315361602d5a97a13b919a9c70bdd721366f Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 2 Sep 2025 14:31:44 -0700 Subject: [PATCH 143/275] [release/v7.5] Fix typo in CHANGELOG for script filename suggestion (#25963) Co-authored-by: Travis Plunk --- CHANGELOG/7.5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index 8cf3dba6282..d2071727790 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -10,7 +10,7 @@ - Set standard handles explicitly when starting a process with `-NoNewWindow` (#25324) - Make inherited protected internal instance members accessible in class scope. (#25547) (Thanks @mawosoft!) -- Remove the old fuzzy suggestion and fix the local script file name suggestion (#25330) +- Remove the old fuzzy suggestion and fix the local script filename suggestion (#25330) - Fix `PSMethodInvocationConstraints.GetHashCode` method (#25306) (Thanks @crazyjncsu!) ### Build and Packaging Improvements From 964a77b46f52c6b35308bbee83db7f878a816fec Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 2 Sep 2025 14:51:58 -0700 Subject: [PATCH 144/275] [release/v7.5] Remove AsyncSDL from Pipelines Toggle Official/NonOfficial Runs (#25964) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Travis Plunk --- .pipelines/MSIXBundle-vPack-Official.yml | 3 +- ...werShell-Coordinated_Packages-Official.yml | 35 +++++++++++-------- .pipelines/PowerShell-Packages-Official.yml | 31 ++++++++-------- .../PowerShell-Release-Official-Azure.yml | 13 ++++--- .pipelines/PowerShell-Release-Official.yml | 19 +++++++--- .pipelines/PowerShell-vPack-Official.yml | 3 +- 6 files changed, 62 insertions(+), 42 deletions(-) diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index f20e8a31114..ef96f63f045 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -68,11 +68,10 @@ extends: suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json binskim: enabled: false + exactToolVersion: 4.4.2 # APIScan requires a non-Ready-To-Run build apiscan: enabled: false - asyncSDL: - enabled: false tsaOptionsFile: .config/tsaoptions.json stages: diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 11215302e46..8de89b0c508 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -26,6 +26,10 @@ parameters: displayName: Enable MSBuild Binary Logs type: boolean default: false + - name: OfficialBuild + type: boolean + default: false + resources: repositories: @@ -74,9 +78,17 @@ variables: - group: mscodehub-feed-read-akv - name: ENABLE_MSBUILD_BINLOGS value: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} + # Fix for BinSkim ICU package error in Linux containers + - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT + value: true + # Disable BinSkim at job level to override NonOfficial template defaults + - name: ob_sdl_binskim_enabled + value: false extends: - template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates + template: ${{ variables.templateFile }} parameters: customTags: 'ES365AIMigrationTooling' featureFlags: @@ -84,6 +96,7 @@ extends: Network: KS3 WindowsHostVersion: Network: KS3 + incrementalSDLBinaryAnalysis: true globalSdl: disableLegacyManifest: true # disabled Armorty as we dont have any ARM templates to scan. It fails on some sample ARM templates. @@ -103,19 +116,13 @@ extends: cg: enabled: true ignoreDirectories: '.devcontainer,demos,docker,docs,src,test,tools/packaging' - asyncSdl: - enabled: true - forStages: [prep, macos, linux, windows, SignFiles, test_and_release_artifacts] - credscan: - enabled: true - scanFolder: $(Build.SourcesDirectory) - suppressionsFile: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - binskim: - enabled: false - # APIScan requires a non-Ready-To-Run build - apiscan: - enabled: false - tsaOptionsFile: .config\tsaoptions.json + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config\tsaoptions.json stages: - stage: prep diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 487e8cb9c6a..f0d428bf1d6 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -24,7 +24,10 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Signing type: string default: 'NO' - + - name: OfficialBuild + type: boolean + default: false + name: pkgs-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) variables: @@ -61,6 +64,9 @@ variables: - name: branchCounter value: $[counter(variables['branchCounterKey'], 1)] - group: MSIXSigningProfile + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} + resources: pipelines: @@ -79,7 +85,7 @@ resources: ref: refs/heads/main extends: - template: v2/OneBranch.Official.CrossPlat.yml@templates + template: ${{ variables.templateFile }} parameters: cloudvault: enabled: false @@ -88,6 +94,7 @@ extends: Version: 2022 Network: KS3 linuxEsrpSigning: true + incrementalSDLBinaryAnalysis: true globalSdl: disableLegacyManifest: true # disabled Armorty as we dont have any ARM templates to scan. It fails on some sample ARM templates. @@ -104,19 +111,13 @@ extends: cg: enabled: true ignoreDirectories: '.devcontainer,demos,docker,docs,src,test,tools/packaging' - asyncSdl: - enabled: true - forStages: ['build'] - credscan: - enabled: true - scanFolder: $(Build.SourcesDirectory) - suppressionsFile: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - binskim: - enabled: false - # APIScan requires a non-Ready-To-Run build - apiscan: - enabled: false - tsaOptionsFile: .config\tsaoptions.json + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config\tsaoptions.json stages: - stage: prep jobs: diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index 2d644c7a5dd..8e144f1ee55 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -13,6 +13,9 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Signing type: string default: 'NO' + - name: OfficialBuild + type: boolean + default: false name: ev2-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) @@ -46,6 +49,9 @@ variables: - name: LinuxContainerImage value: mcr.microsoft.com/onebranch/cbl-mariner/build:2.0 - group: PoolNames + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} + resources: repositories: @@ -67,13 +73,14 @@ resources: - releases/* extends: - template: v2/OneBranch.Official.CrossPlat.yml@templates + template: ${{ variables.templateFile }} parameters: featureFlags: WindowsHostVersion: Version: 2022 Network: Netlock linuxEsrpSigning: true + incrementalSDLBinaryAnalysis: true cloudvault: enabled: false globalSdl: @@ -81,9 +88,6 @@ extends: # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. armory: enabled: false - asyncSdl: - enabled: true - tsaOptionsFile: .config/tsaoptions.json tsa: enabled: true credscan: @@ -92,6 +96,7 @@ extends: suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json binskim: break: false # always break the build on binskim issues in addition to TSA upload + exactToolVersion: 4.4.2 policheck: break: true # always break the build on policheck issues. You can disable it by setting to 'false' tsaOptionsFile: .config\tsaoptions.json diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index bfc475785aa..9d543eae3a9 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -25,6 +25,9 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Copying Archives and Installers to PSInfrastructure Public Location type: boolean default: false + - name: OfficialBuild + type: boolean + default: false name: release-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) @@ -58,6 +61,13 @@ variables: - name: ReleaseTagVar value: ${{ parameters.ReleaseTagVar }} - group: PoolNames + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} + - name: releaseEnvironment + value: ${{ iif ( parameters.OfficialBuild, 'Production', 'Test' ) }} + # Fix for BinSkim ICU package error in Linux containers + - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT + value: true resources: repositories: @@ -83,7 +93,7 @@ resources: - releases/* extends: - template: v2/OneBranch.Official.CrossPlat.yml@templates + template: ${{ variables.templateFile }} parameters: release: category: NonAzure @@ -91,6 +101,7 @@ extends: WindowsHostVersion: Version: 2022 Network: KS3 + incrementalSDLBinaryAnalysis: true cloudvault: enabled: false globalSdl: @@ -98,9 +109,6 @@ extends: # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. armory: enabled: false - asyncSdl: - enabled: true - tsaOptionsFile: .config/tsaoptions.json tsa: enabled: true credscan: @@ -109,6 +117,7 @@ extends: suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json binskim: break: false # always break the build on binskim issues in addition to TSA upload + exactToolVersion: 4.4.2 policheck: break: true # always break the build on policheck issues. You can disable it by setting to 'false' # suppression: @@ -279,7 +288,7 @@ extends: - setReleaseTagAndChangelog - UpdateChangeLog variables: - ob_release_environment: Production + ob_release_environment: ${{ parameters.releaseEnvironment }} jobs: - template: /.pipelines/templates/release-githubNuget.yml@self parameters: diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 9a9aceed387..05a8fefbb0f 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -93,11 +93,10 @@ extends: suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json binskim: enabled: false + exactToolVersion: 4.4.2 # APIScan requires a non-Ready-To-Run build apiscan: enabled: false - asyncSDL: - enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - stage: main From 8fb0da460ddfe48fb43a1463441cd2d59b53943f Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 2 Sep 2025 16:45:51 -0700 Subject: [PATCH 145/275] [release/v7.5] Make the interface `IDeepCloneable` internal (#25830) Co-authored-by: Dongbo Wang Co-authored-by: Travis Plunk --- .../ManagementList/FilterCore/IDeepCloneable.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/IDeepCloneable.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/IDeepCloneable.cs index 3090f93a95c..841a2424b51 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/IDeepCloneable.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/IDeepCloneable.cs @@ -6,8 +6,7 @@ namespace Microsoft.Management.UI.Internal /// /// Defines a generalized method for creating a deep copy of an instance. /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - public interface IDeepCloneable + internal interface IDeepCloneable { /// /// Creates a deep copy of the current instance. From d03f8071174c0c0114113fe4b8f14e411e706ec3 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 2 Sep 2025 17:12:48 -0700 Subject: [PATCH 146/275] [release/v7.5] Remove `OnDeserialized` and `Serializable` attributes from `Microsoft.Management.UI.Internal` project (#25831) Co-authored-by: Dongbo Wang Co-authored-by: Travis Plunk --- .../FilterCore/FilterRules/ComparableValueFilterRule.cs | 1 - .../FilterCore/FilterRules/DoesNotEqualFilterRule.cs | 1 - .../FilterCore/FilterRules/EqualsFilterRule.cs | 1 - .../ManagementList/FilterCore/FilterRules/FilterRule.cs | 2 -- .../FilterCore/FilterRules/IsBetweenFilterRule.cs | 8 -------- .../FilterCore/FilterRules/IsEmptyFilterRule.cs | 1 - .../FilterCore/FilterRules/IsGreaterThanFilterRule.cs | 1 - .../FilterCore/FilterRules/IsLessThanFilterRule.cs | 1 - .../FilterCore/FilterRules/IsNotEmptyFilterRule.cs | 1 - .../FilterCore/FilterRules/IsNotEmptyValidationRule.cs | 1 - .../FilterRules/PropertiesTextContainsFilterRule.cs | 7 ------- .../FilterRules/PropertyValueSelectorFilterRule.cs | 1 - .../FilterCore/FilterRules/SelectorFilterRule.cs | 8 -------- .../FilterRules/SingleValueComparableValueFilterRule.cs | 7 ------- .../FilterCore/FilterRules/TextContainsFilterRule.cs | 1 - .../FilterRules/TextDoesNotContainFilterRule.cs | 1 - .../FilterCore/FilterRules/TextDoesNotEqualFilterRule.cs | 1 - .../FilterCore/FilterRules/TextEndsWithFilterRule.cs | 1 - .../FilterCore/FilterRules/TextEqualsFilterRule.cs | 1 - .../FilterCore/FilterRules/TextFilterRule.cs | 1 - .../FilterCore/FilterRules/TextStartsWithFilterRule.cs | 1 - .../ManagementList/FilterCore/ValidatingSelectorValue.cs | 2 -- .../ManagementList/FilterCore/ValidatingValue.cs | 1 - .../ManagementList/FilterCore/ValidatingValueBase.cs | 3 --- .../ValidationRules/DataErrorInfoValidationRule.cs | 1 - .../FilterProviders/FilterRuleToDisplayNameConverter.cs | 1 - .../ManagementList/ManagementListStateDescriptor.cs | 1 - src/powershell-win-core/powershell-win-core.csproj | 1 - 28 files changed, 58 deletions(-) diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/ComparableValueFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/ComparableValueFilterRule.cs index dca6c08d535..8362a035156 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/ComparableValueFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/ComparableValueFilterRule.cs @@ -13,7 +13,6 @@ namespace Microsoft.Management.UI.Internal /// The generic parameter. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public abstract class ComparableValueFilterRule : FilterRule where T : IComparable { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/DoesNotEqualFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/DoesNotEqualFilterRule.cs index 94451623c3a..c5d4f36fe55 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/DoesNotEqualFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/DoesNotEqualFilterRule.cs @@ -13,7 +13,6 @@ namespace Microsoft.Management.UI.Internal /// The generic parameter. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class DoesNotEqualFilterRule : EqualsFilterRule where T : IComparable { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/EqualsFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/EqualsFilterRule.cs index eaf647f0030..34a1ecb722d 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/EqualsFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/EqualsFilterRule.cs @@ -14,7 +14,6 @@ namespace Microsoft.Management.UI.Internal /// The generic parameter. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class EqualsFilterRule : SingleValueComparableValueFilterRule where T : IComparable { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/FilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/FilterRule.cs index 7f72f33eb2d..f18c89addf9 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/FilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/FilterRule.cs @@ -9,7 +9,6 @@ namespace Microsoft.Management.UI.Internal /// The base class for all filtering rules. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public abstract class FilterRule : IEvaluate, IDeepCloneable { /// @@ -69,7 +68,6 @@ public object DeepClone() /// /// Occurs when the values of this rule changes. /// - [field: NonSerialized] public event EventHandler EvaluationResultInvalidated; /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsBetweenFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsBetweenFilterRule.cs index d8c4a263c61..f51093510ec 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsBetweenFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsBetweenFilterRule.cs @@ -16,7 +16,6 @@ namespace Microsoft.Management.UI.Internal /// The generic parameter. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class IsBetweenFilterRule : ComparableValueFilterRule where T : IComparable { #region Properties @@ -122,13 +121,6 @@ private void Value_PropertyChanged(object sender, PropertyChangedEventArgs e) } } - [OnDeserialized] - private void Initialize(StreamingContext context) - { - this.StartValue.PropertyChanged += this.Value_PropertyChanged; - this.EndValue.PropertyChanged += this.Value_PropertyChanged; - } - #endregion Value Change Handlers } } diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsEmptyFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsEmptyFilterRule.cs index a3add25eae5..71bb7e23e7c 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsEmptyFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsEmptyFilterRule.cs @@ -10,7 +10,6 @@ namespace Microsoft.Management.UI.Internal /// is empty or not. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class IsEmptyFilterRule : FilterRule { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsGreaterThanFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsGreaterThanFilterRule.cs index c6d9ef762b4..6c7d16f312a 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsGreaterThanFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsGreaterThanFilterRule.cs @@ -14,7 +14,6 @@ namespace Microsoft.Management.UI.Internal /// The generic parameter. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class IsGreaterThanFilterRule : SingleValueComparableValueFilterRule where T : IComparable { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsLessThanFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsLessThanFilterRule.cs index a90dcdc8a82..e1dc3268cc5 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsLessThanFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsLessThanFilterRule.cs @@ -14,7 +14,6 @@ namespace Microsoft.Management.UI.Internal /// The generic parameter. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class IsLessThanFilterRule : SingleValueComparableValueFilterRule where T : IComparable { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyFilterRule.cs index 450a1237a97..711caee9874 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyFilterRule.cs @@ -10,7 +10,6 @@ namespace Microsoft.Management.UI.Internal /// is empty or not. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class IsNotEmptyFilterRule : IsEmptyFilterRule { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyValidationRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyValidationRule.cs index 98534aca0ad..cb6eacaaff3 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyValidationRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/IsNotEmptyValidationRule.cs @@ -9,7 +9,6 @@ namespace Microsoft.Management.UI.Internal /// The IsNotEmptyValidationRule checks a value to see if a value is not empty. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class IsNotEmptyValidationRule : DataErrorInfoValidationRule { #region Properties diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertiesTextContainsFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertiesTextContainsFilterRule.cs index 54532335835..8c32530be8c 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertiesTextContainsFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertiesTextContainsFilterRule.cs @@ -12,7 +12,6 @@ namespace Microsoft.Management.UI.Internal /// Represents a filter rule that searches for text within properties on an object. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class PropertiesTextContainsFilterRule : TextFilterRule { private static readonly string TextContainsCharactersRegexPattern = "{0}"; @@ -131,11 +130,5 @@ private void PropertiesTextContainsFilterRule_EvaluationResultInvalidated(object { this.OnEvaluationResultInvalidated(); } - - [OnDeserialized] - private void Initialize(StreamingContext context) - { - this.EvaluationResultInvalidated += this.PropertiesTextContainsFilterRule_EvaluationResultInvalidated; - } } } diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertyValueSelectorFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertyValueSelectorFilterRule.cs index 6699cb0e698..09c732970b0 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertyValueSelectorFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/PropertyValueSelectorFilterRule.cs @@ -16,7 +16,6 @@ namespace Microsoft.Management.UI.Internal /// The generic parameter. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class PropertyValueSelectorFilterRule : SelectorFilterRule where T : IComparable { #region Properties diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SelectorFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SelectorFilterRule.cs index d7451bbd21f..d1627ee2281 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SelectorFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SelectorFilterRule.cs @@ -10,7 +10,6 @@ namespace Microsoft.Management.UI.Internal /// The SelectorFilterRule represents a rule composed of other rules. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class SelectorFilterRule : FilterRule { #region Properties @@ -113,13 +112,6 @@ private void SelectedValue_EvaluationResultInvalidated(object sender, EventArgs #region Private Methods - [OnDeserialized] - private void Initialize(StreamingContext context) - { - this.AvailableRules.SelectedValueChanged += this.AvailableRules_SelectedValueChanged; - this.AvailableRules.SelectedValue.EvaluationResultInvalidated += this.SelectedValue_EvaluationResultInvalidated; - } - private void AvailableRules_SelectedValueChanged(object sender, PropertyChangedEventArgs e) { this.OnSelectedValueChanged(e.OldValue, e.NewValue); diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SingleValueComparableValueFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SingleValueComparableValueFilterRule.cs index a34288a6530..b26531943fc 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SingleValueComparableValueFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/SingleValueComparableValueFilterRule.cs @@ -13,7 +13,6 @@ namespace Microsoft.Management.UI.Internal /// /// The generic parameter. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public abstract class SingleValueComparableValueFilterRule : ComparableValueFilterRule where T : IComparable { #region Properties @@ -72,11 +71,5 @@ private void Value_PropertyChanged(object sender, PropertyChangedEventArgs e) this.NotifyEvaluationResultInvalidated(); } } - - [OnDeserialized] - private void Initialize(StreamingContext context) - { - this.Value.PropertyChanged += this.Value_PropertyChanged; - } } } diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextContainsFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextContainsFilterRule.cs index acd52555498..beb4a29d23f 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextContainsFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextContainsFilterRule.cs @@ -11,7 +11,6 @@ namespace Microsoft.Management.UI.Internal /// check if it is contains the rule's value within it. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class TextContainsFilterRule : TextFilterRule { private static readonly string TextContainsCharactersRegexPattern = "{0}"; diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotContainFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotContainFilterRule.cs index f85ca1bd125..2cdbf1efcef 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotContainFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotContainFilterRule.cs @@ -10,7 +10,6 @@ namespace Microsoft.Management.UI.Internal /// check if it is does not contain the rule's value within it. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class TextDoesNotContainFilterRule : TextContainsFilterRule { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotEqualFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotEqualFilterRule.cs index 0c7bb96532c..e74b371a7a6 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotEqualFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextDoesNotEqualFilterRule.cs @@ -10,7 +10,6 @@ namespace Microsoft.Management.UI.Internal /// check if it is not equal to the rule's value. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class TextDoesNotEqualFilterRule : TextEqualsFilterRule { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEndsWithFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEndsWithFilterRule.cs index 2d4febe058d..d7f7e05c4b8 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEndsWithFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEndsWithFilterRule.cs @@ -11,7 +11,6 @@ namespace Microsoft.Management.UI.Internal /// check if it ends with the rule's value. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class TextEndsWithFilterRule : TextFilterRule { private static readonly string TextEndsWithCharactersRegexPattern = "{0}$"; diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEqualsFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEqualsFilterRule.cs index a6e74dca622..a357575c6ab 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEqualsFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextEqualsFilterRule.cs @@ -11,7 +11,6 @@ namespace Microsoft.Management.UI.Internal /// check if it is equal to the rule's value. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class TextEqualsFilterRule : TextFilterRule { private static readonly string TextEqualsCharactersRegexPattern = "^{0}$"; diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextFilterRule.cs index c4cd5dba9f7..eacbcb8d256 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextFilterRule.cs @@ -14,7 +14,6 @@ namespace Microsoft.Management.UI.Internal /// evaluating string operations. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public abstract class TextFilterRule : SingleValueComparableValueFilterRule { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextStartsWithFilterRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextStartsWithFilterRule.cs index 3b39d0f5660..98eac2b9a41 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextStartsWithFilterRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/FilterRules/TextStartsWithFilterRule.cs @@ -11,7 +11,6 @@ namespace Microsoft.Management.UI.Internal /// check if it starts with the rule's value. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class TextStartsWithFilterRule : TextFilterRule { private static readonly string TextStartsWithCharactersRegexPattern = "^{0}"; diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingSelectorValue.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingSelectorValue.cs index ff981a74751..0fed0c42e65 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingSelectorValue.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingSelectorValue.cs @@ -16,7 +16,6 @@ namespace Microsoft.Management.UI.Internal /// The generic parameter. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class ValidatingSelectorValue : ValidatingValueBase { /// @@ -174,7 +173,6 @@ public IValueConverter DisplayNameConverter /// /// Notifies listeners that the selected value has changed. /// - [field: NonSerialized] public event EventHandler> SelectedValueChanged; #endregion Events diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValue.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValue.cs index eee8ebc6e4a..437cb3be50e 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValue.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValue.cs @@ -15,7 +15,6 @@ namespace Microsoft.Management.UI.Internal /// The generic parameter. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class ValidatingValue : ValidatingValueBase { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValueBase.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValueBase.cs index 6b4c2daa10d..a4ffb1af77c 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValueBase.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidatingValueBase.cs @@ -15,7 +15,6 @@ namespace Microsoft.Management.UI.Internal /// classes to support validation via the IDataErrorInfo interface. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public abstract class ValidatingValueBase : IDataErrorInfo, INotifyPropertyChanged, IDeepCloneable { /// @@ -47,7 +46,6 @@ protected ValidatingValueBase(ValidatingValueBase source) private ReadOnlyCollection readonlyValidationRules; private bool isValidationRulesCollectionDirty = true; - [field: NonSerialized] private DataErrorInfoValidationResult cachedValidationResult; /// @@ -141,7 +139,6 @@ public string Error /// /// The listeners attached to this event are not serialized. /// - [field: NonSerialized] public event PropertyChangedEventHandler PropertyChanged; #endregion PropertyChanged diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidationRules/DataErrorInfoValidationRule.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidationRules/DataErrorInfoValidationRule.cs index 78b54a9c045..a92916c0717 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidationRules/DataErrorInfoValidationRule.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterCore/ValidationRules/DataErrorInfoValidationRule.cs @@ -9,7 +9,6 @@ namespace Microsoft.Management.UI.Internal /// Provides a way to create a custom rule in order to check the validity of user input. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public abstract class DataErrorInfoValidationRule : IDeepCloneable { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/FilterProviders/FilterRuleToDisplayNameConverter.cs b/src/Microsoft.Management.UI.Internal/ManagementList/FilterProviders/FilterRuleToDisplayNameConverter.cs index aaca30ff321..972c19080e0 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/FilterProviders/FilterRuleToDisplayNameConverter.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/FilterProviders/FilterRuleToDisplayNameConverter.cs @@ -12,7 +12,6 @@ namespace Microsoft.Management.UI.Internal /// a FilterRule value to its DisplayName. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class FilterRuleToDisplayNameConverter : IValueConverter { /// diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/ManagementList/ManagementListStateDescriptor.cs b/src/Microsoft.Management.UI.Internal/ManagementList/ManagementList/ManagementListStateDescriptor.cs index 668118a5b7f..bbfd3d8603c 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/ManagementList/ManagementListStateDescriptor.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/ManagementList/ManagementListStateDescriptor.cs @@ -16,7 +16,6 @@ namespace Microsoft.Management.UI.Internal /// Allows the state of the ManagementList to be saved and restored. /// [SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - [Serializable] public class ManagementListStateDescriptor : StateDescriptor { #region Fields diff --git a/src/powershell-win-core/powershell-win-core.csproj b/src/powershell-win-core/powershell-win-core.csproj index 73c55497c5b..5368518dd3c 100644 --- a/src/powershell-win-core/powershell-win-core.csproj +++ b/src/powershell-win-core/powershell-win-core.csproj @@ -13,7 +13,6 @@ ..\..\assets\pwsh.manifest Windows 8.0 - true From 434f880bcdf6cfe8ab7ccc2dbdca4f606d027762 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 3 Sep 2025 14:32:16 -0700 Subject: [PATCH 147/275] [release/v7.5] Add Codeql Suppressions (#25972) Co-authored-by: Anam Navied Co-authored-by: Travis Plunk --- .../commands/management/Process.cs | 1 + .../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 1 + .../engine/NativeCommandProcessor.cs | 1 + .../engine/remoting/common/RunspaceConnectionInfo.cs | 1 + .../namespaces/FileSystemProvider.cs | 1 + 5 files changed, 5 insertions(+) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs index 4ca7d9aaa5b..a1f9dbf1e0f 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs @@ -1904,6 +1904,7 @@ protected override void BeginProcessing() } catch (CommandNotFoundException) { + // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path they are specifying and the process is on the user's system except for remoting in which case restricted remoting security guidelines should be used. startInfo.FileName = FilePath; #if UNIX // Arguments are passed incorrectly to the executable used for ShellExecute and not to filename https://github.com/dotnet/corefx/issues/30718 diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs index 810b54a8391..d7c0931c786 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs @@ -1296,6 +1296,7 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM _cancelToken = new CancellationTokenSource(); try { + // codeql[cs/ssrf] - This is expected Poweshell behavior where user inputted Uri is supported for the context of this method. The user assumes trust for the Uri and invocation is done on the user's machine, not a web application. If there is concern for remoting, they should use restricted remoting. response = client.SendAsync(currentRequest, HttpCompletionOption.ResponseHeadersRead, _cancelToken.Token).GetAwaiter().GetResult(); } catch (TaskCanceledException ex) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 371e1ff00ff..43113d07425 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -1396,6 +1396,7 @@ private ProcessStartInfo GetProcessStartInfo( { var startInfo = new ProcessStartInfo { + // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified on the user's system to retrieve process info for, and in the case of remoting, restricted remoting security guidelines should be used. FileName = this.Path }; diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index 9c221f01dbb..d18eb249cb7 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -2230,6 +2230,7 @@ internal int StartSSHProcess( // linux|macos: // Subsystem powershell /usr/local/bin/pwsh -SSHServerMode -NoLogo -NoProfile + // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified, so any file executed in the runspace would be in the user's local system/process or a system they have access to in which case restricted remoting security guidelines should be used. System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(filePath); // pass "-i identity_file" command line argument to ssh if KeyFilePath is set diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index aefa2d499b6..dee701296e4 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -1325,6 +1325,7 @@ protected override void InvokeDefaultAction(string path) if (ShouldProcess(resource, action)) { var invokeProcess = new System.Diagnostics.Process(); + // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path they are specifying. If there is concern for remoting, restricted remoting guidelines should be used. invokeProcess.StartInfo.FileName = path; #if UNIX bool useShellExecute = false; From 0091d13c5b8f4541dfd70da25a5300cfc0fa8194 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 3 Sep 2025 14:53:57 -0700 Subject: [PATCH 148/275] [release/v7.5] Add build to vPack Pipeline (#25975) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Travis Plunk --- .pipelines/PowerShell-vPack-Official.yml | 285 +++++++++++++++------- .pipelines/templates/obp-file-signing.yml | 25 +- tools/packaging/packaging.psm1 | 18 +- 3 files changed, 230 insertions(+), 98 deletions(-) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 05a8fefbb0f..5783785cfd6 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -1,32 +1,30 @@ trigger: none parameters: # parameters are shown up in ADO UI in a build queue time +- name: OfficialBuild + type: boolean + default: true - name: 'createVPack' displayName: 'Create and Submit VPack' type: boolean default: true -- name: 'debug' - displayName: 'Enable debug output' - type: boolean - default: false -- name: 'architecture' +- name: vPackName type: string - displayName: 'Select the vpack architecture:' + displayName: 'VPack Name:' + default: 'PowerShell' values: - - x64 - - x86 - - arm64 - default: x64 -- name: 'VPackPublishOverride' - type: string - displayName: 'VPack Publish Override Version (can leave blank):' - default: ' ' + - PowerShell + - PowerShellDoNotUse - name: 'ReleaseTagVar' type: string displayName: 'Release Tag Var:' default: 'fromBranch' +- name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false -name: vPack_${{ parameters.architecture }}_$(date:yyMM).$(date:dd)$(rev:rrr) +name: vPack_$(Build.SourceBranchName)_Prod.${{ parameters.OfficialBuild }}_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -51,6 +49,12 @@ variables: value: ${{ parameters.ReleaseTagVar }} - group: Azure Blob variable group - group: certificate_logical_to_actual # used within signing task + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/Microsoft.Official.yml@templates', 'v2/Microsoft.NonOfficial.yml@templates' ) }} + - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual +# We shouldn't be using PATs anymore +# - group: mscodehub-feed-read-general resources: repositories: @@ -59,17 +63,8 @@ resources: name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main - pipelines: - - pipeline: PSPackagesOfficial - source: 'PowerShell-Packages-Official' - trigger: - branches: - include: - - master - - releases/* - extends: - template: v2/Microsoft.Official.yml@templates + template: ${{ variables.templateFile }} parameters: platform: name: 'windows_undocked' # windows undocked @@ -99,35 +94,116 @@ extends: enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - - stage: main + - stage: BuildStage jobs: - - job: main + - job: BuildJob pool: type: windows + strategy: + matrix: + x86: + architecture: x86 + + x64: + architecture: x64 + + arm64: + architecture: arm64 + variables: + ArtifactPlatform: 'windows' + ob_artifactBaseName: drop_build_$(architecture) ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' ob_createvpack_enabled: ${{ parameters.createVPack }} - ob_createvpack_packagename: 'PowerShell.${{ parameters.architecture }}' - ob_createvpack_description: PowerShell ${{ parameters.architecture }} $(version) ob_createvpack_owneralias: tplunk - ob_createvpack_versionAs: string - ob_createvpack_version: '$(version)' + ob_createvpack_versionAs: parts ob_createvpack_propsFile: true ob_createvpack_verbose: true + ob_createvpack_packagename: '${{ parameters.vPackName }}.$(architecture)' + ob_createvpack_description: PowerShell $(architecture) $(version) + # I think the variables reload after we transition back to the host so this works. 🤷‍♂️ + ob_createvpack_majorVer: $(pwshMajorVersion) + ob_createvpack_minorVer: $(pwshMinorVersion) + ob_createvpack_patchVer: $(pwshPatchVersion) + ${{ if ne(variables['pwshPrereleaseVersion'], '') }}: + ob_createvpack_prereleaseVer: $(pwshPrereleaseVersion) + ${{ else }}: + ob_createvpack_prereleaseVer: $(Build.SourceVersion) steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s + env: + ob_restore_phase: true + - template: .pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes UseJson: no + - pwsh: | + $version = '$(Version)' + Write-Verbose -Verbose "Version: $version" + if(!$version) { + throw "Version is not set." + } + + $mainVersionParts = $version -split '-' + + Write-Verbose -Verbose "mainVersionParts: $($mainVersionParts[0]) ; $($mainVersionParts[1])" + $versionParts = $mainVersionParts[0] -split '[.]'; + $major = $versionParts[0] + $minor = $versionParts[1] + $patch = $versionParts[2] + + $previewPart = $mainVersionParts[1] + Write-Verbose -Verbose "previewPart: $previewPart" + + Write-Host "major: $major; minor: $minor; patch: $patch;" + + $vstsCommandString = "vso[task.setvariable variable=pwshMajorVersion]$major" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $vstsCommandString = "vso[task.setvariable variable=pwshMinorVersion]$minor" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $vstsCommandString = "vso[task.setvariable variable=pwshPatchVersion]$patch" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + if($previewPart) { + $vstsCommandString = "vso[task.setvariable variable=pwshPrereleaseVersion]$previewPart" + } else { + Write-Verbose -Verbose "No prerelease part found in version string." + } + displayName: Set ob_createvpack_*Ver + env: + ob_restore_phase: true + + # Validate pwsh*Version variables + - pwsh: | + $variables = @("pwshMajorVersion", "pwshMinorVersion", "pwshPatchVersion") + foreach ($var in $variables) { + if (-not (get-item "Env:\$var" -ErrorAction SilentlyContinue).value) { + throw "Required variable '`$env:$var' is not set." + } + } + displayName: Validate pwsh*Version variables + env: + ob_restore_phase: true + - pwsh: | if($env:RELEASETAGVAR -match '-') { throw "Don't release a preview build without coordinating with Windows Engineering Build Tools Team" } displayName: Stop any preview release + env: + ob_restore_phase: true - task: UseDotNet@2 displayName: 'Use .NET Core sdk' @@ -136,88 +212,115 @@ extends: version: 3.1.x installationPath: $(Agent.ToolsDirectory)/dotnet + ### BUILD ### + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(repoRoot) + + - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + inputs: + Enabled: true + AnalyzeInPipeline: false # Do not upload results + Language: csharp + + - task: UseDotNet@2 + displayName: 'Install .NET based on global.json' + inputs: + useGlobalJson: true + workingDirectory: $(repoRoot) + env: + ob_restore_phase: true + - pwsh: | - $packageArtifactName = 'drop_windows_package_package_win_${{ parameters.architecture }}' - $vstsCommandString = "vso[task.setvariable variable=PackageArtifactName]$packageArtifactName" - Write-Host "sending " + $vstsCommandString + # Need to set PowerShellRoot variable for obp-file-signing template + $vstsCommandString = "vso[task.setvariable variable=PowerShellRoot]$(repoRoot)" + Write-Host ("sending " + $vstsCommandString) Write-Host "##$vstsCommandString" - $packageArtifactPath = '$(Pipeline.Workspace)\PSPackagesOfficial' - $vstsCommandString = "vso[task.setvariable variable=PackageArtifactPath]$packageArtifactPath" - Write-Host "sending " + $vstsCommandString + $Architecture = '$(Architecture)' + $runtime = switch ($Architecture) + { + "x64" { "win7-x64" } + "x86" { "win7-x86" } + "arm64" { "win-arm64" } + } + + $params = @{} + if ($env:BuildConfiguration -eq 'minSize') { + $params['ForMinimalSize'] = $true + } + + $vstsCommandString = "vso[task.setvariable variable=Runtime]$runtime" + Write-Host ("sending " + $vstsCommandString) Write-Host "##$vstsCommandString" - displayName: 'Set package artifact variables' - - download: PSPackagesOfficial - artifact: $(PackageArtifactName) - displayName: Download package + Write-Verbose -Message "Building PowerShell with Runtime: $runtime for '$env:BuildConfiguration' configuration" + Import-Module -Name $(repoRoot)/build.psm1 -Force + $buildWithSymbolsPath = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/Symbols_$Architecture" -Force - - pwsh: 'Get-ChildItem $(PackageArtifactPath)\* -recurse | Select-Object -ExpandProperty Name' - displayName: 'Capture Artifact Listing' + Start-PSBootstrap -Scenario Package + $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose - - pwsh: | - $message = @() - $packages = Get-ChildItem $(PackageArtifactPath)\* -recurse -include *.zip, *.msi - - if($packages.count -eq 0) {throw "No packages found in $(PackageArtifactPath)"} - - $packages | ForEach-Object { - if($_.Name -notmatch 'PowerShell-\d+\.\d+\.\d+\-([a-z]*.\d+\-)?win\-(fxdependent|x64|arm64|x86|fxdependentWinDesktop)\.(msi|zip){1}') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } + $ReleaseTagParam = @{} + + if ($env:RELEASETAGVAR) { + $ReleaseTagParam['ReleaseTag'] = $env:RELEASETAGVAR } - if($message.count -gt 0){throw ($message | out-string)} - displayName: 'Validate Zip and MSI Package Names' + Start-PSBuild -Runtime $runtime -Configuration Release -Output $buildWithSymbolsPath -Clean -PSModuleRestore @params @ReleaseTagParam - - pwsh: | - Get-ChildItem $(PackageArtifactPath)\* -recurse -include *.zip | ForEach-Object { - if($_.Name -match 'PowerShell-\d+\.\d+\.\d+\-([a-z]*.\d+\-)?win\-(${{ parameters.architecture }})\.(zip){1}') - { - Expand-Archive -Path $_.FullName -DestinationPath $(ob_outputDirectory) - } - } - displayName: 'Extract Zip to ob_outputDirectory' + $refFolderPath = Join-Path $buildWithSymbolsPath 'ref' + Write-Verbose -Verbose "refFolderPath: $refFolderPath" + $outputPath = Join-Path '$(ob_outputDirectory)' 'psoptions' + $null = New-Item -ItemType Directory -Path $outputPath -Force + $psOptPath = "$outputPath/psoptions.json" + Save-PSOptions -PSOptionsPath $psOptPath + + Write-Verbose -Verbose "Completed building PowerShell for '$env:BuildConfiguration' configuration" + displayName: Build Windows Universal - $(Architecture) -$(BuildConfiguration) Symbols folder + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: CodeQL3000Finalize@0 # Add CodeQL Finalize task right after your 'Build' step. + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + inputs: + sourceScanPath: '$(repoRoot)\src' + ob_restore_phase: true + + - template: /.pipelines/templates/obp-file-signing.yml@self + parameters: + binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' + SigningProfile: $(windows_build_tools_cert_id) + OfficialBuild: false + vPackScenario: true + + ### END OF BUILD ### - pwsh: | - Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose - Get-ChildItem -Path $(ob_outputDirectory)\* -Recurse - Get-Content $(ob_outputdirectory)\preview.json -ErrorAction SilentlyContinue | Write-Host + Get-ChildItem env:/ob_createvpack_*Ver + Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse + Get-Content "$(Pipeline.Workspace)\PowerShell\preview.json" -ErrorAction SilentlyContinue | Write-Host displayName: Debug Output Directory and Version condition: succeededOrFailed() - pwsh: | - Write-Host "Using VPackPublishOverride variable" - $vpackVersion = '${{ parameters.VPackPublishOverride }}' - $vstsCommandString = "vso[task.setvariable variable=ob_createvpack_version]$vpackVersion" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - condition: ne('${{ parameters.VPackPublishOverride }}', ' ') - displayName: 'Set ob_createvpack_version with VPackPublishOverride' - - - pwsh: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture Environment condition: succeededOrFailed() - pwsh: | - Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose - $vpackFiles = Get-ChildItem -Path $(ob_outputDirectory)\* -Recurse + $vpackFiles = Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse if($vpackFiles.Count -eq 0) { - throw "No files found in $(ob_outputDirectory)" + throw "No files found in $(Pipeline.Workspace)\Symbols_$(Architecture)" } $vpackFiles displayName: Debug Output Directory and Version condition: succeededOrFailed() - - - task: onebranch.pipeline.signing@1 - displayName: 'Onebranch Signing' - inputs: - command: 'sign' - signing_environment: 'azure-ado' - cp_code: $(windows_build_tools_cert_id) - files_to_sign: '**/*.exe;**/System.Management.Automation.dll' - search_root: $(ob_outputDirectory) diff --git a/.pipelines/templates/obp-file-signing.yml b/.pipelines/templates/obp-file-signing.yml index ba761633b29..7c6ce7c6375 100644 --- a/.pipelines/templates/obp-file-signing.yml +++ b/.pipelines/templates/obp-file-signing.yml @@ -1,6 +1,9 @@ parameters: binPath: '$(ob_outputDirectory)' globalTool: 'false' + SigningProfile: 'external_distribution' + OfficialBuild: true + vPackScenario: false steps: - pwsh: | @@ -80,7 +83,7 @@ steps: displayName: Sign 1st party files inputs: command: 'sign' - signing_profile: external_distribution + signing_profile: ${{ parameters.SigningProfile }} files_to_sign: '**\*.psd1;**\*.psm1;**\*.ps1xml;**\*.ps1;**\*.dll;**\*.exe;**\pwsh' search_root: $(Pipeline.Workspace)/toBeSigned @@ -95,12 +98,15 @@ steps: $BuildPath = (Get-Item '${{ parameters.binPath }}').FullName Write-Verbose -Verbose -Message "BuildPath: $BuildPath" + $officialBuild = [System.Convert]::ToBoolean('${{ parameters.OfficialBuild }}') ## copy all files to be signed to build folder - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath '$(Pipeline.Workspace)/toBeSigned' + Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath '$(Pipeline.Workspace)/toBeSigned' -OfficialBuild $officialBuild $dlls = Get-ChildItem $BuildPath/*.dll, $BuildPath/*.exe -Recurse $signatures = $dlls | Get-AuthenticodeSignature - $missingSignatures = $signatures | Where-Object { $_.status -eq 'notsigned' -or $_.SignerCertificate.Issuer -notmatch '^CN=Microsoft.*'}| select-object -ExpandProperty Path + $officialIssuerPattern = '^CN=(Microsoft Code Signing PCA|Microsoft Root Certificate Authority|Microsoft Corporation).*' + $testCert = '^CN=(Microsoft|TestAzureEngBuildCodeSign).*' + $missingSignatures = $signatures | Where-Object { $_.status -eq 'notsigned' -or $_.SignerCertificate.Issuer -notmatch $testCert -or $_.SignerCertificate.Issuer -notmatch $officialIssuerPattern} | select-object -ExpandProperty Path Write-Verbose -verbose "to be signed:`r`n $($missingSignatures | Out-String)" @@ -137,11 +143,20 @@ steps: displayName: Capture ThirdParty Signed files - pwsh: | + $officialBuild = [System.Convert]::ToBoolean('${{ parameters.OfficialBuild }}') + $vPackScenario = [System.Convert]::ToBoolean('${{ parameters.vPackScenario }}') Import-Module '$(PowerShellRoot)/build.psm1' -Force Import-Module '$(PowerShellRoot)/tools/packaging' -Force $isGlobalTool = '${{ parameters.globalTool }}' -eq 'true' - if (-not $isGlobalTool) { + if ($vPackScenario) { + Write-Verbose -Verbose -Message "vPackScenario is true, copying to $(ob_outputDirectory)" + $pathForUpload = New-Item -ItemType Directory -Path '$(ob_outputDirectory)' -Force + Write-Verbose -Verbose -Message "pathForUpload: $pathForUpload" + Copy-Item -Path '${{ parameters.binPath }}\*' -Destination $pathForUpload -Recurse -Force -Verbose + Write-Verbose -Verbose -Message "Files copied to $pathForUpload" + } + elseif (-not $isGlobalTool) { $pathForUpload = New-Item -ItemType Directory -Path '$(ob_outputDirectory)/Signed-$(Runtime)' -Force Write-Verbose -Verbose -Message "pathForUpload: $pathForUpload" Copy-Item -Path '${{ parameters.binPath }}\*' -Destination $pathForUpload -Recurse -Force -Verbose @@ -153,7 +168,7 @@ steps: Write-Verbose "Copying third party signed files to the build folder" $thirdPartySignedFilesPath = (Get-Item '$(Pipeline.Workspace)/thirdPartyToBeSigned').FullName - Update-PSSignedBuildFolder -BuildPath $pathForUpload -SignedFilesPath $thirdPartySignedFilesPath + Update-PSSignedBuildFolder -BuildPath $pathForUpload -SignedFilesPath $thirdPartySignedFilesPath -OfficialBuild $officialBuild displayName: 'Copy signed files for upload' diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 782a4ecadc8..560a985283b 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -887,7 +887,8 @@ function Update-PSSignedBuildFolder [string]$BuildPath, [Parameter(Mandatory)] [string]$SignedFilesPath, - [string[]] $RemoveFilter = ('*.pdb', '*.zip', '*.r2rmap') + [string[]] $RemoveFilter = ('*.pdb', '*.zip', '*.r2rmap'), + [bool]$OfficialBuild = $true ) $BuildPathNormalized = (Get-Item $BuildPath).FullName @@ -943,8 +944,21 @@ function Update-PSSignedBuildFolder if ($IsWindows) { $signature = Get-AuthenticodeSignature -FilePath $signedFilePath - if ($signature.Status -ne 'Valid') { + + if ($signature.Status -ne 'Valid' -and $OfficialBuild) { + Write-Host "Certificate Issuer: $($signature.SignerCertificate.Issuer)" + Write-Host "Certificate Subject: $($signature.SignerCertificate.Subject)" Write-Error "Invalid signature for $signedFilePath" + } elseif ($OfficialBuild -eq $false) { + if ($signature.Status -eq 'NotSigned') { + Write-Warning "File is not signed: $signedFilePath" + } elseif ($signature.SignerCertificate.Issuer -notmatch '^CN=(Microsoft|TestAzureEngBuildCodeSign|Windows Internal Build Tools).*') { + Write-Warning "File signed with test certificate: $signedFilePath" + Write-Host "Certificate Issuer: $($signature.SignerCertificate.Issuer)" + Write-Host "Certificate Subject: $($signature.SignerCertificate.Subject)" + } else { + Write-Verbose -Verbose "File properly signed: $signedFilePath" + } } } else From cbfecf7ae155fa310ee78fd1ff42f0fcf1d13a71 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 5 Sep 2025 11:11:07 -0700 Subject: [PATCH 149/275] [release/v7.5] Update container images to use mcr.microsoft.com for Linux and Azure Linux (#25986) --- .../PowerShell-Coordinated_Packages-Official.yml | 6 ++++-- .pipelines/PowerShell-Packages-Official.yml | 3 +-- .pipelines/PowerShell-Release-Official-Azure.yml | 3 +-- .pipelines/PowerShell-Release-Official.yml | 6 +++--- .pipelines/apiscan-gen-notice.yml | 2 +- .pipelines/templates/linux.yml | 1 + .pipelines/templates/mac.yml | 1 + .pipelines/templates/windows-hosted-build.yml | 2 ++ build.psm1 | 12 +++++++----- 9 files changed, 21 insertions(+), 15 deletions(-) diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 8de89b0c508..73c6e4f39b8 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -65,7 +65,7 @@ variables: - name: __DOTNET_RUNTIME_FEED value: ${{ parameters.InternalSDKBlobURL }} - name: LinuxContainerImage - value: onebranch.azurecr.io/linux/ubuntu-2004:latest + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - name: WindowsContainerImage value: onebranch.azurecr.io/windows/ltsc2019/vse2022:latest - name: CDP_DEFINITION_BUILD_COUNT @@ -86,6 +86,8 @@ variables: # Disable BinSkim at job level to override NonOfficial template defaults - name: ob_sdl_binskim_enabled value: false + - name: ps_official_build + value: ${{ parameters.OfficialBuild }} extends: template: ${{ variables.templateFile }} @@ -130,7 +132,7 @@ extends: - job: SetVars displayName: Set Variables pool: - type: windows + type: linux variables: - name: ob_outputDirectory diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index f0d428bf1d6..b756b6f8c36 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -56,7 +56,7 @@ variables: - name: WindowsContainerImage value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' # Docker image which is used to build the project - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/cbl-mariner/build:2.0 + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - group: mscodehub-feed-read-general - group: mscodehub-feed-read-akv - name: branchCounterKey @@ -66,7 +66,6 @@ variables: - group: MSIXSigningProfile - name: templateFile value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} - resources: pipelines: diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index 8e144f1ee55..1f210ac6745 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -47,11 +47,10 @@ variables: - name: WindowsContainerImage value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/cbl-mariner/build:2.0 + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - group: PoolNames - name: templateFile value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} - resources: repositories: diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 9d543eae3a9..0c943871462 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -57,7 +57,7 @@ variables: - name: WindowsContainerImage value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/cbl-mariner/build:2.0 + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - name: ReleaseTagVar value: ${{ parameters.ReleaseTagVar }} - group: PoolNames @@ -284,7 +284,7 @@ extends: - stage: PublishGitHubReleaseAndNuget displayName: Publish GitHub and Nuget Release - dependsOn: + dependsOn: - setReleaseTagAndChangelog - UpdateChangeLog variables: @@ -404,7 +404,7 @@ extends: - stage: ChangesToMaster displayName: Ensure changes are in GH master - dependsOn: + dependsOn: - PublishPMC jobs: - template: /.pipelines/templates/approvalJob.yml@self diff --git a/.pipelines/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml index 1507b9345bd..af122fb2365 100644 --- a/.pipelines/apiscan-gen-notice.yml +++ b/.pipelines/apiscan-gen-notice.yml @@ -26,7 +26,7 @@ variables: - group: 'ComponentGovernance' - group: 'PoolNames' - name: LinuxContainerImage - value: onebranch.azurecr.io/linux/ubuntu-2004:latest + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - name: WindowsContainerImage value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest - ${{ if eq(parameters['FORCE_CODEQL'],'true') }}: diff --git a/.pipelines/templates/linux.yml b/.pipelines/templates/linux.yml index d6026dc5336..ccfac3fbc8e 100644 --- a/.pipelines/templates/linux.yml +++ b/.pipelines/templates/linux.yml @@ -199,5 +199,6 @@ jobs: - template: /.pipelines/templates/obp-file-signing.yml@self parameters: binPath: $(DropRootPath) + OfficialBuild: $(ps_official_build) - template: /.pipelines/templates/step/finalize.yml@self diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index 310c5695979..b08becedc22 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -148,5 +148,6 @@ jobs: - template: /.pipelines/templates/obp-file-signing.yml@self parameters: binPath: $(DropRootPath) + OfficialBuild: $(ps_official_build) - template: /.pipelines/templates/step/finalize.yml@self diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index 8f8273f4ec8..1f732a0145c 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -204,6 +204,7 @@ jobs: - template: /.pipelines/templates/obp-file-signing.yml@self parameters: binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' + OfficialBuild: $(ps_official_build) ## first we sign all the files in the bin folder - ${{ if eq(variables['Architecture'], 'fxdependent') }}: @@ -211,6 +212,7 @@ jobs: parameters: binPath: '$(GlobalToolArtifactPath)/publish/PowerShell.Windows.x64/release' globalTool: 'true' + OfficialBuild: $(ps_official_build) - pwsh: | Get-ChildItem '$(GlobalToolArtifactPath)/obj/PowerShell.Windows.x64/release' diff --git a/build.psm1 b/build.psm1 index ffaf7b02f9d..21bf0f332ab 100644 --- a/build.psm1 +++ b/build.psm1 @@ -193,7 +193,7 @@ function Get-EnvironmentInformation $environment += @{'IsRedHatFamily' = $environment.IsCentOS -or $environment.IsFedora -or $environment.IsRedHat} $environment += @{'IsSUSEFamily' = $environment.IsSLES -or $environment.IsOpenSUSE} $environment += @{'IsAlpine' = $LinuxInfo.ID -match 'alpine'} - $environment += @{'IsMariner' = $LinuxInfo.ID -match 'mariner'} + $environment += @{'IsMariner' = $LinuxInfo.ID -match 'mariner' -or $LinuxInfo.ID -match 'azurelinux'} # Workaround for temporary LD_LIBRARY_PATH hack for Fedora 24 # https://github.com/PowerShell/PowerShell/issues/2511 @@ -353,8 +353,8 @@ function Start-PSBuild { $PSModuleRestore = $true } - if ($Runtime -eq "linux-arm" -and $environment.IsLinux -and -not $environment.IsUbuntu) { - throw "Cross compiling for linux-arm is only supported on Ubuntu environment" + if ($Runtime -eq "linux-arm" -and $environment.IsLinux -and -not $environment.IsUbuntu -and -not $environment.IsMariner) { + throw "Cross compiling for linux-arm is only supported on AzureLinux/Ubuntu environment" } if ("win-arm","win-arm64" -contains $Runtime -and -not $environment.IsWindows) { @@ -2196,6 +2196,8 @@ function Get-RedHatPackageManager { "yum install -y -q" } elseif ($environment.IsFedora -or (Get-Command -Name dnf -CommandType Application -ErrorAction SilentlyContinue)) { "dnf install -y -q" + } elseif ($environment.IsMariner -or (Get-Command -Name Test-DscConfiguration -CommandType Application -ErrorAction SilentlyContinue)) { + "tdnf install -y -q" } else { throw "Error determining package manager for this distribution." } @@ -2267,8 +2269,8 @@ function Start-PSBootstrap { # Note that when it is null, Invoke-Expression (but not &) must be used to interpolate properly $sudo = if (!$NoSudo) { "sudo" } - if ($BuildLinuxArm -and $environment.IsLinux -and -not $environment.IsUbuntu) { - Write-Error "Cross compiling for linux-arm is only supported on Ubuntu environment" + if ($BuildLinuxArm -and $environment.IsLinux -and -not $environment.IsUbuntu -and -not $environment.IsMariner) { + Write-Error "Cross compiling for linux-arm is only supported on AzureLinux/Ubuntu environment" return } From 30814e81966ca7ebb9b5904fd54188ab6cf838e4 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 5 Sep 2025 13:26:32 -0700 Subject: [PATCH 150/275] [release/v7.5] Make logical template name consistent between pipelines (#25991) Co-authored-by: Travis Plunk --- .pipelines/MSIXBundle-vPack-Official.yml | 4 ++-- .pipelines/PowerShell-Coordinated_Packages-Official.yml | 2 +- .pipelines/PowerShell-Packages-Official.yml | 4 ++-- .pipelines/PowerShell-Release-Official-Azure.yml | 4 ++-- .pipelines/PowerShell-Release-Official.yml | 4 ++-- .pipelines/PowerShell-vPack-Official.yml | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index ef96f63f045..8e175c5a6bb 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -29,7 +29,7 @@ variables: resources: repositories: - - repository: templates + - repository: onebranchTemplates type: git name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main @@ -44,7 +44,7 @@ resources: - releases/* extends: - template: v2/Microsoft.Official.yml@templates + template: v2/Microsoft.Official.yml@onebranchTemplates parameters: platform: name: 'windows_undocked' # windows undocked diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 73c6e4f39b8..b309791d77d 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -1,4 +1,3 @@ -name: bins-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) trigger: none parameters: @@ -30,6 +29,7 @@ parameters: type: boolean default: false +name: bins-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) resources: repositories: diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index b756b6f8c36..333d73276b8 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -28,7 +28,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false -name: pkgs-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -78,7 +78,7 @@ resources: - releases/* repositories: - - repository: templates + - repository: onebranchTemplates type: git name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index 1f210ac6745..f4c41143b5f 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -17,7 +17,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false -name: ev2-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) +name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -54,7 +54,7 @@ variables: resources: repositories: - - repository: templates + - repository: onebranchTemplates type: git name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 0c943871462..974b8f328c8 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -29,7 +29,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false -name: release-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) +name: release-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -71,7 +71,7 @@ variables: resources: repositories: - - repository: templates + - repository: onebranchTemplates type: git name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 5783785cfd6..f110ff0366a 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -50,7 +50,7 @@ variables: - group: Azure Blob variable group - group: certificate_logical_to_actual # used within signing task - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/Microsoft.Official.yml@templates', 'v2/Microsoft.NonOfficial.yml@templates' ) }} + value: ${{ iif ( parameters.OfficialBuild, 'v2/Microsoft.Official.yml@onebranchTemplates', 'v2/Microsoft.NonOfficial.yml@onebranchTemplates' ) }} - group: DotNetPrivateBuildAccess - group: certificate_logical_to_actual # We shouldn't be using PATs anymore @@ -58,7 +58,7 @@ variables: resources: repositories: - - repository: templates + - repository: onebranchTemplates type: git name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main From efdb4a61859cf3381c107a8a0473db32dab9a48f Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 5 Sep 2025 14:09:47 -0700 Subject: [PATCH 151/275] Update third-party library versions in ThirdPartyNotices.txt to 9.0.8 (#25995) --- ThirdPartyNotices.txt | 102 +++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index c97524423aa..ce31689d1f0 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -284,7 +284,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 8.0.17 - MIT +Microsoft.Extensions.ObjectPool 8.0.19 - MIT Copyright Jorn Zaefferer @@ -374,7 +374,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Win32.Registry.AccessControl 9.0.6 - MIT +Microsoft.Win32.Registry.AccessControl 9.0.8 - MIT Copyright (c) 2021 @@ -464,7 +464,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Win32.SystemEvents 9.0.6 - MIT +Microsoft.Win32.SystemEvents 9.0.8 - MIT Copyright (c) 2021 @@ -554,7 +554,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Windows.Compatibility 9.0.6 - MIT +Microsoft.Windows.Compatibility 9.0.8 - MIT (c) Microsoft Corporation @@ -607,7 +607,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.android-arm.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.android-arm.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -697,7 +697,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-arm64.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.android-arm64.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -787,7 +787,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x64.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.android-x64.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -877,7 +877,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x86.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.android-x86.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -967,7 +967,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.linux-arm.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -1057,7 +1057,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -1147,7 +1147,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -1237,7 +1237,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -1327,7 +1327,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -1417,7 +1417,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -1507,7 +1507,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -1597,7 +1597,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-x64.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.linux-x64.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -1687,7 +1687,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -1777,7 +1777,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -1912,7 +1912,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -2002,7 +2002,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -2092,7 +2092,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-x64.runtime.native.System.IO.Ports 9.0.6 - MIT +runtime.osx-x64.runtime.native.System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -2182,7 +2182,7 @@ SOFTWARE. --------------------------------------------------------- -System.CodeDom 9.0.6 - MIT +System.CodeDom 9.0.8 - MIT Copyright (c) 2021 @@ -2358,7 +2358,7 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition 9.0.6 - MIT +System.ComponentModel.Composition 9.0.8 - MIT Copyright (c) 2021 @@ -2448,7 +2448,7 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition.Registration 9.0.6 - MIT +System.ComponentModel.Composition.Registration 9.0.8 - MIT Copyright (c) 2021 @@ -2538,7 +2538,7 @@ SOFTWARE. --------------------------------------------------------- -System.Configuration.ConfigurationManager 9.0.6 - MIT +System.Configuration.ConfigurationManager 9.0.8 - MIT Copyright (c) 2021 @@ -2628,7 +2628,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.Odbc 9.0.6 - MIT +System.Data.Odbc 9.0.8 - MIT Copyright (c) 2021 @@ -2718,7 +2718,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.OleDb 9.0.6 - MIT +System.Data.OleDb 9.0.8 - MIT Copyright (c) 2021 @@ -2827,7 +2827,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Diagnostics.DiagnosticSource 9.0.6 - MIT +System.Diagnostics.DiagnosticSource 9.0.8 - MIT Copyright (c) 2021 @@ -2917,7 +2917,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.EventLog 9.0.6 - MIT +System.Diagnostics.EventLog 9.0.8 - MIT Copyright (c) 2021 @@ -3007,7 +3007,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.PerformanceCounter 9.0.6 - MIT +System.Diagnostics.PerformanceCounter 9.0.8 - MIT Copyright (c) 2021 @@ -3097,7 +3097,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices 9.0.6 - MIT +System.DirectoryServices 9.0.8 - MIT Copyright (c) 2021 @@ -3187,7 +3187,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.AccountManagement 9.0.6 - MIT +System.DirectoryServices.AccountManagement 9.0.8 - MIT Copyright (c) 2021 @@ -3277,7 +3277,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.Protocols 9.0.6 - MIT +System.DirectoryServices.Protocols 9.0.8 - MIT Copyright (c) 2021 @@ -3367,7 +3367,7 @@ SOFTWARE. --------------------------------------------------------- -System.Drawing.Common 9.0.6 - MIT +System.Drawing.Common 9.0.8 - MIT (c) Microsoft Corporation @@ -3402,7 +3402,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Packaging 9.0.6 - MIT +System.IO.Packaging 9.0.8 - MIT Copyright (c) 2021 @@ -3492,7 +3492,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Ports 9.0.6 - MIT +System.IO.Ports 9.0.8 - MIT Copyright (c) 2021 @@ -3582,7 +3582,7 @@ SOFTWARE. --------------------------------------------------------- -System.Management 9.0.6 - MIT +System.Management 9.0.8 - MIT Copyright (c) 2021 @@ -3672,7 +3672,7 @@ SOFTWARE. --------------------------------------------------------- -System.Net.Http.WinHttpHandler 9.0.6 - MIT +System.Net.Http.WinHttpHandler 9.0.8 - MIT Copyright (c) 2021 @@ -3847,7 +3847,7 @@ SOFTWARE. --------------------------------------------------------- -System.Reflection.Context 9.0.6 - MIT +System.Reflection.Context 9.0.8 - MIT Copyright (c) 2021 @@ -4077,7 +4077,7 @@ SOFTWARE. --------------------------------------------------------- -System.Runtime.Caching 9.0.6 - MIT +System.Runtime.Caching 9.0.8 - MIT Copyright (c) 2021 @@ -4242,7 +4242,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Pkcs 9.0.6 - MIT +System.Security.Cryptography.Pkcs 9.0.8 - MIT Copyright (c) 2021 @@ -4332,7 +4332,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.ProtectedData 9.0.6 - MIT +System.Security.Cryptography.ProtectedData 9.0.8 - MIT Copyright (c) 2021 @@ -4422,7 +4422,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Xml 9.0.6 - MIT +System.Security.Cryptography.Xml 9.0.8 - MIT Copyright (c) 2021 @@ -4512,7 +4512,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Permissions 9.0.6 - MIT +System.Security.Permissions 9.0.8 - MIT Copyright (c) 2021 @@ -4851,7 +4851,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Syndication 9.0.6 - MIT +System.ServiceModel.Syndication 9.0.8 - MIT Copyright (c) 2021 @@ -4941,7 +4941,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceProcess.ServiceController 9.0.6 - MIT +System.ServiceProcess.ServiceController 9.0.8 - MIT Copyright (c) 2021 @@ -5031,7 +5031,7 @@ SOFTWARE. --------------------------------------------------------- -System.Speech 9.0.6 - MIT +System.Speech 9.0.8 - MIT Copyright (c) 2021 @@ -5121,7 +5121,7 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encoding.CodePages 9.0.6 - MIT +System.Text.Encoding.CodePages 9.0.8 - MIT Copyright (c) 2021 @@ -5211,7 +5211,7 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encodings.Web 9.0.6 - MIT +System.Text.Encodings.Web 9.0.8 - MIT Copyright (c) 2021 @@ -5301,7 +5301,7 @@ SOFTWARE. --------------------------------------------------------- -System.Threading.AccessControl 9.0.6 - MIT +System.Threading.AccessControl 9.0.8 - MIT Copyright (c) 2021 @@ -5427,7 +5427,7 @@ SOFTWARE. --------------------------------------------------------- -System.Windows.Extensions 9.0.6 - MIT +System.Windows.Extensions 9.0.8 - MIT Copyright (c) 2021 From bcd6bc473f257c09f1d9c226b83a433c83af174b Mon Sep 17 00:00:00 2001 From: "Travis Plunk (HE/HIM)" Date: Tue, 2 Sep 2025 16:58:56 -0700 Subject: [PATCH 152/275] Fix race condition in RemoteHyperVSocket --- .github/workflows/linux-ci.yml | 1 + .github/workflows/macos-ci.yml | 1 + .github/workflows/windows-ci.yml | 1 + build.psm1 | 27 +- .../host/msh/CommandLineParameterParser.cs | 131 ++- .../host/msh/ConsoleHost.cs | 49 +- .../CommandLineParameterParserStrings.resx | 3 + .../resources/ConsoleHostStrings.resx | 6 + .../common/RemoteSessionHyperVSocket.cs | 800 ++++++++++++++---- .../fanin/OutOfProcTransportManager.cs | 24 +- .../server/OutOfProcServerMediator.cs | 28 + .../resources/RemotingErrorIdStrings.resx | 6 + test/xUnit/csharp/test_CommandLineParser.cs | 22 + test/xUnit/csharp/test_RemoteHyperV.cs | 661 +++++++++++++++ 14 files changed, 1563 insertions(+), 197 deletions(-) create mode 100644 test/xUnit/csharp/test_RemoteHyperV.cs diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index a7523f430cf..2bf61ca3e48 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -21,6 +21,7 @@ on: - master - release/** - github-mirror + - "*-feature" # Path filters for PRs need to go into the changes job concurrency: diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 9184dc088f0..e0a85042053 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -19,6 +19,7 @@ on: - master - release/** - github-mirror + - "*-feature" # Path filters for PRs need to go into the changes job concurrency: diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 1e955c78be6..2e392987cb0 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -18,6 +18,7 @@ on: - master - release/** - github-mirror + - "*-feature" # Path filters for PRs need to go into the changes job diff --git a/build.psm1 b/build.psm1 index 21bf0f332ab..fe7eff67b2f 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1973,7 +1973,9 @@ function Test-PSPesterResults function Start-PSxUnit { [CmdletBinding()]param( - [string] $xUnitTestResultsFile = "xUnitResults.xml" + [string] $xUnitTestResultsFile = "xUnitResults.xml", + [switch] $DebugLogging, + [string] $Filter ) # Add .NET CLI tools to PATH @@ -2031,9 +2033,28 @@ function Start-PSxUnit { # We run the xUnit tests sequentially to avoid race conditions caused by manipulating the config.json file. # xUnit tests run in parallel by default. To make them run sequentially, we need to define the 'xunit.runner.json' file. - dotnet test --configuration $Options.configuration --test-adapter-path:. "--logger:xunit;LogFilePath=$xUnitTestResultsFile" + $extraParams = @() + if($Filter) { + $extraParams += @( + '--filter' + $Filter + ) + } + + if($DebugLogging) { + $extraParams += @( + "--logger:console;verbosity=detailed" + ) + } else { + $extraParams += @( + "--logger:xunit;LogFilePath=$xUnitTestResultsFile" + ) + } + dotnet test @extraParams --configuration $Options.configuration --test-adapter-path:. - Publish-TestResults -Path $xUnitTestResultsFile -Type 'XUnit' -Title 'Xunit Sequential' + if(!$DebugLogging){ + Publish-TestResults -Path $xUnitTestResultsFile -Type 'XUnit' -Title 'Xunit Sequential' + } } finally { $env:DOTNET_ROOT = $originalDOTNET_ROOT diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs index 50d2bd77d0f..bafaa9cabdf 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs @@ -203,35 +203,35 @@ internal static int MaxNameLength() [Flags] internal enum ParameterBitmap : long { - Command = 0x00000001, // -Command | -c - ConfigurationName = 0x00000002, // -ConfigurationName | -config - CustomPipeName = 0x00000004, // -CustomPipeName - EncodedCommand = 0x00000008, // -EncodedCommand | -e | -ec - EncodedArgument = 0x00000010, // -EncodedArgument - ExecutionPolicy = 0x00000020, // -ExecutionPolicy | -ex | -ep - File = 0x00000040, // -File | -f - Help = 0x00000080, // -Help, -?, /? - InputFormat = 0x00000100, // -InputFormat | -inp | -if - Interactive = 0x00000200, // -Interactive | -i - Login = 0x00000400, // -Login | -l - MTA = 0x00000800, // -MTA - NoExit = 0x00001000, // -NoExit | -noe - NoLogo = 0x00002000, // -NoLogo | -nol - NonInteractive = 0x00004000, // -NonInteractive | -noni - NoProfile = 0x00008000, // -NoProfile | -nop - OutputFormat = 0x00010000, // -OutputFormat | -o | -of - SettingsFile = 0x00020000, // -SettingsFile | -settings - SSHServerMode = 0x00040000, // -SSHServerMode | -sshs - SocketServerMode = 0x00080000, // -SocketServerMode | -sockets - ServerMode = 0x00100000, // -ServerMode | -server - NamedPipeServerMode = 0x00200000, // -NamedPipeServerMode | -namedpipes - STA = 0x00400000, // -STA - Version = 0x00800000, // -Version | -v - WindowStyle = 0x01000000, // -WindowStyle | -w - WorkingDirectory = 0x02000000, // -WorkingDirectory | -wd - ConfigurationFile = 0x04000000, // -ConfigurationFile - NoProfileLoadTime = 0x08000000, // -NoProfileLoadTime - CommandWithArgs = 0x10000000, // -CommandWithArgs | -cwa + Command = 0x0000000000000001, // -Command | -c + ConfigurationName = 0x0000000000000002, // -ConfigurationName | -config + CustomPipeName = 0x0000000000000004, // -CustomPipeName + EncodedCommand = 0x0000000000000008, // -EncodedCommand | -e | -ec + EncodedArgument = 0x0000000000000010, // -EncodedArgument + ExecutionPolicy = 0x0000000000000020, // -ExecutionPolicy | -ex | -ep + File = 0x0000000000000040, // -File | -f + Help = 0x0000000000000080, // -Help, -?, /? + InputFormat = 0x0000000000000100, // -InputFormat | -inp | -if + Interactive = 0x0000000000000200, // -Interactive | -i + Login = 0x0000000000000400, // -Login | -l + MTA = 0x0000000000000800, // -MTA + NoExit = 0x0000000000001000, // -NoExit | -noe + NoLogo = 0x0000000000002000, // -NoLogo | -nol + NonInteractive = 0x0000000000004000, // -NonInteractive | -noni + NoProfile = 0x0000000000008000, // -NoProfile | -nop + OutputFormat = 0x0000000000010000, // -OutputFormat | -o | -of + SettingsFile = 0x0000000000020000, // -SettingsFile | -settings + SSHServerMode = 0x0000000000040000, // -SSHServerMode | -sshs + SocketServerMode = 0x0000000000080000, // -SocketServerMode | -sockets + ServerMode = 0x0000000000100000, // -ServerMode | -server + NamedPipeServerMode = 0x0000000000200000, // -NamedPipeServerMode | -namedpipes + STA = 0x0000000000400000, // -STA + Version = 0x0000000000800000, // -Version | -v + WindowStyle = 0x0000000001000000, // -WindowStyle | -w + WorkingDirectory = 0x0000000002000000, // -WorkingDirectory | -wd + ConfigurationFile = 0x0000000004000000, // -ConfigurationFile + NoProfileLoadTime = 0x0000000008000000, // -NoProfileLoadTime + CommandWithArgs = 0x0000000010000000, // -CommandWithArgs | -cwa // Enum values for specified ExecutionPolicy EPUnrestricted = 0x0000000100000000, // ExecutionPolicy unrestricted EPRemoteSigned = 0x0000000200000000, // ExecutionPolicy remote signed @@ -241,6 +241,8 @@ internal enum ParameterBitmap : long EPBypass = 0x0000002000000000, // ExecutionPolicy bypass EPUndefined = 0x0000004000000000, // ExecutionPolicy undefined EPIncorrect = 0x0000008000000000, // ExecutionPolicy incorrect + // V2 Socket Server Mode + V2SocketServerMode = 0x0000100000000000, // -V2SocketServerMode | -v2so } internal ParameterBitmap ParametersUsed = 0; @@ -597,6 +599,33 @@ internal bool RemoveWorkingDirectoryTrailingCharacter return _removeWorkingDirectoryTrailingCharacter; } } + + internal DateTimeOffset? UTCTimestamp + { + get + { + AssertArgumentsParsed(); + return _utcTimestamp; + } + } + + internal string? Token + { + get + { + AssertArgumentsParsed(); + return _token; + } + } + + internal bool V2SocketServerMode + { + get + { + AssertArgumentsParsed(); + return _v2SocketServerMode; + } + } #endif #endregion Internal properties @@ -916,6 +945,14 @@ private void ParseHelper(string[] args) _showBanner = false; ParametersUsed |= ParameterBitmap.SocketServerMode; } +#if !UNIX + else if (MatchSwitch(switchKey, "v2socketservermode", "v2so")) + { + _v2SocketServerMode = true; + _showBanner = false; + ParametersUsed |= ParameterBitmap.V2SocketServerMode; + } +#endif else if (MatchSwitch(switchKey, "servermode", "s")) { _serverMode = true; @@ -1176,6 +1213,35 @@ private void ParseHelper(string[] args) { _removeWorkingDirectoryTrailingCharacter = true; } + else if (MatchSwitch(switchKey, "token", "to") ) + { + ++i; + if (i >= args.Length) + { + SetCommandLineError( + string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.MissingMandatoryArgument, "-Token")); + break; + } + + _token = args[i]; + // Not adding anything to ParametersUsed, because it is required with V2 socket server mode + // So, we can assume it based on that bit + } + else if (MatchSwitch(switchKey, "utctimestamp", "utc") ) + { + ++i; + if (i >= args.Length) + { + SetCommandLineError( + string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.MissingMandatoryArgument, "-UTCTimestamp")); + break; + } + + // Parse as iso8601UtcString + _utcTimestamp = DateTimeOffset.ParseExact(args[i], "yyyy-MM-dd'T'HH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind); + // Not adding anything to ParametersUsed, because it is required with V2 socket server mode + // So, we can assume it based on that bit + } #endif else { @@ -1530,6 +1596,9 @@ private bool CollectArgs(string[] args, ref int i) } private bool _socketServerMode; +#if !UNIX + private bool _v2SocketServerMode; +#endif private bool _serverMode; private bool _namedPipeServerMode; private bool _sshServerMode; @@ -1562,6 +1631,10 @@ private bool CollectArgs(string[] args, ref int i) private string? _executionPolicy; private string? _settingsFile; private string? _workingDirectory; +#if !UNIX + private string? _token; + private DateTimeOffset? _utcTimestamp; +#endif #if !UNIX private ProcessWindowStyle? _windowStyle; diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index 8cc7ee00f57..aa5d532da2a 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -198,7 +198,26 @@ internal static int Start( } // Servermode parameter validation check. - if ((s_cpp.ServerMode && s_cpp.NamedPipeServerMode) || (s_cpp.ServerMode && s_cpp.SocketServerMode) || (s_cpp.NamedPipeServerMode && s_cpp.SocketServerMode)) + int serverModeCount = 0; + if (s_cpp.ServerMode) + { + serverModeCount++; + } + if (s_cpp.NamedPipeServerMode) + { + serverModeCount++; + } + if (s_cpp.SocketServerMode) + { + serverModeCount++; + } +#if !UNIX + if (s_cpp.V2SocketServerMode) + { + serverModeCount++; + } +#endif + if (serverModeCount > 1) { s_tracer.TraceError("Conflicting server mode parameters, parameters must be used exclusively."); s_theConsoleHost?.ui.WriteErrorLine(ConsoleHostStrings.ConflictingServerModeParameters); @@ -242,6 +261,34 @@ internal static int Start( configurationName: s_cpp.ConfigurationName); exitCode = 0; } +#if !UNIX + else if (s_cpp.V2SocketServerMode) + { + if (s_cpp.Token == null) + { + s_tracer.TraceError("Token is required for V2SocketServerMode."); + s_theConsoleHost?.ui.WriteErrorLine(string.Format(CultureInfo.CurrentCulture, ConsoleHostStrings.MissingMandatoryParameter, "-Token", "-V2SocketServerMode")); + return ExitCodeBadCommandLineParameter; + } + + if (s_cpp.UTCTimestamp == null) + { + s_tracer.TraceError("UTCTimestamp is required for V2SocketServerMode."); + s_theConsoleHost?.ui.WriteErrorLine(string.Format(CultureInfo.CurrentCulture, ConsoleHostStrings.MissingMandatoryParameter, "-UTCTimestamp", "-v2socketservermode")); + return ExitCodeBadCommandLineParameter; + } + + ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("V2SocketServerMode", s_cpp.ParametersUsedAsDouble); + ProfileOptimization.StartProfile("StartupProfileData-V2SocketServerMode"); + HyperVSocketMediator.Run( + initialCommand: s_cpp.InitialCommand, + configurationName: s_cpp.ConfigurationName, + token: s_cpp.Token, + tokenCreationTime: s_cpp.UTCTimestamp.Value + ); + exitCode = 0; + } +#endif else if (s_cpp.SocketServerMode) { ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("SocketServerMode", s_cpp.ParametersUsedAsDouble); diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx index 34bb696c33c..33445ceebd2 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx @@ -225,4 +225,7 @@ Valid formats are: Invalid ExecutionPolicy value '{0}'. + + An argument is required to be supplied to the '{0}' parameter. + diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx index ce124ec084c..9bc06e0d42f 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx @@ -182,4 +182,10 @@ The current session does not support debugging; execution will continue. Run as Administrator + + PushRunspace can only push a remote runspace. + + + The '{0}' parameter is mandatory and must be specified when using the '{1}' parameter. + diff --git a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs index 7fae8118310..a9de12c3931 100644 --- a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs +++ b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs @@ -7,8 +7,10 @@ using System.Net.Sockets; using System.Text; using System.Threading; +using System.Buffers; using Dbg = System.Diagnostics.Debug; +using SMA = System.Management.Automation; namespace System.Management.Automation.Remoting { @@ -140,6 +142,10 @@ internal sealed class RemoteSessionHyperVSocketServer : IDisposable private readonly object _syncObject; private readonly PowerShellTraceSource _tracer = PowerShellTraceSourceFactory.GetTraceSource(); + // This is to prevent persistent replay attacks. + // it is not meant to ensure all replay attacks are impossible. + private const int MAX_TOKEN_LIFE_MINUTES = 10; + #endregion #region Properties @@ -175,64 +181,74 @@ internal sealed class RemoteSessionHyperVSocketServer : IDisposable public RemoteSessionHyperVSocketServer(bool LoopbackMode) { - // TODO: uncomment below code when .NET supports Hyper-V socket duplication - /* - NamedPipeClientStream clientPipeStream; - byte[] buffer = new byte[1000]; - int bytesRead; - */ _syncObject = new object(); Exception ex = null; try { - // TODO: uncomment below code when .NET supports Hyper-V socket duplication - /* - if (!LoopbackMode) - { - // - // Create named pipe client. - // - using (clientPipeStream = new NamedPipeClientStream(".", - "PS_VMSession", - PipeDirection.InOut, - PipeOptions.None, - TokenImpersonationLevel.None)) - { - // - // Connect to named pipe server. - // - clientPipeStream.Connect(10*1000); - - // - // Read LPWSAPROTOCOL_INFO. - // - bytesRead = clientPipeStream.Read(buffer, 0, 1000); - } - } + Guid serviceId = new Guid("a5201c21-2770-4c11-a68e-f182edb29220"); // HV_GUID_VM_SESSION_SERVICE_ID_2 + Guid loopbackId = new Guid("e0e16197-dd56-4a10-9195-5ee7a155a838"); // HV_GUID_LOOPBACK + Guid parentId = new Guid("a42e7cda-d03f-480c-9cc2-a4de20abb878"); // HV_GUID_PARENT + Guid vmId = LoopbackMode ? loopbackId : parentId; + HyperVSocketEndPoint endpoint = new HyperVSocketEndPoint(HyperVSocketEndPoint.AF_HYPERV, vmId, serviceId); + + Socket listenSocket = new Socket(endpoint.AddressFamily, SocketType.Stream, (System.Net.Sockets.ProtocolType)1); + listenSocket.Bind(endpoint); + + listenSocket.Listen(1); + HyperVSocket = listenSocket.Accept(); + + Stream = new NetworkStream(HyperVSocket, true); + + // Create reader/writer streams. + TextReader = new StreamReader(Stream); + TextWriter = new StreamWriter(Stream); + TextWriter.AutoFlush = true; // - // Create duplicate socket. + // listenSocket is not closed when it goes out of scope here. Sometimes it is + // closed later in this thread, while other times it is not closed at all. This will + // cause problem when we set up a second PowerShell Direct session. Let's + // explicitly close listenSocket here for safe. // - byte[] protocolInfo = new byte[bytesRead]; - Array.Copy(buffer, protocolInfo, bytesRead); + if (listenSocket != null) + { + try { listenSocket.Dispose(); } + catch (ObjectDisposedException) { } + } + } + catch (Exception e) + { + ex = e; + } - SocketInformation sockInfo = new SocketInformation(); - sockInfo.ProtocolInformation = protocolInfo; - sockInfo.Options = SocketInformationOptions.Connected; + if (ex != null) + { + Dbg.Fail("Unexpected error in RemoteSessionHyperVSocketServer."); - socket = new Socket(sockInfo); - if (socket == null) - { - Dbg.Assert(false, "Unexpected error in RemoteSessionHyperVSocketServer."); + // Unexpected error. + string errorMessage = !string.IsNullOrEmpty(ex.Message) ? ex.Message : string.Empty; + _tracer.WriteMessage("RemoteSessionHyperVSocketServer", "RemoteSessionHyperVSocketServer", Guid.Empty, + "Unexpected error in constructor: {0}", errorMessage); - tracer.WriteMessage("RemoteSessionHyperVSocketServer", "RemoteSessionHyperVSocketServer", Guid.Empty, - "Unexpected error in constructor: {0}", "socket duplication failure"); - } - */ + throw new PSInvalidOperationException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.RemoteSessionHyperVSocketServerConstructorFailure), + ex, + nameof(PSRemotingErrorId.RemoteSessionHyperVSocketServerConstructorFailure), + ErrorCategory.InvalidOperation, + null); + } + } + + public RemoteSessionHyperVSocketServer(bool LoopbackMode, string token, DateTimeOffset tokenCreationTime) + { + _syncObject = new object(); - // TODO: remove below 6 lines of code when .NET supports Hyper-V socket duplication + Exception ex = null; + + try + { Guid serviceId = new Guid("a5201c21-2770-4c11-a68e-f182edb29220"); // HV_GUID_VM_SESSION_SERVICE_ID_2 HyperVSocketEndPoint endpoint = new HyperVSocketEndPoint(HyperVSocketEndPoint.AF_HYPERV, Guid.Empty, serviceId); @@ -242,6 +258,31 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode) listenSocket.Listen(1); HyperVSocket = listenSocket.Accept(); + TimeSpan timeout = TimeSpan.FromMinutes(MAX_TOKEN_LIFE_MINUTES); + DateTimeOffset timeoutExpiry = tokenCreationTime.Add(timeout); + DateTimeOffset now = DateTimeOffset.UtcNow; + + // Calculate remaining time and create cancellation token + TimeSpan remainingTime = timeoutExpiry - now; + + // Check if the token has already expired + if (remainingTime <= TimeSpan.Zero) + { + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential, "Token has expired")); + } + + // Set socket timeout for receive operations to prevent indefinite blocking + int timeoutMs = (int)remainingTime.TotalMilliseconds; + HyperVSocket.ReceiveTimeout = timeoutMs; + HyperVSocket.SendTimeout = timeoutMs; + + // Create a cancellation token that will be cancelled when the timeout expires + using var cancellationTokenSource = new CancellationTokenSource(remainingTime); + CancellationToken cancellationToken = cancellationTokenSource.Token; + + ValidateToken(HyperVSocket, token, cancellationToken); + Stream = new NetworkStream(HyperVSocket, true); // Create reader/writer streams. @@ -257,8 +298,13 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode) // if (listenSocket != null) { - try { listenSocket.Dispose(); } - catch (ObjectDisposedException) { } + try + { + listenSocket.Dispose(); + } + catch (ObjectDisposedException) + { + } } } catch (Exception e) @@ -272,8 +318,12 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode) // Unexpected error. string errorMessage = !string.IsNullOrEmpty(ex.Message) ? ex.Message : string.Empty; - _tracer.WriteMessage("RemoteSessionHyperVSocketServer", "RemoteSessionHyperVSocketServer", Guid.Empty, - "Unexpected error in constructor: {0}", errorMessage); + _tracer.WriteMessage( + "RemoteSessionHyperVSocketServer", + "RemoteSessionHyperVSocketServer", + Guid.Empty, + "Unexpected error in constructor: {0}", + errorMessage); throw new PSInvalidOperationException( PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.RemoteSessionHyperVSocketServerConstructorFailure), @@ -283,7 +333,6 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode) null); } } - #endregion #region IDisposable @@ -333,6 +382,79 @@ public void Dispose() } #endregion + + /// + /// Validates the token received from the client over the HyperVSocket. + /// Throws PSDirectException if the token is invalid or not received in time. + /// + /// The connected HyperVSocket. + /// The expected token string. + /// Cancellation token for timeout handling. + internal static void ValidateToken(Socket socket, string token, CancellationToken cancellationToken = default) + { + // Check for cancellation before starting validation + cancellationToken.ThrowIfCancellationRequested(); + + // We should move to this pattern and + // in the tests I found I needed to get a bigger buffer than the token length + // and test length of the received data similar to this pattern. + string responseString = RemoteSessionHyperVSocketClient.ReceiveResponse(socket, RemoteSessionHyperVSocketClient.VERSION_REQUEST.Length + 4); + if (string.IsNullOrEmpty(responseString) || responseString.Length != RemoteSessionHyperVSocketClient.VERSION_REQUEST.Length) + { + socket.Send("FAIL"u8); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Client", "Version Request: " + responseString)); + } + + cancellationToken.ThrowIfCancellationRequested(); + + socket.Send(Encoding.UTF8.GetBytes(RemoteSessionHyperVSocketClient.CLIENT_VERSION)); + responseString = RemoteSessionHyperVSocketClient.ReceiveResponse(socket, RemoteSessionHyperVSocketClient.CLIENT_VERSION.Length + 4); + + // In the future we may need to handle different versions, differently. + // For now, we are just checking that we exchanged versions correctly. + if (string.IsNullOrEmpty(responseString) || !responseString.StartsWith(RemoteSessionHyperVSocketClient.VERSION_PREFIX, StringComparison.Ordinal)) + { + socket.Send("FAIL"u8); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Client", "Version Response: " + responseString)); + } + + cancellationToken.ThrowIfCancellationRequested(); + + socket.Send("PASS"u8); + + // The client should send the token in the format TOKEN + // the token should be up to 256 bits, which is less than 50 characters. + // I'll double that to 100 characters to be safe, plus the "TOKEN " prefix. + // So we expect a response of length 6 + 100 = 106 characters. + responseString = RemoteSessionHyperVSocketClient.ReceiveResponse(socket, 110); + + cancellationToken.ThrowIfCancellationRequested(); + + if (string.IsNullOrEmpty(responseString) || !responseString.StartsWith("TOKEN ", StringComparison.Ordinal)) + { + socket.Send("FAIL"u8); + // If the response is not in the expected format, we throw an exception. + // This is a failure to authenticate the client. + // don't send this response for risk of information disclosure. + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Client", "Token Response")); + } + + // Extract the token from the response. + string responseToken = responseString.Substring(6).Trim(); + + if (!string.Equals(responseToken, token, StringComparison.Ordinal)) + { + socket.Send("FAIL"u8); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential)); + } + + // Acknowledge the token is valid with "PASS". + socket.Send("PASS"u8); + } } internal sealed class RemoteSessionHyperVSocketClient : IDisposable @@ -340,7 +462,15 @@ internal sealed class RemoteSessionHyperVSocketClient : IDisposable #region Members private readonly object _syncObject; - private readonly PowerShellTraceSource _tracer = PowerShellTraceSourceFactory.GetTraceSource(); + + #region tracer + /// + /// An instance of the PSTraceSource class used for trace output. + /// + [SMA.TraceSource("RemoteSessionHyperVSocketClient", "Class that has PowerShell Direct Client implementation")] + private static readonly PSTraceSource s_tracer = PSTraceSource.GetTracer("RemoteSessionHyperVSocketClient", "Class that has PowerShell Direct Client implementation"); + + #endregion tracer private static readonly ManualResetEvent s_connectDone = new ManualResetEvent(false); @@ -354,6 +484,14 @@ internal sealed class RemoteSessionHyperVSocketClient : IDisposable #endregion + #region version constants + + internal const string VERSION_REQUEST = "VERSION"; + internal const string CLIENT_VERSION = "VERSION_2"; + internal const string VERSION_PREFIX = "VERSION_"; + + #endregion + #region Properties /// @@ -364,7 +502,7 @@ internal sealed class RemoteSessionHyperVSocketClient : IDisposable /// /// Returns the Hyper-V socket object. /// - public Socket HyperVSocket { get; } + public Socket HyperVSocket { get; private set; } /// /// Returns the network stream object. @@ -381,6 +519,37 @@ internal sealed class RemoteSessionHyperVSocketClient : IDisposable /// public StreamWriter TextWriter { get; private set; } + /// + /// True if the client is a Hyper-V container. + /// + public bool IsContainer { get; } + + /// + /// True if the client is using backwards compatible mode. + /// This is used to determine if the client should use + /// the backwards compatible or not. + /// In modern mode, the vmicvmsession service will + /// hand off the socket to the PowerShell process + /// inside the VM automatically. + /// In backwards compatible mode, the vmicvmsession + /// service create a new socket to the PowerShell process + /// inside the VM. + /// + public bool UseBackwardsCompatibleMode { get; private set; } + + /// + /// The authentication token used for the session. + /// This token is provided by the broker and provided to the server to authenticate the server session. + /// This protocol uses two connections: + /// 1. The first is to the broker or vmicvmsession service to exchange credentials and configuration. + /// The broker will respond with an authentication token. The broker also launches a PowerShell + /// server process with the authentication token. + /// 2. The second is to the server process, that was launched by the broker, + /// inside the VM, which uses the authentication token to verify that the client is the same client + /// that connected to the broker. + /// + public string AuthenticationToken { get; private set; } + /// /// Returns true if object is currently disposed. /// @@ -393,7 +562,9 @@ internal sealed class RemoteSessionHyperVSocketClient : IDisposable internal RemoteSessionHyperVSocketClient( Guid vmId, bool isFirstConnection, - bool isContainer = false) + bool useBackwardsCompatibleMode = false, + bool isContainer = false, + string authenticationToken = null) { Guid serviceId; @@ -412,28 +583,16 @@ internal RemoteSessionHyperVSocketClient( EndPoint = new HyperVSocketEndPoint(HyperVSocketEndPoint.AF_HYPERV, vmId, serviceId); - HyperVSocket = new Socket(EndPoint.AddressFamily, SocketType.Stream, (System.Net.Sockets.ProtocolType)1); + IsContainer = isContainer; - // - // We need to call SetSocketOption() in order to set up Hyper-V socket connection between container host and Hyper-V container. - // Here is the scenario: the Hyper-V container is inside a utility vm, which is inside the container host - // - if (isContainer) - { - var value = new byte[sizeof(uint)]; - value[0] = 1; + UseBackwardsCompatibleMode = useBackwardsCompatibleMode; - try - { - HyperVSocket.SetSocketOption((System.Net.Sockets.SocketOptionLevel)HV_PROTOCOL_RAW, - (System.Net.Sockets.SocketOptionName)HVSOCKET_CONTAINER_PASSTHRU, - (byte[])value); - } - catch - { - throw new PSDirectException( - PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.RemoteSessionHyperVSocketClientConstructorSetSocketOptionFailure)); - } + if (!isFirstConnection && !useBackwardsCompatibleMode && !string.IsNullOrEmpty(authenticationToken)) + { + // If this is not the first connection and we are using backwards compatible mode, + // we should not set the authentication token here. + // The authentication token will be set during the Connect method. + AuthenticationToken = authenticationToken; } } @@ -489,6 +648,81 @@ public void Dispose() #region Public Methods + private void ShutdownSocket() + { + if (HyperVSocket != null) + { + // Ensure the socket is disposed properly. + try + { + s_tracer.WriteLine("ShutdownSocket: Disposing of the HyperVSocket."); + HyperVSocket.Dispose(); + } + catch (Exception ex) + { + s_tracer.WriteLine("ShutdownSocket: Exception while disposing the socket: {0}", ex.Message); + } + } + + // Dispose of the existing stream if it exists. + if (Stream != null) + { + try + { + Stream.Dispose(); + } + catch (Exception ex) + { + s_tracer.WriteLine("ShutdownSocket: Exception while disposing the stream: {0}", ex.Message); + } + } + } + + /// + /// Recreates the HyperVSocket and connects it to the endpoint, updating the Stream if successful. + /// + private bool ConnectSocket() + { + HyperVSocket = new Socket(EndPoint.AddressFamily, SocketType.Stream, (System.Net.Sockets.ProtocolType)1); + + // + // We need to call SetSocketOption() in order to set up Hyper-V socket connection between container host and Hyper-V container. + // Here is the scenario: the Hyper-V container is inside a utility vm, which is inside the container host + // + if (IsContainer) + { + var value = new byte[sizeof(uint)]; + value[0] = 1; + + try + { + HyperVSocket.SetSocketOption( + (System.Net.Sockets.SocketOptionLevel)HV_PROTOCOL_RAW, + (System.Net.Sockets.SocketOptionName)HVSOCKET_CONTAINER_PASSTHRU, + value); + } + catch + { + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.RemoteSessionHyperVSocketClientConstructorSetSocketOptionFailure)); + } + } + + s_tracer.WriteLine("Connect: Client connecting, to {0}; isContainer: {1}.", EndPoint.ServiceId.ToString(), IsContainer); + HyperVSocket.Connect(EndPoint); + + // Check if the socket is connected. + // If it is connected, create a NetworkStream. + if (HyperVSocket.Connected) + { + s_tracer.WriteLine("Connect: Client connected, to {0}; isContainer: {1}.", EndPoint.ServiceId.ToString(), IsContainer); + Stream = new NetworkStream(HyperVSocket, true); + return true; + } + + return false; + } + /// /// Connect to Hyper-V socket server. This is a blocking call until a /// connection occurs or the timeout time has elapsed. @@ -516,100 +750,51 @@ public bool Connect( } } - HyperVSocket.Connect(EndPoint); - - if (HyperVSocket.Connected) + if (ConnectSocket()) { - _tracer.WriteMessage("RemoteSessionHyperVSocketClient", "Connect", Guid.Empty, - "Client connected."); - - Stream = new NetworkStream(HyperVSocket, true); - if (isFirstConnection) { - if (string.IsNullOrEmpty(networkCredential.Domain)) + var exchangeResult = ExchangeCredentialsAndConfiguration(networkCredential, configurationName, HyperVSocket, this.UseBackwardsCompatibleMode); + if (!exchangeResult.success) { - networkCredential.Domain = "localhost"; - } + // We will not block here for a container because a container does not have a broker. + if (IsRequirePsDirectAuthenticationEnabled(@"SOFTWARE\\Microsoft\\PowerShell", Microsoft.Win32.RegistryHive.LocalMachine)) + { + s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: RequirePsDirectAuthentication is enabled, requiring latest transport version."); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVNegotiationFailed)); + } - bool emptyPassword = string.IsNullOrEmpty(networkCredential.Password); - bool emptyConfiguration = string.IsNullOrEmpty(configurationName); - - byte[] domain = Encoding.Unicode.GetBytes(networkCredential.Domain); - byte[] userName = Encoding.Unicode.GetBytes(networkCredential.UserName); - byte[] password = Encoding.Unicode.GetBytes(networkCredential.Password); - byte[] response = new byte[4]; // either "PASS" or "FAIL" - string responseString; - - // - // Send credential to VM so that PowerShell process inside VM can be - // created under the correct security context. - // - HyperVSocket.Send(domain); - HyperVSocket.Receive(response); - - HyperVSocket.Send(userName); - HyperVSocket.Receive(response); - - // - // We cannot simply send password because if it is empty, - // the vmicvmsession service in VM will block in recv method. - // - if (emptyPassword) - { - HyperVSocket.Send("EMPTYPW"u8); - HyperVSocket.Receive(response); - responseString = Encoding.ASCII.GetString(response); - } - else - { - HyperVSocket.Send("NONEMPTYPW"u8); - HyperVSocket.Receive(response); + this.UseBackwardsCompatibleMode = true; + s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: Using backwards compatible mode."); - HyperVSocket.Send(password); - HyperVSocket.Receive(response); - responseString = Encoding.ASCII.GetString(response); + // If the first connection fails in modern mode, fall back to backwards compatible mode. + ShutdownSocket(); // will terminate the broker + ConnectSocket(); // restart the broker + exchangeResult = ExchangeCredentialsAndConfiguration(networkCredential, configurationName, HyperVSocket, this.UseBackwardsCompatibleMode); + if (!exchangeResult.success) + { + s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: Failed to exchange credentials and configuration in backwards compatible mode."); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Broker", "Credential")); + } } - - // - // There are 3 cases for the responseString received above. - // - "FAIL": credential is invalid - // - "PASS": credential is valid, but PowerShell Direct in VM does not support configuration (Server 2016 TP4 and before) - // - "CONF": credential is valid, and PowerShell Direct in VM supports configuration (Server 2016 TP5 and later) - // - - // - // Credential is invalid. - // - if (string.Equals(responseString, "FAIL", StringComparison.Ordinal)) + else { - HyperVSocket.Send(response); - - throw new PSDirectException( - PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential)); + this.AuthenticationToken = exchangeResult.authenticationToken; } + } - // - // If PowerShell Direct in VM supports configuration, send configuration name. - // - if (string.Equals(responseString, "CONF", StringComparison.Ordinal)) + if (!isFirstConnection) + { + if (!this.UseBackwardsCompatibleMode) { - if (emptyConfiguration) - { - HyperVSocket.Send("EMPTYCF"u8); - } - else - { - HyperVSocket.Send("NONEMPTYCF"u8); - HyperVSocket.Receive(response); - - byte[] configName = Encoding.Unicode.GetBytes(configurationName); - HyperVSocket.Send(configName); - } + s_tracer.WriteLine("Connect-Server: Performing transport version and token exchange for Hyper-V socket. isFirstConnection: {0}, UseBackwardsCompatibleMode: {1}", isFirstConnection, this.UseBackwardsCompatibleMode); + RemoteSessionHyperVSocketClient.PerformTransportVersionAndTokenExchange(HyperVSocket, this.AuthenticationToken); } else { - HyperVSocket.Send(response); + s_tracer.WriteLine("Connect-Server: Skipping transport version and token exchange for backwards compatible mode."); } } @@ -621,8 +806,7 @@ public bool Connect( } else { - _tracer.WriteMessage("RemoteSessionHyperVSocketClient", "Connect", Guid.Empty, - "Client unable to connect."); + s_tracer.WriteLine("Connect: Client unable to connect."); result = false; } @@ -630,12 +814,318 @@ public bool Connect( return result; } + /// + /// Performs the transport version and token exchange sequence for the Hyper-V socket connection. + /// Throws PSDirectException on failure. + /// + /// The socket to use for communication. + /// The authentication token to send. + public static void PerformTransportVersionAndTokenExchange(Socket socket, string authenticationToken) + { + if (string.IsNullOrEmpty(authenticationToken)) + { + s_tracer.WriteLine("PerformTransportVersionAndTokenExchange: Authentication token is null or empty. Aborting transport version and token exchange."); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential)); + } + + socket.Send(Encoding.UTF8.GetBytes(VERSION_REQUEST)); + string responseStr = ReceiveResponse(socket, 16); + + // Check if the response starts with the expected version prefix. + // We will rely on the broker to determine if the two can communicate. + // At least, for now. + if (!responseStr.StartsWith(VERSION_PREFIX, StringComparison.Ordinal)) + { + s_tracer.WriteLine("PerformTransportVersionAndTokenExchange: Server responded with an invalid response of {0}. Notifying the transport manager to downgrade if allowed.", responseStr); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Server", "TransportVersion")); + } + + socket.Send(Encoding.UTF8.GetBytes(CLIENT_VERSION)); + string response = ReceiveResponse(socket, 4); // either "PASS" or "FAIL" + + if (!string.Equals(response, "PASS", StringComparison.Ordinal)) + { + s_tracer.WriteLine( + "PerformTransportVersionAndTokenExchange: Transport version negotiation with server failed. Response: {0}", response); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Server", "TransportVersion")); + } + + byte[] tokenBytes = Encoding.UTF8.GetBytes("TOKEN " + authenticationToken); + socket.Send(tokenBytes); + + // This is the opportunity for the server to tell the client to go away. + string tokenResponse = ReceiveResponse(socket, 256); // either "PASS" or "FAIL", but get a little more buffer to allow for better error in the future + if (!string.Equals(tokenResponse, "PASS", StringComparison.Ordinal)) + { + s_tracer.WriteLine( + "PerformTransportVersionAndTokenExchange: Server Authentication Token exchange failed. Response: {0}", tokenResponse); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential)); + } + } + + /// + /// Checks if the registry key RequirePsDirectAuthentication is set to 1. + /// Returns true if fallback should be aborted. + /// Uses the 64-bit registry view on 64-bit systems to ensure consistent behavior regardless of process architecture. + /// On 32-bit systems, uses the default registry view since there is no WOW64 redirection. + /// + internal static bool IsRequirePsDirectAuthenticationEnabled(string keyPath, Microsoft.Win32.RegistryHive registryHive) + { + const string regValueName = "RequirePsDirectAuthentication"; + + try + { + Microsoft.Win32.RegistryView registryView = Environment.Is64BitOperatingSystem + ? Microsoft.Win32.RegistryView.Registry64 + : Microsoft.Win32.RegistryView.Default; + + using (Microsoft.Win32.RegistryKey baseKey = Microsoft.Win32.RegistryKey.OpenBaseKey( + registryHive, + registryView)) + { + using (Microsoft.Win32.RegistryKey key = baseKey.OpenSubKey(keyPath)) + { + if (key != null) + { + var value = key.GetValue(regValueName); + if (value is int intValue && intValue != 0) + { + return true; + } + } + + return false; + } + } + } + catch (Exception regEx) + { + s_tracer.WriteLine("IsRequirePsDirectAuthenticationEnabled: Exception while checking registry key: {0}", regEx.Message); + return false; // If we cannot read the registry, assume the feature is not enabled. + } + } + + /// + /// Handles credential and configuration exchange with the VM for the first connection. + /// + public static (bool success, string authenticationToken) ExchangeCredentialsAndConfiguration(NetworkCredential networkCredential, string configurationName, Socket HyperVSocket, bool useBackwardsCompatibleMode) + { + // Encoding for the Hyper-V socket communication + // To send the domain, username, password, and configuration name, use UTF-16 (Encoding.Unicode) + // All other sends use UTF-8 (Encoding.UTF8) + // Receiving uses ASCII encoding + // NOT CONFUSING AT ALL + + if (!useBackwardsCompatibleMode) + { + HyperVSocket.Send(Encoding.UTF8.GetBytes(VERSION_REQUEST)); + // vmicvmsession service in VM will respond with "VERSION_2" or newer + // Version 1 protocol will respond with "PASS" or "FAIL" + // Receive the response and check for VERSION_2 or newer + string responseStr = ReceiveResponse(HyperVSocket, 16); + if (!responseStr.StartsWith(VERSION_PREFIX, StringComparison.Ordinal)) + { + s_tracer.WriteLine("When asking for version the server responded with an invalid response of {0}.", responseStr); + s_tracer.WriteLine("Session is invalid, continuing session with a fake user to close the session with the broker for stability."); + // If not the new protocol, finish the conversation + // Send a fake user + // Use ? <> that are illegal in user names so no one can create the user + string probeUserName = "?"; // must be less than or equal to 20 characters for Windows Server 2016 + s_tracer.WriteLine("probeUserName (static): length: {0}", probeUserName.Length); + SendUserData(probeUserName, HyperVSocket); + responseStr = ReceiveResponse(HyperVSocket, 4); // either "PASS" or "FAIL" + s_tracer.WriteLine("When sending user {0}.", responseStr); + + // Send that the password is empty + HyperVSocket.Send("EMPTYPW"u8); + responseStr = ReceiveResponse(HyperVSocket, 4); // either "CONF", "PASS" or "FAIL" + s_tracer.WriteLine("When sending EMPTYPW: {0}.", responseStr); // server responds with FAIL so we respond with FAIL and the conversation is done + HyperVSocket.Send("FAIL"u8); + + s_tracer.WriteLine("Notifying the transport manager to downgrade if allowed."); + // end new code + return (false, null); + } + + HyperVSocket.Send(Encoding.UTF8.GetBytes(CLIENT_VERSION)); + ReceiveResponse(HyperVSocket, 4); // either "PASS" or "FAIL" + } + + if (string.IsNullOrEmpty(networkCredential.Domain)) + { + networkCredential.Domain = "localhost"; + } + + System.Security.SecureString securePassword = networkCredential.SecurePassword; + int passwordLength = securePassword.Length; + bool emptyPassword = (passwordLength <= 0); + bool emptyConfiguration = string.IsNullOrEmpty(configurationName); + + string responseString; + + // Send credential to VM so that PowerShell process inside VM can be + // created under the correct security context. + SendUserData(networkCredential.Domain, HyperVSocket); + ReceiveResponse(HyperVSocket, 4); // only "PASS" is expected + + SendUserData(networkCredential.UserName, HyperVSocket); + ReceiveResponse(HyperVSocket, 4); // only "PASS" is expected + + // We cannot simply send password because if it is empty, + // the vmicvmsession service in VM will block in recv method. + if (emptyPassword) + { + HyperVSocket.Send("EMPTYPW"u8); + responseString = ReceiveResponse(HyperVSocket, 4); // either "CONF", "PASS" or "FAIL" (note, "PASS" is not used in VERSION_2 or newer mode) + } + else + { + HyperVSocket.Send("NONEMPTYPW"u8); + ReceiveResponse(HyperVSocket, 4); // only "PASS" is expected + + // Get the password bytes from the SecureString, send them, and then zero out the byte array. + byte[] passwordBytes = Microsoft.PowerShell.SecureStringHelper.GetData(securePassword); + try + { + HyperVSocket.Send(passwordBytes); + } + finally + { + // Zero out the byte array for security + Array.Clear(passwordBytes); + } + + responseString = ReceiveResponse(HyperVSocket, 4); // either "CONF", "PASS" or "FAIL" (note, "PASS" is not used in VERSION_2 or newer mode) + } + + // Check for invalid response from server + if (!string.Equals(responseString, "FAIL", StringComparison.Ordinal) && + !string.Equals(responseString, "PASS", StringComparison.Ordinal) && + !string.Equals(responseString, "CONF", StringComparison.Ordinal)) + { + s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: Server responded with an invalid response of {0} for credentials.", responseString); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Broker", "Credential")); + } + + // Credential is invalid. + if (string.Equals(responseString, "FAIL", StringComparison.Ordinal)) + { + HyperVSocket.Send("FAIL"u8); + // should we be doing this? Disabling the test for now + // HyperVSocket.Shutdown(SocketShutdown.Both); + s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: Server responded with FAIL for credentials."); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential)); + } + + // If PowerShell Direct in VM supports configuration, send configuration name. + if (string.Equals(responseString, "CONF", StringComparison.Ordinal)) + { + if (emptyConfiguration) + { + HyperVSocket.Send("EMPTYCF"u8); + } + else + { + HyperVSocket.Send("NONEMPTYCF"u8); + ReceiveResponse(HyperVSocket, 4); // only "PASS" is expected + + SendUserData(configurationName, HyperVSocket); + } + } + else + { + HyperVSocket.Send("PASS"u8); + } + + if (!useBackwardsCompatibleMode) + { + // Receive the token from the server + // Getting 1024 bytes because it is well above the expected token size + // The expected size at the time of writing this would be about 50 based64 characters, + // plus the 6 characters for the "TOKEN " prefix. + // The 50 character size is designed to last 10 years of cryptographic changes. + // Since the broker completely controls the cryptographic portion here, + // allowing a significant larger size, allows the broker to make almost arbitrary changes, + // without breaking the client. + string token = ReceiveResponse(HyperVSocket, 1024); // either "PASS" or "FAIL" + if (token == null || !token.StartsWith("TOKEN ", StringComparison.Ordinal)) + { + s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: Server did not respond with a valid token. Response: {0}", token); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Broker", "Token " + token)); + } + + token = token.Substring(6); // remove "TOKEN " prefix + + HyperVSocket.Send("PASS"u8); // acknowledge the token + return (true, token); + } + + return (true, null); + } + public void Close() { Stream.Dispose(); HyperVSocket.Dispose(); } + /// + /// Receives a response from the socket and decodes it. + /// + /// The socket to receive from. + /// The size of the buffer to use for receiving data. + /// The decoded response string. + internal static string ReceiveResponse(Socket socket, int bufferSize) + { + System.Buffers.ArrayPool pool = System.Buffers.ArrayPool.Shared; + byte[] responseBuffer = pool.Rent(bufferSize); + int bytesReceived = 0; + try + { + bytesReceived = socket.Receive(responseBuffer); + if (bytesReceived == 0) + { + return null; + } + + string response = Encoding.ASCII.GetString(responseBuffer, 0, bytesReceived); + + // Handle null terminators and log if found + if (response.EndsWith('\0')) + { + int originalLength = response.Length; + response = response.TrimEnd('\0'); + // Cannot log actual response, because we don't know if it is sensitive + s_tracer.WriteLine( + "ReceiveResponse: Removed null terminator(s). Original length: {0}, New length: {1}", + originalLength, + response.Length); + } + + return response; + } + finally + { + pool.Return(responseBuffer); + } + } + + /// + /// Sends user data (domain, username, etc.) over the HyperVSocket using Unicode encoding. + /// + private static void SendUserData(string data, Socket socket) + { + // this encodes the data in UTF-16 (Unicode) + byte[] buffer = Encoding.Unicode.GetBytes(data); + socket.Send(buffer); + } #endregion } } diff --git a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs index 96a8b833885..d9532c8691a 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs @@ -1014,7 +1014,7 @@ internal void OnCloseTimeOutTimerElapsed(object source) } #endregion - + #region Protected Methods /// @@ -1544,8 +1544,9 @@ internal VMHyperVSocketClientSessionTransportManager( /// public override void CreateAsync() { - _client = new RemoteSessionHyperVSocketClient(_vmGuid, true); - if (!_client.Connect(_networkCredential, _configurationName, true)) + // isFirstConnection: true - specifies to use VM_SESSION_SERVICE_ID socket. + _client = new RemoteSessionHyperVSocketClient(_vmGuid, useBackwardsCompatibleMode: false, isFirstConnection: true); + if (!_client.Connect(_networkCredential, _configurationName, isFirstConnection: true)) { _client.Dispose(); throw new PSInvalidOperationException( @@ -1555,11 +1556,14 @@ public override void CreateAsync() ErrorCategory.InvalidOperation, null); } + bool useBackwardsCompatibleMode = _client.UseBackwardsCompatibleMode; + string token = _client.AuthenticationToken; - // TODO: remove below 3 lines when Hyper-V socket duplication is supported in .NET framework. _client.Dispose(); - _client = new RemoteSessionHyperVSocketClient(_vmGuid, false); - if (!_client.Connect(_networkCredential, _configurationName, false)) + + // isFirstConnection: false - specifies to use the SESSION_SERVICE_ID_2 socket. + _client = new RemoteSessionHyperVSocketClient(_vmGuid, useBackwardsCompatibleMode: useBackwardsCompatibleMode, isFirstConnection: false, authenticationToken: token); + if (!_client.Connect(_networkCredential, _configurationName, isFirstConnection: false)) { _client.Dispose(); throw new PSInvalidOperationException( @@ -1617,7 +1621,9 @@ internal ContainerHyperVSocketClientSessionTransportManager( /// public override void CreateAsync() { - _client = new RemoteSessionHyperVSocketClient(_targetGuid, false, true); + // Container scenario is not working. + // When we fix it we need to setup the token in ContainerConnectionInfo and use it here. + _client = new RemoteSessionHyperVSocketClient(_targetGuid, isFirstConnection: false, useBackwardsCompatibleMode: false, isContainer: true); if (!_client.Connect(null, string.Empty, false)) { _client.Dispose(); @@ -1716,7 +1722,7 @@ public override void CreateAsync() // Start connection timeout timer if requested. // Timer callback occurs only once after timeout time. _connectionTimer = new Timer( - callback: (_) => + callback: (_) => { if (_connectionEstablished) { @@ -2505,7 +2511,7 @@ internal OutOfProcessServerSessionTransportManager(OutOfProcessTextWriter outWri _stdErrWriter = errWriter; _cmdTransportManagers = new Dictionary(); - this.WSManTransportErrorOccured += (object sender, TransportErrorOccuredEventArgs e) => + this.WSManTransportErrorOccured += (object sender, TransportErrorOccuredEventArgs e) => { string msg = e.Exception.TransportMessage ?? e.Exception.InnerException?.Message ?? string.Empty; _stdErrWriter.WriteLine(StringUtil.Format(RemotingErrorIdStrings.RemoteTransportError, msg)); diff --git a/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs b/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs index 14b0240858b..6c794e21b24 100644 --- a/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs +++ b/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs @@ -635,6 +635,16 @@ private HyperVSocketMediator() originalStdErr = new HyperVSocketErrorTextWriter(_hypervSocketServer.TextWriter); } + private HyperVSocketMediator(string token, + DateTimeOffset tokenCreationTime) + : base(false) + { + _hypervSocketServer = new RemoteSessionHyperVSocketServer(false, token: token, tokenCreationTime: tokenCreationTime); + + originalStdIn = _hypervSocketServer.TextReader; + originalStdOut = new OutOfProcessTextWriter(_hypervSocketServer.TextWriter); + originalStdErr = new HyperVSocketErrorTextWriter(_hypervSocketServer.TextWriter); + } #endregion #region Static Methods @@ -656,6 +666,24 @@ internal static void Run( configurationFile: null); } + internal static void Run( + string initialCommand, + string configurationName, + string token, + DateTimeOffset tokenCreationTime) + { + lock (SyncObject) + { + s_instance = new HyperVSocketMediator(token, tokenCreationTime); + } + + s_instance.Start( + initialCommand: initialCommand, + cryptoHelper: new PSRemotingCryptoHelperServer(), + workingDirectory: null, + configurationName: configurationName, + configurationFile: null); + } #endregion } diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx index da56deb4598..05f12b0c29b 100644 --- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx +++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx @@ -1723,4 +1723,10 @@ SSH client process terminated before connection could be established. Failed to get Hyper-V VM State. The value was of the type {0} but was expected to be Microsoft.HyperV.PowerShell.VMState or System.String. + + Hyper-V {0} sent an invalid {1} response during the connection negotiation. + + + Negotiating a secure connection to Hyper-V failed. Make sure the Host and Guest are updated with all relevant Microsoft Updates. + diff --git a/test/xUnit/csharp/test_CommandLineParser.cs b/test/xUnit/csharp/test_CommandLineParser.cs index 5025584d6ac..01f572d230d 100644 --- a/test/xUnit/csharp/test_CommandLineParser.cs +++ b/test/xUnit/csharp/test_CommandLineParser.cs @@ -48,6 +48,9 @@ public static void TestDefaults() Assert.False(cpp.ShowVersion); Assert.False(cpp.SkipProfiles); Assert.False(cpp.SocketServerMode); +#if !UNIX + Assert.False(cpp.V2SocketServerMode); +#endif Assert.False(cpp.SSHServerMode); if (Platform.IsWindows) { @@ -336,6 +339,25 @@ public static void TestParameter_SocketServerMode(params string[] commandLine) Assert.Null(cpp.ErrorMessage); } +#if !UNIX + [Theory] + [InlineData("-v2socketservermode", "-token", "natoheusatoehusnatoeu", "-utctimestamp", "2023-10-01T12:00:00Z")] + [InlineData("-v2so", "-token", "asentuhasoneuthsaoe", "-utctimestamp", "2025-06-09T12:00:00Z")] + public static void TestParameter_V2SocketServerMode(params string[] commandLine) + { + var cpp = new CommandLineParameterParser(); + + cpp.Parse(commandLine); + + Assert.False(cpp.AbortStartup); + Assert.True(cpp.NoExit); + Assert.False(cpp.ShowShortHelp); + Assert.False(cpp.ShowBanner); + Assert.True(cpp.V2SocketServerMode); + Assert.Null(cpp.ErrorMessage); + } +#endif + [Theory] [InlineData("-servermode")] [InlineData("-s")] diff --git a/test/xUnit/csharp/test_RemoteHyperV.cs b/test/xUnit/csharp/test_RemoteHyperV.cs new file mode 100644 index 00000000000..f694f6894df --- /dev/null +++ b/test/xUnit/csharp/test_RemoteHyperV.cs @@ -0,0 +1,661 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Management.Automation.Language; +using System.Management.Automation.Subsystem; +using System.Management.Automation.Subsystem.Prediction; +using System.Threading; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Reflection; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +namespace PSTests.Sequential +{ + public class RemoteHyperVTests + { + private static ITestOutputHelper _output; + private static TimeSpan timeout = TimeSpan.FromSeconds(15); + + public RemoteHyperVTests(ITestOutputHelper output) + { + if (!System.Management.Automation.Platform.IsWindows) + { + throw new SkipException("RemoteHyperVTests are only supported on Windows."); + } + + _output = output; + } + + // Helper method to connect with retries + private static void ConnectWithRetry(Socket client, IPAddress address, int port, ITestOutputHelper output, int maxRetries = 10) + { + int retryDelayMs = 500; + int attempt = 0; + bool connected = false; + while (attempt < maxRetries && !connected) + { + try + { + client.Connect(address, port); + connected = true; + } + catch (SocketException) + { + attempt++; + if (attempt < maxRetries) + { + output?.WriteLine($"Connect attempt {attempt} failed, retrying in {retryDelayMs}ms..."); + Thread.Sleep(retryDelayMs); + retryDelayMs *= 2; + } + else + { + output?.WriteLine($"Failed to connect after {maxRetries} attempts. This is most likely an intermittent failure due to environmental issues."); + throw; + } + } + } + } + + private static void StartHandshakeServer( + string name, + int port, + IEnumerable<(string message, + Encoding encoding)> expectedClientSends, + IEnumerable<(string message, Encoding encoding)> serverResponses, + bool verifyConnectionClosed, + CancellationToken cancellationToken, + bool sendFirst = false) + { + var expectedMessages = new Queue<(string message, byte[] bytes, Encoding encoding)>(); + foreach (var item in expectedClientSends) + { + var itemBytes = item.encoding.GetBytes(item.message); + expectedMessages.Enqueue((message: item.message, bytes: itemBytes, encoding: item.encoding)); + } + + var serverResponseBytes = new Queue(); + foreach (var item in serverResponses) + { + serverResponseBytes.Enqueue(item.encoding.GetBytes(item.message)); + } + + StartHandshakeServer(name, port, expectedMessages, serverResponseBytes, verifyConnectionClosed, cancellationToken, sendFirst); + } + + private static void StartHandshakeServer(string name, int port, Queue<(string message, byte[] bytes, Encoding encoding)> expectedClientSends, Queue serverResponses, bool verifyConnectionClosed, CancellationToken cancellationToken, bool sendFirst = false) + { + var buffer = new byte[1024]; + var listener = new TcpListener(IPAddress.Loopback, port); + listener.Start(); + try + { + using (var client = listener.AcceptSocket()) + { + if (sendFirst) + { + // Send the first message from the serverResponses queue + if (serverResponses.Count > 0) + { + var resp = serverResponses.Dequeue(); + client.Send(resp, resp.Length, SocketFlags.None); + _output.WriteLine($"Mock {name} - sent response: " + Encoding.ASCII.GetString(resp)); + } + } + + while (expectedClientSends.Count > 0) + { + client.ReceiveTimeout = 2 * 1000; // 2 seconds timeout for receiving data + cancellationToken.ThrowIfCancellationRequested(); + var expectedMessage = expectedClientSends.Dequeue(); + var expected = expectedMessage.bytes; + Array.Clear(buffer, 0, buffer.Length); + int received = client.Receive(buffer); + // Optionally validate received data matches expected + string expectedString = expectedMessage.message; + string bufferString = expectedMessage.encoding.GetString(buffer, 0, received); + string alternativeEncodedString = string.Empty; + if (expectedMessage.encoding == Encoding.Unicode) + { + alternativeEncodedString = Encoding.UTF8.GetString(buffer, 0, received); + } + else if (expectedMessage.encoding == Encoding.UTF8) + { + alternativeEncodedString = Encoding.Unicode.GetString(buffer, 0, received); + } + + if (received != expected.Length) + { + string errorMessage = $"Mock {name} - Expected {expected.Length} bytes, but received {received} bytes: `{bufferString}`(alt encoding: `{alternativeEncodedString}`); expected: {expectedString}"; + _output.WriteLine(errorMessage); + throw new Exception(errorMessage); + } + if (!string.Equals(bufferString, expectedString, StringComparison.OrdinalIgnoreCase)) + { + string errorMessage = $"Mock {name} - Expected `{expectedString}`; length {expected.Length}, but received; length {received}; `{bufferString}`(alt encoding: `{alternativeEncodedString}`) instead."; + _output.WriteLine(errorMessage); + throw new Exception(errorMessage); + } + _output.WriteLine($"Mock {name} - received expected message: " + expectedString); + if (serverResponses.Count > 0) + { + var resp = serverResponses.Dequeue(); + client.Send(resp, resp.Length, SocketFlags.None); + _output.WriteLine($"Mock {name} - sent response: " + Encoding.ASCII.GetString(resp)); + } + } + + if (verifyConnectionClosed) + { + _output.WriteLine($"Mock {name} - verifying client connection is closed."); + // Wait for the client to close the connection synchronously (no timeout) + try + { + while (true) + { + int bytesRead = client.Receive(buffer, SocketFlags.None); + if (bytesRead == 0) + { + break; + } + + // If we receive any data, log and throw (assume UTF8 encoding) + string unexpectedData = Encoding.UTF8.GetString(buffer, 0, bytesRead); + _output.WriteLine($"Mock {name} - received unexpected data after handshake: {unexpectedData}"); + throw new Exception($"Mock {name} - received unexpected data after handshake: {unexpectedData}"); + } + _output.WriteLine($"Mock {name} - client closed the connection."); + } + catch (SocketException ex) + { + _output.WriteLine($"Mock {name} - socket exception while waiting for client close: {ex.Message} {ex.GetType().FullName}"); + } + catch (ObjectDisposedException) + { + // Socket already closed + } + } + } + + _output.WriteLine($"Mock {name} - on port {port} completed successfully."); + } + finally + { + listener.Stop(); + } + } + + // Helper function to create a random 4-character ASCII response + private static string CreateRandomAsciiResponse() + { + var rand = new Random(); + // Randomly return either "PASS" or "FAIL" + return rand.Next(0, 2) == 0 ? "PASS" : "FAIL"; + } + + // Helper method to create test data + private static (List<(string, Encoding)> expectedClientSends, List<(string, Encoding)> serverResponses) CreateHandshakeTestData(NetworkCredential cred) + { + var expectedClientSends = new List<(string message, Encoding encoding)> + { + (message: cred.Domain, encoding: Encoding.Unicode), + (message: cred.UserName, encoding: Encoding.Unicode), + (message: "NONEMPTYPW", encoding: Encoding.ASCII), + (message: cred.Password, encoding: Encoding.Unicode) + }; + + var serverResponses = new List<(string message, Encoding encoding)> + { + (message: CreateRandomAsciiResponse(), encoding: Encoding.ASCII), // Response to domain + (message: CreateRandomAsciiResponse(), encoding: Encoding.ASCII), // Response to username + (message: CreateRandomAsciiResponse(), encoding: Encoding.ASCII) // Response to non-empty password + }; + + return (expectedClientSends, serverResponses); + } + + private static List<(string message, Encoding encoding)> CreateVersionNegotiationClientSends() + { + return new List<(string message, Encoding encoding)> + { + (message: "VERSION", encoding: Encoding.UTF8), + (message: "VERSION_2", encoding: Encoding.UTF8), + }; + } + + private static List<(string, Encoding)> CreateV2Sends(NetworkCredential cred, string configurationName) + { + var sends = CreateVersionNegotiationClientSends(); + var password = cred.Password; + var emptyPassword = string.IsNullOrEmpty(password); + + sends.AddRange(new List<(string message, Encoding encoding)> + { + (message: cred.Domain, encoding: Encoding.Unicode), + (message: cred.UserName, encoding: Encoding.Unicode) + }); + + if (!emptyPassword) + { + sends.AddRange(new List<(string message, Encoding encoding)> + { + (message: "NONEMPTYPW", encoding: Encoding.UTF8), + (message: cred.Password, encoding: Encoding.Unicode) + }); + } + else + { + sends.Add((message: "EMPTYPW", encoding: Encoding.UTF8)); // Empty password and we don't expect a response + } + + if (!string.IsNullOrEmpty(configurationName)) + { + sends.Add((message: "NONEMPTYCF", encoding: Encoding.UTF8)); + sends.Add((message: configurationName, encoding: Encoding.Unicode)); // Configuration string and we don't expect a response + } + else + { + sends.Add((message: "EMPTYCF", encoding: Encoding.UTF8)); // Configuration string and we don't expect a response + } + + sends.Add((message: "PASS", encoding: Encoding.ASCII)); // Response to TOKEN + + return sends; + } + + private static List<(string, Encoding)> CreateV2Responses(string version = "VERSION_2", bool emptyConfig = false, string token = "FakeToken0+/=", bool emptyPassword = false) + { + var responses = new List<(string message, Encoding encoding)> + { + (message: version, encoding: Encoding.ASCII), // Response to VERSION + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII), // Response to domain + (message: "PASS", encoding: Encoding.ASCII), // Response to username + }; + + if (!emptyPassword) + { + responses.Add((message: "PASS", encoding: Encoding.ASCII)); // Response to non-empty password + } + + responses.Add((message: "CONF", encoding: Encoding.ASCII)); // Response to configuration + + if (!emptyConfig) + { + responses.Add((message: "PASS", encoding: Encoding.ASCII)); // Response to non-empty configuration + } + responses.Add((message: "TOKEN " + token, encoding: Encoding.ASCII)); // Response to with a token than uses each class of character in base 64 encoding + + return responses; + } + + // Helper method to create test data + private static (List<(string, Encoding)> expectedClientSends, List<(string, Encoding)> serverResponses) + CreateHandshakeTestDataV2(NetworkCredential cred, string version, string configurationName, string token) + { + bool emptyConfig = string.IsNullOrEmpty(configurationName); + bool emptyPassword = string.IsNullOrEmpty(cred.Password); + return (CreateV2Sends(cred, configurationName), CreateV2Responses(version, emptyConfig, token, emptyPassword)); + } + + // Helper method to create test data + private static (List<(string, Encoding)> expectedClientSends, List<(string, Encoding)> serverResponses) CreateHandshakeTestDataForFallback(NetworkCredential cred) + { + var expectedClientSends = new List<(string message, Encoding encoding)> + { + (message: "VERSION", encoding: Encoding.UTF8), + (message: @"?", encoding: Encoding.Unicode), + (message: "EMPTYPW", encoding: Encoding.UTF8), // Response to domain + (message: "FAIL", encoding: Encoding.UTF8), // Response to domain + }; + + List<(string message, Encoding encoding)> serverResponses = new List<(string message, Encoding encoding)> + { + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION but v1 server expects domain so it says "PASS" + (message: "PASS", encoding: Encoding.ASCII), // Response to username + (message: "FAIL", encoding: Encoding.ASCII) // Response to EMPTYPW + }; + + return (expectedClientSends, serverResponses); + } + + // Helper to create a password with at least one non-ASCII Unicode character + public static string CreateRandomUnicodePassword(string prefix) + { + var rand = new Random(); + var asciiPart = new char[6 + prefix.Length]; + // Copy prefix into asciiPart + Array.Copy(prefix.ToCharArray(), 0, asciiPart, 0, prefix.Length); + for (int i = prefix.Length; i < asciiPart.Length; i++) + { + asciiPart[i] = (char)rand.Next(33, 127); // ASCII printable + } + // Add a random Unicode character outside ASCII range (e.g., U+0100 to U+017F) + char unicodeChar = (char)rand.Next(0x0100, 0x017F); + // Insert the unicode character at a random position + int insertPos = rand.Next(0, asciiPart.Length + 1); + var passwordChars = new List(asciiPart); + passwordChars.Insert(insertPos, unicodeChar); + return new string(passwordChars.ToArray()); + } + + public static NetworkCredential CreateTestCredential() + { + return new NetworkCredential(CreateRandomUnicodePassword("username"), CreateRandomUnicodePassword("password"), CreateRandomUnicodePassword("domain")); + } + + [SkippableFact] + public async Task PerformCredentialAndConfigurationHandshake_V1_Pass() + { + // Arrange + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + var cred = CreateTestCredential(); + string configurationName = CreateRandomUnicodePassword("config"); + + var (expectedClientSends, serverResponses) = CreateHandshakeTestData(cred); + expectedClientSends.Add(("PASS", Encoding.ASCII)); + serverResponses.Add(("PASS", Encoding.ASCII)); + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Broker", port, expectedClientSends, serverResponses, verifyConnectionClosed: false, cts.Token), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + var exchangeResult = System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.ExchangeCredentialsAndConfiguration(cred, configurationName, client, true); + var result = exchangeResult.success; + _output.WriteLine($"Exchange result: {result}, Token: {exchangeResult.authenticationToken}"); + System.Threading.Thread.Sleep(100); // Allow time for server to process + Assert.True(result, $"Expected Exchange to pass"); + } + + await serverTask; + } + + [SkippableTheory] + [InlineData("VERSION_2", "configurationname1", "FakeTokenaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAA0FakeTokenaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAA0+/==")] // a fake base64 token about 512 bits long (double the size when this was spec'ed) + [InlineData("VERSION_10", null, "FakeTokenaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAA0+/=")] // a fake base64 token about 256 bits Long (the size when this was spec'ed) + public async Task PerformCredentialAndConfigurationHandshake_V2_Pass(string versionResponse, string configurationName, string token) + { + // Arrange + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + var cred = CreateTestCredential(); + + var (expectedClientSends, serverResponses) = CreateHandshakeTestDataV2(cred, versionResponse, configurationName, token); + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Broker", port, expectedClientSends, serverResponses, verifyConnectionClosed: true, cts.Token), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + client.Connect(IPAddress.Loopback, port); + var exchangeResult = System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.ExchangeCredentialsAndConfiguration(cred, configurationName, client, false); + var result = exchangeResult.success; + System.Threading.Thread.Sleep(100); // Allow time for server to process + Assert.True(result, $"Expected Exchange to pass for version response '{versionResponse}'"); + Assert.Equal(token, exchangeResult.authenticationToken); + } + + await serverTask; + } + + [SkippableFact] + public async Task PerformCredentialAndConfigurationHandshake_V1_Fallback() + { + // Arrange + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + var cred = CreateTestCredential(); + string configurationName = CreateRandomUnicodePassword("config"); + + var (expectedClientSends, serverResponses) = CreateHandshakeTestDataForFallback(cred); + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Broker", port, expectedClientSends, serverResponses, verifyConnectionClosed: false, cts.Token), cts.Token); + + bool isFallback = false; + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + _output.WriteLine("Starting handshake with V2 protocol."); + client.Connect(IPAddress.Loopback, port); + var exchangeResult = System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.ExchangeCredentialsAndConfiguration(cred, configurationName, client, false); + isFallback = !exchangeResult.success; + + System.Threading.Thread.Sleep(100); // Allow time for server to process + _output.WriteLine("Handshake indicated fallback to V1."); + Assert.True(isFallback, "Expected fallback to V1."); + } + _output.WriteLine("Handshake completed successfully with fallback to V1."); + + await serverTask; + } + + [SkippableFact] + public async Task PerformCredentialAndConfigurationHandshake_V2_InvalidResponse() + { + // Arrange + int port = 51000 + (int)(DateTime.Now.Ticks % 10000); + var cred = CreateTestCredential(); + + var (expectedClientSends, serverResponses) = CreateHandshakeTestData(cred); + //expectedClientSends.Add("FAI1"); + serverResponses.Add(("FAI1", Encoding.ASCII)); + + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); + + //cts.Token.Register(() => throw new OperationCanceledException("Test timed out.")); + + var serverTask = Task.Run(() => StartHandshakeServer("Broker", port, expectedClientSends, serverResponses, verifyConnectionClosed: false, cts.Token), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + _output.WriteLine("connecting on port " + port); + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + + var ex = Record.Exception(() => System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.ExchangeCredentialsAndConfiguration(cred, "config", client, true)); + + try + { + await serverTask; + } + catch (AggregateException exAgg) + { + Assert.Null(exAgg.Flatten().InnerExceptions[1].Message); + } + cts.Token.ThrowIfCancellationRequested(); + + Assert.NotNull(ex); + Assert.NotNull(ex.Message); + Assert.Contains("Hyper-V Broker sent an invalid Credential response", ex.Message); + } + } + + [SkippableFact] + public async Task PerformCredentialAndConfigurationHandshake_V1_Fail() + { + // Arrange + int port = 51000 + (int)(DateTime.Now.Ticks % 10000); + var cred = CreateTestCredential(); + + var (expectedClientSends, serverResponses) = CreateHandshakeTestData(cred); + expectedClientSends.Add(("FAIL", Encoding.ASCII)); + serverResponses.Add(("FAIL", Encoding.ASCII)); + + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15)); + + // This scenario does not close the connection in a timely manner, so we set verifyConnectionClosed to false + var serverTask = Task.Run(() => StartHandshakeServer("Broker", port, expectedClientSends, serverResponses, verifyConnectionClosed: false, cts.Token), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + client.Connect(IPAddress.Loopback, port); + + var ex = Record.Exception(() => System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.ExchangeCredentialsAndConfiguration(cred, "config", client, true)); + + try + { + await serverTask; + } + catch (AggregateException exAgg) + { + Assert.Null(exAgg.Flatten().InnerExceptions[1].Message); + } + + cts.Token.ThrowIfCancellationRequested(); + + Assert.NotNull(ex); + Assert.NotNull(ex.Message); + Assert.Contains("The credential is invalid.", ex.Message); + } + } + + [SkippableTheory] + [InlineData("VERSION_2", "FakeTokenaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAA0FakeTokenaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAA0+/==")] // a fake base64 token about 512 bits long (double the size when this was spec'ed) + [InlineData("VERSION_10", "FakeTokenaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAA0+/=")] // a fake base64 token about 256 bits Long (the size when this was spec'ed) + public async Task PerformTransportVersionAndTokenExchange_Pass(string version, string token) + { + // Arrange + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + var cred = CreateTestCredential(); + + var expectedClientSends = CreateVersionNegotiationClientSends(); + expectedClientSends.Add((message: "TOKEN " + token, encoding: Encoding.ASCII)); + + var serverResponses = new List<(string message, Encoding encoding)>{ + (message: version, encoding: Encoding.ASCII), // Response to VERSION + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII) // Response to token + }; + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Server", port, expectedClientSends, serverResponses, verifyConnectionClosed: true, cts.Token), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.PerformTransportVersionAndTokenExchange(client, token); + System.Threading.Thread.Sleep(100); // Allow time for server to process + } + + await serverTask; + } + + [SkippableTheory] + [InlineData(1, true)] + [InlineData(2, true)] + [InlineData(0, false)] + [InlineData(null, false)] + [System.Runtime.Versioning.SupportedOSPlatform("windows")] + public void IsRequirePsDirectAuthenticationEnabled(int? regValue, bool expected) + { + const string testKeyPath = @"SOFTWARE\Microsoft\TestRequirePsDirectAuthentication"; + const string valueName = "RequirePsDirectAuthentication"; + if (!System.Management.Automation.Platform.IsWindows) + { + throw new SkipException("RemoteHyperVTests are only supported on Windows."); + } + + // Clean up any previous test key + var regHive = Microsoft.Win32.RegistryHive.CurrentUser; + var baseKey = Microsoft.Win32.RegistryKey.OpenBaseKey(regHive, Microsoft.Win32.RegistryView.Registry64); + baseKey.DeleteSubKeyTree(testKeyPath, false); + + bool? result = null; + + // Create the test key + using (var key = baseKey.CreateSubKey(testKeyPath)) + { + if (regValue.HasValue) + { + key.SetValue(valueName, regValue.Value, Microsoft.Win32.RegistryValueKind.DWord); + } + else + { + // Ensure the value does not exist + key.DeleteValue(valueName, false); + } + + result = System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.IsRequirePsDirectAuthenticationEnabled(testKeyPath, regHive); + } + + Assert.True(result.HasValue, "IsRequirePsDirectAuthenticationEnabled should return a value."); + Assert.True(expected == result.Value, + $"Expected IsRequirePsDirectAuthenticationEnabled to return {expected} when registry value is {(regValue.HasValue ? regValue.ToString() : "not set")}."); + + return; + } + + [SkippableTheory] + [InlineData("testToken", "testToken")] + [InlineData("testToken\0", "testToken")] + public async Task ValidatePassesWhenTokensMatch(string token, string expectedToken) + { + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + + var expectedClientSends = new List<(string message, Encoding encoding)>{ + (message: "VERSION", encoding: Encoding.ASCII), // Response to VERSION + (message: "VERSION_2", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: $"TOKEN {token}", encoding: Encoding.ASCII) + }; + + var serverResponses = new List<(string message, Encoding encoding)>{ + (message: "VERSION_2", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII) // Response to token + }; + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Client", port, serverResponses, expectedClientSends, verifyConnectionClosed: true, cts.Token, sendFirst: true), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken); + System.Threading.Thread.Sleep(100); // Allow time for server to process + } + + await serverTask; + } + + [SkippableTheory] + [InlineData("abc", "xyz")] + [InlineData("abc", "abcdef")] + [InlineData("abcdef", "abc")] + [InlineData("abc\0def", "abc")] + public async Task ValidateFailsWhenTokensMismatch(string token, string expectedToken) + { + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + + var expectedClientSends = new List<(string message, Encoding encoding)>{ + (message: "VERSION", encoding: Encoding.ASCII), // Initial request + (message: "VERSION_2", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: $"TOKEN {token}", encoding: Encoding.ASCII) + }; + + var serverResponses = new List<(string message, Encoding encoding)>{ + (message: "VERSION_2", encoding: Encoding.ASCII), // Response to VERSION + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "FAIL", encoding: Encoding.ASCII) // Response to token + }; + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Client", port, serverResponses, expectedClientSends, verifyConnectionClosed: true, cts.Token, sendFirst: true), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + var exception = Assert.Throws( + () => System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken)); + System.Threading.Thread.Sleep(100); // Allow time for server to process + Assert.Contains("The credential is invalid.", exception.Message); + } + + await serverTask; + } + } +} From 37086d441c9704d2fe66ce6dc0d5057e9e9e5668 Mon Sep 17 00:00:00 2001 From: "Travis Plunk (HE/HIM)" Date: Fri, 5 Sep 2025 17:50:40 -0700 Subject: [PATCH 153/275] Add LinuxHost Network configuration to PowerShell Packages pipeline --- .pipelines/PowerShell-Packages-Official.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 333d73276b8..552e7d10a68 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -92,6 +92,8 @@ extends: WindowsHostVersion: Version: 2022 Network: KS3 + LinuxHostVersion: + Network: KS3 linuxEsrpSigning: true incrementalSDLBinaryAnalysis: true globalSdl: From 653e93df4d2aa529752425642dc27126b434c0b2 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Sat, 6 Sep 2025 12:32:38 -0700 Subject: [PATCH 154/275] [release/v7.5] Add LinuxHost Network configuration to PowerShell Packages pipeline (#26002) Co-authored-by: Travis Plunk --- .pipelines/PowerShell-Packages-Official.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 333d73276b8..552e7d10a68 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -92,6 +92,8 @@ extends: WindowsHostVersion: Version: 2022 Network: KS3 + LinuxHostVersion: + Network: KS3 linuxEsrpSigning: true incrementalSDLBinaryAnalysis: true globalSdl: From 82c9317ad186500d446b8cf3da4170c798ada485 Mon Sep 17 00:00:00 2001 From: "Travis Plunk (HE/HIM)" Date: Mon, 8 Sep 2025 12:00:32 -0700 Subject: [PATCH 155/275] Fix variable reference for release environment in pipeline --- .pipelines/PowerShell-Release-Official.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 974b8f328c8..986f803361b 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -288,7 +288,7 @@ extends: - setReleaseTagAndChangelog - UpdateChangeLog variables: - ob_release_environment: ${{ parameters.releaseEnvironment }} + ob_release_environment: ${{ variables.releaseEnvironment }} jobs: - template: /.pipelines/templates/release-githubNuget.yml@self parameters: From 5ad67e1697cb9f3ac70f7f55c9d4361adde336e1 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 8 Sep 2025 12:53:26 -0700 Subject: [PATCH 156/275] [release/v7.5] Add v7.5.3 Changelog (#26015) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> --- CHANGELOG/7.5.md | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index d2071727790..e231ce6b0e2 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -1,5 +1,47 @@ # 7.5 Changelog +## [7.5.3] + +### General Cmdlet Updates and Fixes + +- Fix `Out-GridView` by replacing the use of obsolete `BinaryFormatter` with custom implementation. (#25559) +- Remove `OnDeserialized` and `Serializable` attributes from `Microsoft.Management.UI.Internal` project (#25831) +- Make the interface `IDeepCloneable` internal (#25830) + +### Tools + +- Add CodeQL suppressions (#25972) + +### Tests + +- Fix updatable help test for new content (#25944) + +### Build and Packaging Improvements + +
+ + + +

Update to .NET SDK 9.0.304

+ +
+ +
    +
  • Make logical template name consistent between pipelines (#25991)
  • +
  • Update container images to use mcr.microsoft.com for Linux and Azure Linux (#25986)
  • +
  • Add build to vPack Pipeline (#25975)
  • +
  • Remove AsyncSDL from Pipelines Toggle Official/NonOfficial Runs (#25964)
  • +
  • Update branch for release (#25942)
  • +
+ +
+ +### Documentation and Help Content + +- Fix typo in CHANGELOG for script filename suggestion (#25963) + +[7.5.3]: https://github.com/PowerShell/PowerShell/compare/v7.5.2...v7.5.3 + ## [7.5.2] - 2025-06-24 ### Engine Updates and Fixes @@ -41,7 +83,6 @@ [7.5.2]: https://github.com/PowerShell/PowerShell/compare/v7.5.1...v7.5.2 - ## [7.5.1] ### Engine Updates and Fixes From a77962d18346f59ab32b52a179504ed9d218d74d Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 8 Sep 2025 14:32:56 -0700 Subject: [PATCH 157/275] [release/v7.5] Fix variable reference for release environment in pipeline (#26013) Co-authored-by: Travis Plunk --- .pipelines/PowerShell-Release-Official.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 974b8f328c8..986f803361b 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -288,7 +288,7 @@ extends: - setReleaseTagAndChangelog - UpdateChangeLog variables: - ob_release_environment: ${{ parameters.releaseEnvironment }} + ob_release_environment: ${{ variables.releaseEnvironment }} jobs: - template: /.pipelines/templates/release-githubNuget.yml@self parameters: From b72c7ab1238c2d95b5c9004bca8399b8b3ca88ac Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 8 Sep 2025 12:53:26 -0700 Subject: [PATCH 158/275] [release/v7.5] Add v7.5.3 Changelog (#26015) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> --- CHANGELOG/7.5.md | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index d2071727790..e231ce6b0e2 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -1,5 +1,47 @@ # 7.5 Changelog +## [7.5.3] + +### General Cmdlet Updates and Fixes + +- Fix `Out-GridView` by replacing the use of obsolete `BinaryFormatter` with custom implementation. (#25559) +- Remove `OnDeserialized` and `Serializable` attributes from `Microsoft.Management.UI.Internal` project (#25831) +- Make the interface `IDeepCloneable` internal (#25830) + +### Tools + +- Add CodeQL suppressions (#25972) + +### Tests + +- Fix updatable help test for new content (#25944) + +### Build and Packaging Improvements + +
+ + + +

Update to .NET SDK 9.0.304

+ +
+ +
    +
  • Make logical template name consistent between pipelines (#25991)
  • +
  • Update container images to use mcr.microsoft.com for Linux and Azure Linux (#25986)
  • +
  • Add build to vPack Pipeline (#25975)
  • +
  • Remove AsyncSDL from Pipelines Toggle Official/NonOfficial Runs (#25964)
  • +
  • Update branch for release (#25942)
  • +
+ +
+ +### Documentation and Help Content + +- Fix typo in CHANGELOG for script filename suggestion (#25963) + +[7.5.3]: https://github.com/PowerShell/PowerShell/compare/v7.5.2...v7.5.3 + ## [7.5.2] - 2025-06-24 ### Engine Updates and Fixes @@ -41,7 +83,6 @@ [7.5.2]: https://github.com/PowerShell/PowerShell/compare/v7.5.1...v7.5.2 - ## [7.5.1] ### Engine Updates and Fixes From ca3365b94be7af48ccd057ab9692a39881a42e13 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 10 Sep 2025 10:15:45 -0700 Subject: [PATCH 159/275] [release/v7.5] Update Ev2 Shell Extension Image to AzureLinux 3 for PMC Release (#26032) Co-authored-by: Anam Navied --- .pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json b/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json index 00555349c35..ce974fe69e5 100644 --- a/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json +++ b/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json @@ -17,8 +17,8 @@ { "type": "Run", "properties": { - "imageName": "adm-mariner-20-l", - "imageVersion": "v11" + "imageName": "adm-azurelinux-30-l", + "imageVersion": "v2" } } ] From 8272044640ecc6908c894c53712b6176ba147f2a Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 22 Sep 2025 14:06:31 -0700 Subject: [PATCH 160/275] [release/v7.5] Suppress false positive PSScriptAnalyzer warnings in tests and build scripts (#26059) Co-authored-by: Patrick Meinecke --- ....Cmdlets.LocalAccounts.LocalUser.Tests.ps1 | 4 +- .../Set-Service.Tests.ps1 | 4 ++ .../CmsMessage.Tests.ps1 | 4 ++ .../GetCredential.Tests.ps1 | 4 ++ .../UserConfigProviderModVersion1.psm1 | 60 ++++++++--------- .../UserConfigProviderModVersion2.psm1 | 66 +++++++++---------- .../UserConfigProviderModVersion3.psm1 | 58 ++++++++-------- .../certificateCommon.psm1 | 3 + .../ConvertTo-SecureString.Tests.ps1 | 4 ++ .../ConfigProvider.Tests.ps1 | 3 + .../engine/Api/Serialization.Tests.ps1 | 5 +- .../engine/Remoting/PSSession.Tests.ps1 | 3 + .../Remoting/RemoteSession.Basic.Tests.ps1 | 3 + .../Modules/WebListener/WebListener.psm1 | 4 ++ tools/WindowsCI.psm1 | 2 + tools/ci.psm1 | 3 + 16 files changed, 127 insertions(+), 103 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.LocalAccounts/Pester.Command.Cmdlets.LocalAccounts.LocalUser.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.LocalAccounts/Pester.Command.Cmdlets.LocalAccounts.LocalUser.Tests.ps1 index e6e5ebb8d4f..2e56df87256 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.LocalAccounts/Pester.Command.Cmdlets.LocalAccounts.LocalUser.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.LocalAccounts/Pester.Command.Cmdlets.LocalAccounts.LocalUser.Tests.ps1 @@ -4,6 +4,9 @@ # Module removed due to #4272 # disabling tests +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + return Set-Variable dateInFuture -Option Constant -Value "12/12/2036 09:00" @@ -1557,4 +1560,3 @@ try { finally { $global:PSDefaultParameterValues = $originalDefaultParameterValues } - diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 index 2c5f0fed3ee..bcb7a56ccde 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 @@ -1,5 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Import-Module (Join-Path -Path $PSScriptRoot '..\Microsoft.PowerShell.Security\certificateCommon.psm1') Describe "Set/New/Remove-Service cmdlet tests" -Tags "Feature", "RequireAdminOnWindows" { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 index 50cbdebab69..a40dfc8cfcd 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 @@ -1,5 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Import-Module (Join-Path -Path $PSScriptRoot 'certificateCommon.psm1') -Force Describe "CmsMessage cmdlets and Get-PfxCertificate basic tests" -Tags "CI" { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/GetCredential.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/GetCredential.Tests.ps1 index cb9d0ee70ed..fad8285aab3 100755 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/GetCredential.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/GetCredential.Tests.ps1 @@ -1,5 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Describe "Get-Credential Test" -Tag "CI" { BeforeAll { $th = New-TestHost diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion1/UserConfigProviderModVersion1.psm1 b/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion1/UserConfigProviderModVersion1.psm1 index fd85fef1552..45188075fbc 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion1/UserConfigProviderModVersion1.psm1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion1/UserConfigProviderModVersion1.psm1 @@ -5,56 +5,50 @@ # This cmdlet executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). The result of the script execution is in the form of a hashtable containing all the information # gathered from the GetScript execution. -function Get-TargetResource -{ +function Get-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $text - ) + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Text + ) $result = @{ - Text = "Hello from Get!"; - } - $result; + Text = "Hello from Get!" + } + + $result } # The Set-TargetResource cmdlet is used to Set the desired state of the DSC managed node through a powershell script. # The method executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). If the DSC managed node requires a restart either during or after the execution of the SetScript, # the SetScript notifies the PS Infrastructure by setting the variable $DSCMachineStatus.IsRestartRequired to $true. -function Set-TargetResource -{ +function Set-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $text - ) - $path = "$env:SystemDrive\dscTestPath\hello1.txt" - New-Item -Path $path -Type File -Force - Add-Content -Path $path -Value $text + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Text + ) + $path = "$env:SystemDrive\dscTestPath\hello1.txt" + New-Item -Path $path -Type File -Force + Add-Content -Path $path -Value $text } # The Test-TargetResource cmdlet is used to validate the desired state of the DSC managed node through a powershell script. # The method executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). The result of the script execution should be true if the DSC managed machine is in the desired state # or else false should be returned. -function Test-TargetResource -{ +function Test-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] + param( + [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] - $text - ) - $false + $Text + ) + $false } - diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion2/UserConfigProviderModVersion2.psm1 b/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion2/UserConfigProviderModVersion2.psm1 index d2f6a9ac719..05dbdcec7e1 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion2/UserConfigProviderModVersion2.psm1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion2/UserConfigProviderModVersion2.psm1 @@ -5,57 +5,51 @@ # This cmdlet executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). The result of the script execution is in the form of a hashtable containing all the information # gathered from the GetScript execution. -function Get-TargetResource -{ +function Get-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $text - ) + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Text + ) $result = @{ - Text = "Hello from Get!"; - } - $result; - } + Text = "Hello from Get!" + } + + $result +} # The Set-TargetResource cmdlet is used to Set the desired state of the DSC managed node through a powershell script. # The method executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). If the DSC managed node requires a restart either during or after the execution of the SetScript, # the SetScript notifies the PS Infrastructure by setting the variable $DSCMachineStatus.IsRestartRequired to $true. -function Set-TargetResource -{ +function Set-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $text - ) + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Text + ) - $path = "$env:SystemDrive\dscTestPath\hello2.txt" - New-Item -Path $path -Type File -Force - Add-Content -Path $path -Value $text + $path = "$env:SystemDrive\dscTestPath\hello2.txt" + New-Item -Path $path -Type File -Force + Add-Content -Path $path -Value $text } # The Test-TargetResource cmdlet is used to validate the desired state of the DSC managed node through a powershell script. # The method executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). The result of the script execution should be true if the DSC managed machine is in the desired state # or else false should be returned. -function Test-TargetResource -{ +function Test-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $text - ) - $false + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Text + ) + $false } - diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion3/UserConfigProviderModVersion3.psm1 b/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion3/UserConfigProviderModVersion3.psm1 index 45987a71f76..134158d62a9 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion3/UserConfigProviderModVersion3.psm1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion3/UserConfigProviderModVersion3.psm1 @@ -5,57 +5,51 @@ # This cmdlet executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). The result of the script execution is in the form of a hashtable containing all the information # gathered from the GetScript execution. -function Get-TargetResource -{ +function Get-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] + param( + [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] - $text - ) + $Text + ) $result = @{ - Text = "Hello from Get!"; - } - $result; - } + Text = "Hello from Get!" + } + + $result +} # The Set-TargetResource cmdlet is used to Set the desired state of the DSC managed node through a powershell script. # The method executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). If the DSC managed node requires a restart either during or after the execution of the SetScript, # the SetScript notifies the PS Infrastructure by setting the variable $DSCMachineStatus.IsRestartRequired to $true. -function Set-TargetResource -{ +function Set-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] + param( + [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] - $text - ) + $Text + ) - $path = "$env:SystemDrive\dscTestPath\hello3.txt" - New-Item -Path $path -Type File -Force - Add-Content -Path $path -Value $text + $path = "$env:SystemDrive\dscTestPath\hello3.txt" + New-Item -Path $path -Type File -Force + Add-Content -Path $path -Value $text } # The Test-TargetResource cmdlet is used to validate the desired state of the DSC managed node through a powershell script. # The method executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). The result of the script execution should be true if the DSC managed machine is in the desired state # or else false should be returned. -function Test-TargetResource -{ +function Test-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $text - ) - $false + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Text + ) + $false } - diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/certificateCommon.psm1 b/test/powershell/Modules/Microsoft.PowerShell.Security/certificateCommon.psm1 index 5601767a120..46092386fe3 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/certificateCommon.psm1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/certificateCommon.psm1 @@ -1,6 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Function New-GoodCertificate { <# diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-SecureString.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-SecureString.Tests.ps1 index e58a227fbcf..5a2660ed621 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-SecureString.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-SecureString.Tests.ps1 @@ -1,5 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Describe "ConvertTo--SecureString" -Tags "CI" { Context "Checking return types of ConvertTo--SecureString" { diff --git a/test/powershell/Modules/Microsoft.WSMan.Management/ConfigProvider.Tests.ps1 b/test/powershell/Modules/Microsoft.WSMan.Management/ConfigProvider.Tests.ps1 index 49d60cd1283..1845933e8f4 100644 --- a/test/powershell/Modules/Microsoft.WSMan.Management/ConfigProvider.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.WSMan.Management/ConfigProvider.Tests.ps1 @@ -1,6 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Describe "WSMan Config Provider" -Tag Feature,RequireAdminOnWindows { BeforeAll { #skip all tests on non-windows platform diff --git a/test/powershell/engine/Api/Serialization.Tests.ps1 b/test/powershell/engine/Api/Serialization.Tests.ps1 index 6b011ffc6ab..317a0907ca5 100644 --- a/test/powershell/engine/Api/Serialization.Tests.ps1 +++ b/test/powershell/engine/Api/Serialization.Tests.ps1 @@ -1,5 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Describe "Serialization Tests" -tags "CI" { BeforeAll { $testfileName="SerializationTest.txt" @@ -99,4 +103,3 @@ Describe "Serialization Tests" -tags "CI" { SerializeAndDeserialize($versionObject).TestScriptProperty | Should -Be $versionObject.TestScriptProperty } } - diff --git a/test/powershell/engine/Remoting/PSSession.Tests.ps1 b/test/powershell/engine/Remoting/PSSession.Tests.ps1 index cbf7313eed0..689e587ddb1 100644 --- a/test/powershell/engine/Remoting/PSSession.Tests.ps1 +++ b/test/powershell/engine/Remoting/PSSession.Tests.ps1 @@ -5,6 +5,9 @@ # PSSession tests for non-Windows platforms # +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + function GetRandomString() { return [System.IO.Path]::GetFileNameWithoutExtension([System.IO.Path]::GetRandomFileName()) diff --git a/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 b/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 index 43f92cef295..a5d49b75005 100644 --- a/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 +++ b/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 @@ -1,6 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Import-Module HelpersCommon function GetRandomString() diff --git a/test/tools/Modules/WebListener/WebListener.psm1 b/test/tools/Modules/WebListener/WebListener.psm1 index 15ce1d8fe38..7f590b79b76 100644 --- a/test/tools/Modules/WebListener/WebListener.psm1 +++ b/test/tools/Modules/WebListener/WebListener.psm1 @@ -1,6 +1,10 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')] +param() + Class WebListener { [int]$HttpPort diff --git a/tools/WindowsCI.psm1 b/tools/WindowsCI.psm1 index 57d506bda8b..685882546c2 100644 --- a/tools/WindowsCI.psm1 +++ b/tools/WindowsCI.psm1 @@ -15,6 +15,8 @@ function New-LocalUser .OUTPUTS .NOTES #> + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingUsernameAndPasswordParams', '')] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')] param( [Parameter(Mandatory=$true)] [string] $username, diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 317f05effd0..7b13ded1811 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -1,6 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Set-StrictMode -Version 3.0 $ErrorActionPreference = 'continue' From ce08de80517b41077bdb48ce25df1fda0004bcee Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 9 Oct 2025 13:14:23 -0700 Subject: [PATCH 161/275] [release/v7.5] Ensure that socket timeouts are set only during the token validation (#26079) --- .../common/RemoteSessionHyperVSocket.cs | 57 +++--- test/xUnit/csharp/test_RemoteHyperV.cs | 186 ++++++++++++++++-- 2 files changed, 197 insertions(+), 46 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs index a9de12c3931..d62805d7e89 100644 --- a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs +++ b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs @@ -258,30 +258,7 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode, string token, DateTime listenSocket.Listen(1); HyperVSocket = listenSocket.Accept(); - TimeSpan timeout = TimeSpan.FromMinutes(MAX_TOKEN_LIFE_MINUTES); - DateTimeOffset timeoutExpiry = tokenCreationTime.Add(timeout); - DateTimeOffset now = DateTimeOffset.UtcNow; - - // Calculate remaining time and create cancellation token - TimeSpan remainingTime = timeoutExpiry - now; - - // Check if the token has already expired - if (remainingTime <= TimeSpan.Zero) - { - throw new PSDirectException( - PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential, "Token has expired")); - } - - // Set socket timeout for receive operations to prevent indefinite blocking - int timeoutMs = (int)remainingTime.TotalMilliseconds; - HyperVSocket.ReceiveTimeout = timeoutMs; - HyperVSocket.SendTimeout = timeoutMs; - - // Create a cancellation token that will be cancelled when the timeout expires - using var cancellationTokenSource = new CancellationTokenSource(remainingTime); - CancellationToken cancellationToken = cancellationTokenSource.Token; - - ValidateToken(HyperVSocket, token, cancellationToken); + ValidateToken(HyperVSocket, token, tokenCreationTime, MAX_TOKEN_LIFE_MINUTES * 60); Stream = new NetworkStream(HyperVSocket, true); @@ -389,9 +366,33 @@ public void Dispose() ///
/// The connected HyperVSocket. /// The expected token string. - /// Cancellation token for timeout handling. - internal static void ValidateToken(Socket socket, string token, CancellationToken cancellationToken = default) + /// The creation time of the token. + /// The maximum lifetime of the token in seconds. + internal static void ValidateToken(Socket socket, string token, DateTimeOffset tokenCreationTime, int maxTokenLifeSeconds) { + TimeSpan timeout = TimeSpan.FromSeconds(maxTokenLifeSeconds); + DateTimeOffset timeoutExpiry = tokenCreationTime.Add(timeout); + DateTimeOffset now = DateTimeOffset.UtcNow; + + // Calculate remaining time and create cancellation token + TimeSpan remainingTime = timeoutExpiry - now; + + // Check if the token has already expired + if (remainingTime <= TimeSpan.Zero) + { + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential, "Token has expired")); + } + + // Create a cancellation token that will be cancelled when the timeout expires + using var cancellationTokenSource = new CancellationTokenSource(remainingTime); + CancellationToken cancellationToken = cancellationTokenSource.Token; + + // Set socket timeout for receive operations to prevent indefinite blocking + int timeoutMs = (int)remainingTime.TotalMilliseconds; + socket.ReceiveTimeout = timeoutMs; + socket.SendTimeout = timeoutMs; + // Check for cancellation before starting validation cancellationToken.ThrowIfCancellationRequested(); @@ -430,6 +431,7 @@ internal static void ValidateToken(Socket socket, string token, CancellationToke // So we expect a response of length 6 + 100 = 106 characters. responseString = RemoteSessionHyperVSocketClient.ReceiveResponse(socket, 110); + // Final check if we got the token before the timeout cancellationToken.ThrowIfCancellationRequested(); if (string.IsNullOrEmpty(responseString) || !responseString.StartsWith("TOKEN ", StringComparison.Ordinal)) @@ -454,6 +456,9 @@ internal static void ValidateToken(Socket socket, string token, CancellationToke // Acknowledge the token is valid with "PASS". socket.Send("PASS"u8); + + socket.ReceiveTimeout = 0; // Disable the timeout after successful validation + socket.SendTimeout = 0; } } diff --git a/test/xUnit/csharp/test_RemoteHyperV.cs b/test/xUnit/csharp/test_RemoteHyperV.cs index f694f6894df..27f7fb17375 100644 --- a/test/xUnit/csharp/test_RemoteHyperV.cs +++ b/test/xUnit/csharp/test_RemoteHyperV.cs @@ -63,15 +63,51 @@ private static void ConnectWithRetry(Socket client, IPAddress address, int port, } } + private static void SendResponse(string name, Socket client, Queue<(byte[] bytes, int delayMs)> serverResponses) + { + if (serverResponses.Count > 0) + { + _output.WriteLine($"Mock {name} ----------------------------------------------------"); + var respTuple = serverResponses.Dequeue(); + var resp = respTuple.bytes; + + if (respTuple.delayMs > 0) + { + _output.WriteLine($"Mock {name} - delaying response by {respTuple.delayMs} ms"); + Thread.Sleep(respTuple.delayMs); + } + if (resp.Length > 0) { + client.Send(resp, resp.Length, SocketFlags.None); + _output.WriteLine($"Mock {name} - sent response: " + Encoding.ASCII.GetString(resp)); + } + } + } + private static void StartHandshakeServer( string name, int port, - IEnumerable<(string message, - Encoding encoding)> expectedClientSends, + IEnumerable<(string message, Encoding encoding)> expectedClientSends, IEnumerable<(string message, Encoding encoding)> serverResponses, bool verifyConnectionClosed, CancellationToken cancellationToken, bool sendFirst = false) + { + IEnumerable<(string message, Encoding encoding, int delayMs)> serverResponsesWithDelay = new List<(string message, Encoding encoding, int delayMs)>(); + foreach (var item in serverResponses) + { + ((List<(string message, Encoding encoding, int delayMs)>)serverResponsesWithDelay).Add((item.message, item.encoding, 1)); + } + StartHandshakeServer(name, port, expectedClientSends, serverResponsesWithDelay, verifyConnectionClosed, cancellationToken, sendFirst); + } + + private static void StartHandshakeServer( + string name, + int port, + IEnumerable<(string message, Encoding encoding)> expectedClientSends, + IEnumerable<(string message, Encoding encoding, int delayMs)> serverResponses, + bool verifyConnectionClosed, + CancellationToken cancellationToken, + bool sendFirst = false) { var expectedMessages = new Queue<(string message, byte[] bytes, Encoding encoding)>(); foreach (var item in expectedClientSends) @@ -80,17 +116,27 @@ private static void StartHandshakeServer( expectedMessages.Enqueue((message: item.message, bytes: itemBytes, encoding: item.encoding)); } - var serverResponseBytes = new Queue(); + var serverResponseBytes = new Queue<(byte[] bytes, int delayMs)>(); foreach (var item in serverResponses) { - serverResponseBytes.Enqueue(item.encoding.GetBytes(item.message)); + (byte[] bytes, int delayMs) queueItem = (item.encoding.GetBytes(item.message), item.delayMs); + serverResponseBytes.Enqueue(queueItem); } - StartHandshakeServer(name, port, expectedMessages, serverResponseBytes, verifyConnectionClosed, cancellationToken, sendFirst); + _output.WriteLine($"Mock {name} - starting listener on port {port} with {expectedMessages.Count} expected messages and {serverResponseBytes.Count} responses."); + StartHandshakeServerImplementation(name, port, expectedMessages, serverResponseBytes, verifyConnectionClosed, cancellationToken, sendFirst); } - private static void StartHandshakeServer(string name, int port, Queue<(string message, byte[] bytes, Encoding encoding)> expectedClientSends, Queue serverResponses, bool verifyConnectionClosed, CancellationToken cancellationToken, bool sendFirst = false) + private static void StartHandshakeServerImplementation( + string name, + int port, + Queue<(string message, byte[] bytes, Encoding encoding)> expectedClientSends, + Queue<(byte[] bytes, int delayMs)> serverResponses, + bool verifyConnectionClosed, + CancellationToken cancellationToken, + bool sendFirst = false) { + DateTime startTime = DateTime.UtcNow; var buffer = new byte[1024]; var listener = new TcpListener(IPAddress.Loopback, port); listener.Start(); @@ -101,19 +147,16 @@ private static void StartHandshakeServer(string name, int port, Queue<(string me if (sendFirst) { // Send the first message from the serverResponses queue - if (serverResponses.Count > 0) - { - var resp = serverResponses.Dequeue(); - client.Send(resp, resp.Length, SocketFlags.None); - _output.WriteLine($"Mock {name} - sent response: " + Encoding.ASCII.GetString(resp)); - } + SendResponse(name, client, serverResponses); } while (expectedClientSends.Count > 0) { + _output.WriteLine($"Mock {name} - time elapsed: {(DateTime.UtcNow - startTime).TotalMilliseconds} milliseconds"); client.ReceiveTimeout = 2 * 1000; // 2 seconds timeout for receiving data cancellationToken.ThrowIfCancellationRequested(); var expectedMessage = expectedClientSends.Dequeue(); + _output.WriteLine($"Mock {name} - remaining expected messages: {expectedClientSends.Count}"); var expected = expectedMessage.bytes; Array.Clear(buffer, 0, buffer.Length); int received = client.Receive(buffer); @@ -143,12 +186,7 @@ private static void StartHandshakeServer(string name, int port, Queue<(string me throw new Exception(errorMessage); } _output.WriteLine($"Mock {name} - received expected message: " + expectedString); - if (serverResponses.Count > 0) - { - var resp = serverResponses.Dequeue(); - client.Send(resp, resp.Length, SocketFlags.None); - _output.WriteLine($"Mock {name} - sent response: " + Encoding.ASCII.GetString(resp)); - } + SendResponse(name, client, serverResponses); } if (verifyConnectionClosed) @@ -178,6 +216,7 @@ private static void StartHandshakeServer(string name, int port, Queue<(string me } catch (ObjectDisposedException) { + _output.WriteLine($"Mock {name} - socket already closed."); // Socket already closed } } @@ -185,8 +224,16 @@ private static void StartHandshakeServer(string name, int port, Queue<(string me _output.WriteLine($"Mock {name} - on port {port} completed successfully."); } + catch (Exception ex) + { + _output.WriteLine($"Mock {name} - Exception: {ex.Message} {ex.GetType().FullName}"); + _output.WriteLine(ex.StackTrace); + throw; + } finally { + _output.WriteLine($"Mock {name} - remaining expected messages: {expectedClientSends.Count}"); + _output.WriteLine($"Mock {name} - stopping listener on port {port}."); listener.Stop(); } } @@ -615,13 +662,111 @@ public async Task ValidatePassesWhenTokensMatch(string token, string expectedTok using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { ConnectWithRetry(client, IPAddress.Loopback, port, _output); - System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken); + System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken, DateTimeOffset.UtcNow, 1); System.Threading.Thread.Sleep(100); // Allow time for server to process } await serverTask; } + [SkippableTheory] + [InlineData(5500, "A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.", "SocketException")] // test the socket timeout + [InlineData(3200, "canceled", "System.OperationCanceledException")] // test the cancellation token + [InlineData(10, "", "")] + public async Task ValidateTokenTimeoutFails(int timeoutMs, string expectedMessage, string expectedExceptionType = "SocketException") + { + string token = "testToken"; + string expectedToken = token; + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + + var expectedClientSends = new List<(string message, Encoding encoding, int delayMs)>{ + (message: "VERSION", encoding: Encoding.ASCII, delayMs: timeoutMs), // Response to VERSION + (message: "VERSION_2", encoding: Encoding.ASCII, delayMs: timeoutMs), // Response to VERSION_2 + (message: $"TOKEN {token}", encoding: Encoding.ASCII, delayMs: 1) + }; + + var serverResponses = new List<(string message, Encoding encoding)>{ + (message: "VERSION_2", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII) // Response to token + }; + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Client", port, serverResponses, expectedClientSends, verifyConnectionClosed: true, cts.Token, sendFirst: true), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + if (expectedMessage.Length > 0) + { + var exception = Record.Exception( + () => System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken, DateTimeOffset.UtcNow, 5)); // set the timeout to 5 seconds or 5000 ms + Assert.NotNull(exception); + string exceptionType = exception.GetType().FullName; + _output.WriteLine($"Caught exception of type {exceptionType} with message: {exception.Message}"); + Assert.Contains(expectedExceptionType, exceptionType, StringComparison.OrdinalIgnoreCase); + Assert.Contains(expectedMessage, exception.Message, StringComparison.OrdinalIgnoreCase); + } + else + { + System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken, DateTimeOffset.UtcNow, 5); + } + System.Threading.Thread.Sleep(100); // Allow time for server to process + } + + if (expectedMessage.Length == 0) + { + await serverTask; + } + } + + [SkippableFact] + public async Task ValidateTokenTimeoutDoesAffectSession() + { + string token = "testToken"; + string expectedToken = token; + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + + var expectedClientSends = new List<(string message, Encoding encoding, int delayMs)>{ + (message: "VERSION", encoding: Encoding.ASCII, delayMs: 1), // Response to VERSION + (message: "VERSION_2", encoding: Encoding.ASCII, delayMs: 1), // Response to VERSION_2 + (message: $"TOKEN {token}", encoding: Encoding.ASCII, delayMs: 1), + (message: string.Empty, encoding: Encoding.ASCII, delayMs: 99), // Send some data after the handshake + (message: string.Empty, encoding: Encoding.ASCII, delayMs: 100), // Send some data after the handshake + (message: string.Empty, encoding: Encoding.ASCII, delayMs: 101), // Send some data after the handshake + (message: string.Empty, encoding: Encoding.ASCII, delayMs: 102), // Send some data after the handshake + (message: string.Empty, encoding: Encoding.ASCII, delayMs: 103) // Send some data after the handshake + }; + + var serverResponses = new List<(string message, Encoding encoding)>{ + (message: "VERSION_2", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII), // Response to token + (message: "PSRP-Message0", encoding: Encoding.ASCII), // Indicate server is ready to receive data + (message: "PSRP-Message1", encoding: Encoding.ASCII), // Indicate server is ready to receive data + (message: "PSRP-Message2", encoding: Encoding.ASCII), // Indicate server is ready to receive data + (message: "PSRP-Message3", encoding: Encoding.ASCII), // Indicate server is ready to receive data + (message: "PSRP-Message4", encoding: Encoding.ASCII) // + + }; + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2)); + var serverTask = Task.Run(() => StartHandshakeServer("Client", port, serverResponses, expectedClientSends, verifyConnectionClosed: false, cts.Token, sendFirst: true), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken, DateTimeOffset.UtcNow, 5); + for (int i = 0; i < 5; i++) + { + System.Threading.Thread.Sleep(1500); + client.Send(Encoding.ASCII.GetBytes($"PSRP-Message{i}")); // Send some data after the handshake + } + } + + await serverTask; + } + [SkippableTheory] [InlineData("abc", "xyz")] [InlineData("abc", "abcdef")] @@ -649,8 +794,9 @@ public async Task ValidateFailsWhenTokensMismatch(string token, string expectedT using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { ConnectWithRetry(client, IPAddress.Loopback, port, _output); + DateTimeOffset tokenCreationTime = DateTimeOffset.UtcNow; // Token created 10 minutes ago var exception = Assert.Throws( - () => System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken)); + () => System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken, tokenCreationTime, 5)); System.Threading.Thread.Sleep(100); // Allow time for server to process Assert.Contains("The credential is invalid.", exception.Message); } From 0a404341482af00449210c503aa448f60e95f000 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 9 Oct 2025 13:54:02 -0700 Subject: [PATCH 162/275] [release/v7.5] Automate Store Publishing (#26164) --- .pipelines/PowerShell-Release-Official.yml | 13 +- .../store/PDP/PDP-Media/en-US/Error.png | Bin 0 -> 120539 bytes .../PDP-Media/en-US/Experimental_Features.png | Bin 0 -> 161370 bytes .../PDP/PDP-Media/en-US/Feedback_Provider.png | Bin 0 -> 167038 bytes .../PDP/PDP-Media/en-US/Predictor_Inline.png | Bin 0 -> 110258 bytes .../PDP-Media/en-US/Predictor_ListView.png | Bin 0 -> 146469 bytes .../store/PDP/PDP-Media/en-US/Prompt.png | Bin 0 -> 132747 bytes .../PDP/PDP-Media/en-US/Stable_Release.png | Bin 0 -> 179123 bytes .../store/PDP/PDP-Media/en-US/pwshLogo.png | Bin 0 -> 13152 bytes .pipelines/store/PDP/PDP/en-US/PDP.xml | 176 ++++++++++++++++++ .pipelines/store/SBConfig.json | 67 +++++++ .pipelines/templates/channelSelection.yml | 31 +++ .pipelines/templates/package-create-msix.yml | 128 +++++++++++++ .pipelines/templates/release-MSIX-Publish.yml | 115 ++++++++++++ .../templates/release-SetTagAndChangelog.yml | 4 +- tools/packaging/packaging.psm1 | 11 ++ 16 files changed, 539 insertions(+), 6 deletions(-) create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Error.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Predictor_ListView.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Prompt.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Stable_Release.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png create mode 100644 .pipelines/store/PDP/PDP/en-US/PDP.xml create mode 100644 .pipelines/store/SBConfig.json create mode 100644 .pipelines/templates/channelSelection.yml create mode 100644 .pipelines/templates/release-MSIX-Publish.yml diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 986f803361b..36bee13a0c7 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -25,6 +25,10 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Copying Archives and Installers to PSInfrastructure Public Location type: boolean default: false + - name: skipMSIXPublish + displayName: Skip MSIX Publish + type: boolean + default: false - name: OfficialBuild type: boolean default: false @@ -363,13 +367,12 @@ extends: - stage: PublishMsix dependsOn: PushGitTagAndMakeDraftPublic displayName: Publish MSIX to store + variables: + ob_release_environment: Production jobs: - - template: /.pipelines/templates/approvalJob.yml@self + - template: /.pipelines/templates/release-MSIX-Publish.yml@self parameters: - displayName: Publish the MSIX Bundle package to store - jobName: PublishMsix - instructions: | - Ask Steve to release MSIX bundle package to Store + skipMSIXPublish: ${{ parameters.skipMSIXPublish }} - stage: PublishVPack dependsOn: PushGitTagAndMakeDraftPublic diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Error.png b/.pipelines/store/PDP/PDP-Media/en-US/Error.png new file mode 100644 index 0000000000000000000000000000000000000000..48e96378055b5d7fbb4d744007c1ebc073da2453 GIT binary patch literal 120539 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

qKdpe4ED4mcn4J%^2KM0@o*9MuqiJ3p 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 literal 0 HcmV?d00001 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png b/.pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png new file mode 100644 index 0000000000000000000000000000000000000000..90420254a8e4a4720601e3050567db719819efc6 GIT binary patch literal 161370 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 literal 0 HcmV?d00001 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png b/.pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png new file mode 100644 index 0000000000000000000000000000000000000000..f4084360d5c630119e469b721dde87920d5a8346 GIT binary patch literal 167038 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 z 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 L$C>(5*M9y#()S`v literal 0 HcmV?d00001 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png b/.pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png new file mode 100644 index 0000000000000000000000000000000000000000..3b8d62284859c6ce60c96d643b3b2bdb994471d0 GIT binary patch literal 110258 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 W56C)9ct$q>0000&bOJEruf;N2sW%7_MGX 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৉_@RHYK?qICgM3gY!80&(!b=+^Y=YMc!;`E2uKcA2p&!DILBPtF4 z=~J=G)?yHWYSAU-FZ+8tWzg>|A z*mEgxn)dy$8U_E6L@P#K^rgT{p)g!YWk>(el52;ta*;5@(frr26bN7iPh^CwkxPJj5lt76h;vVYQn(??M75Yax@)`-=bCTY=+Muwe2( zO&d$#vO3DA6;Vpp*VQbl-@P4~n9=NGm9)LhQ=8b9qKs@pqccsUnC%IphTDR3=mo!I z9x+kYjd8)1NPTyuQg>$s$_bkUVsnjqe!0&ZeIw;rVIeWs!C;MmUR~)-fB{1Wmg}b^2k6Bm8*SQmg&y?4aR^jg=W~6#n}c?!GD1^B+yE7M)EZ{XkTP?!;iO zoKmo=cDOK8bvv+PJwZCdw8qP{ufpHvR6W9KOC~JJu^+6G@6w#Q_~?SiscVR%d@<~} zxQz&*uSpTIPmiW(s}Zp)?THcTe+67^$JbKu>nSgE-zV6VINcC-N?kiwcdy&hckqY> zYW$~P`oGP|`bKIB^_ZV(C3=*~o5qnxghj-t|HFs&8+T3L844cDG(A+#`hDUJnnxC`2X0U{5P+}yf<&UO{=x}h%PY;Ywk;oHRyIO~7~oas9#rMvd! zO4XLG{Y)QOBj&+7(1{r0*QUGPgemH=NH`(#6XD~LT~+*{Wl8&a)A_e zf0wM_CrndLNY@~e#W|(zFYAx0mlmDl67pB6bn{@jZ76s^_zSJMm-zgFb6rlqZo zJPs8rC&}@2ixR=T&@)~UDzs66P0359I51bq@N@^F$Y!ARuf^FQR-{tU83slM_JpT` z5m>)~Sxn(_Obl2Dx-n7K**<^8ywcXV!o3?e)mjkZO=;||x|C;CQt`uL^TtX{;MaEd zAx#xoQ>Ex>%=+e|YhU8Kn<8SDRQk&OEzAvDMm`r3JEr2b?)_Z=!bURk5nGb&_~q2bz%UuaxIlxWvI**TCvn7 zZ|LMnA_EyB2nE8gsP>lsgWzuC*CR8kG7)+3>tw^55d`9L(AaBO2Sgkt@75*Pa-Cmk>Qr-zYY|V&*<8 zyhFB_V%(YAkyc#U5{!tzG}!mQV3>N*T_v%#QZRE>47F|7IgQKdywfA2+F0U%k@bR@ zXwem5HQ}UX; z4xoyXM5|Yu=6rnkKy^azJ^w|(#xO_i-1hBhDRTXtkY6jj9Y%o zUVXNjWI1=OcB{WOHXKt^)CD#mdlNWUoVLAETQ( zP)o#4>00vOvgrno9$ih~1u~h;Izlj>B0?9$Ix2T6cg_q_GNez;70s!h9s}_JjPIQu zKOrv&qLxV|dh7NN?$HaS0 zkeoqpUA?(lb1UWkOeL1H>vUM-2-r5TPV|u#oSR31xtXaiJ#32v6=P@O8wIgwy)W-I zVcK$!VO zX)yMe!oj!3oSc%AM@k{f-?PXxvwN*M{=QwB`?hx>DMj{DOS< zFh=>cW>b@(T8qJqU$&6PMcbRKsN*W4`32_Ha?WQ}+a0@|uY@7}FEOOdRb9iZN6OU~ z8=SsmJ~ZLT+!27^81ntH4pYoNix#B7R*H}*Y@-n>rpNrox1&mN*IJ_T(I|(5qZ_l8 zbI)9u>zyU^as`!`+nuHEuu%_XH|X3VI3TspNW`$CcCr+a65p;>iAkMBIAiz|_ z4u2QsN8`_}&pox>ahW{L=s2YZ#|F)M+FM)mR&NZ>iRPTrx;wVEJzR<3n$4w;;7N^` zljN@g&uBv_9Z&J5EpoAY$ReNDsnTH9Cm`!GrmAiIFr`&elQXkw^amH;G9U}^+6~Nm z)S+^L6HXkQoFZ(`4`5KoJ($(ojN>Ai7Gi=oJD0mdq@PJSnikleB9>C zHLWw!1OA%#*v&?nE;rjU>*O0OKEIuvrpoDy+RrWkv(CQpsdFF-YRlc;CtC2uoyRDimw!|tY3}`pxlBc#F6JRxh{`c zxS-NEO_fFileBn(ibp&=sMd8|0}TBY>0*%q(^-$VQhufK|Hw;Bu$k#l$;KcKpk?nT zm#xEQyA}Jt{BU1ZUKUkY03YWPIvbs8{apqQvt;)q7*ygBJ3 z!loNW=olu?WAPfumm!KLAbCy-ruSrGaQE^q2Ineg3lZ5IBM5#jxh1pl8?D7r8-yVT z)+sZ?YKm8~BeBBnHF9ZJ)TiNVMN&I;I%0V_NnOYBp;*ED3iuKr68B!JPS2rqKg78D zHE?D;z{Du7^c0tXc=ZWx|DH+0qnW}(s@LO@n|GQgjuSKj7rzKL=Ry0#+9Rku5OW2eV+d@1KA?(+mR@=Al4Nd964Zpvpm9MEy7r zVgSoG%CEBd+O+!oRwW*$AAonQlDG8byFbv~ofy3Qz0hmUlv{geO04!(G*7TxR8+E< zDu!7Jag@VUm?x0{EoXZ}h_WcnWJoH_AR;K2fvSqL?X-5EV7(b`-YwWKf6SslGa2xt zIOokyBFoc6UhBWh(R(n-j-9xHFf?7c9 zPJPAp4mD)b#Y|AC25uZ>o{KVA%ln2>FsbZHL6-qkj7q`b&&VWMH?Z=RvB;ur8&7nrh!FMU91tGe-KJL8bR=sfKeUEDbX*N@JpE5hU zYsqQL?aEv__@L!Nuj$^o%x_ERNRrLny95WO_1h=?7tKSMt%p9`(&m7aoKf6}SF_JO z0G!53lu&h13CLE`LH0dv(mXk`&gq!1!a9N4rryB3p{{I zc4wU@L<)`kwoa#Y8?oN!f$d#7EFo|~N=k}s__1s#z%c+IHj{T_uf(#Z;9?LjTK|eB z^cNZX4>80GQ{D#|gOCv)f3h5LYKGFC95_x&BMI{rSeEfw`r}IM@70TsGsKudJElqUi2*IvHx@IGOnHaJ)v&_z@ zl)Sw#SNlqDb2-jy7Q@)l(?0b@2y@ZoCfV;JkaGa)d^+Yuzc)!bgUl(#&KisE_(lxA z;UZ5gQz5)kr$TYmWFK-!I{ek7p%T~bwq=iV&tZ)w^y2Qjdq164#L1e>#Sqn*a`jG8*#hVRfp-I6yQ00zJc65mCMT6lP|FFGwxvkr$|XEhh~JL2 z-{p9?+X7l?rEu9UWW{d0SO5lanm~k**fF=WJx9;$+et5JO7rjNz}r4fW67gxWoV=_ z6x`V6wK$d~pzTT z#zjY7a9=njCd{YLt-Q18In`^2xGETp6cdd~KP8c1#hGNU5@Mg>b4lom<1G z37k%Nsd--cH$P^HwxG9{+`L6`(+w!-tVJHhBJcUY&Sa^50#=6yIg?;B&&*mfzcobFGYV+>hq zD7I~Vy{r|otR=+j+oyf$x0U4&KvSJkXqC%Wlh?Sha(wXeymTbfBI@Ijg+5$PN2HaX z2F2C2`gHXQuHZ`dRtwI)f#R)U?Z=-Y6C^sgLk`h{ZlQVJ%_(hfEgKnZ`K^5ypIY&) zksVy@Gffv3!^ctR-uAgyZH*?r4}i=z6|mU9e_sk4?#EwUW#_~1ESiQGo2U-~oKKpT z9A#6#*;#t~_@^#NmJHp4BugzxqvW|Kp8m-oNmF64soE!8FtbU1X#nr}2Q5Ig`StV- z1}XiNAD>bZDrUK12`|*|t8mgz0D>}P`b&`jWO`9E|47V>wA{J})v<+#e`k|~SIPlJ zwz0f^G5y`l0v*k*tEO>!?7bC?+}7M#u=BOQQ$)J2T)05>2sNday=2?r5#|$JQEH4qdUcbEgWMml^vPSfp zm}l&`YigBpi0)A5lQe9bziXyXxV76cJ~UY1yD=j*5v4`OI5?g-lz+%h;3*`}4Z>AM z82||rhdsPEU#-}1GxIz8=9qf8ELTleaX$LUIat*0sa-Prs13UtNSg`4A03Ka+N6yu z3f)r&2Yj7=S^vd)%1%^@8#+Uzzq6}3|GW?{Qa@7UOx|An;@W+#-a0A7m&f`gn19Bgv7 zC$*6}Gg8E~Nm5Q%lgg~(n$Vhn+#w8y(3Mdkh#K>1nc6wfn8|^%uwz_b6GeMX3N-3u z%#9%Vr4-Mll7L!Gq764$#cMgzAFYt);E^UdR`|NNNrt&Cn)o@mx^WFR-Qr$tK7|?z zd4o2NNjF}I*u!Aw85m>UE!>6+VvlClZZ)lTLT7he z0>*~pr#43(+E1>4U^!K_4q@PQjP8`>9$G|tsVXPz1#HNGdp{Ig&+k* z?=>g$BKJUpgX^yW=5yL>`g0t>qO_d%_1;bgxsR)uwn(iI;u~(_=G`GNORXmSZL3m8 zCYxm36<41Wa*`vL3~tHNd_uW83D7EZg7K?0t0FQl*{BH+E;(!gw@kFGu|xc}2BIh*1vyQoVi(SNM7+aqh_nGa%$Aa<*P< z3jv6LsMZG-$F4|=s~8Ep*xh$N*FD%0Kn6JOIuCjYiu~O-o(@DLo<61XTIJj>IoMa} zJ9o{Zl>G0ti9Z#n!X&j)4b$)Qt`(?50ELJPQ87^&{JIb$Wp4ej$gfQy)jK5n24zKr z9wOze@Hj%*Qz8l>|Ds7t;69i&UJMoyIJ)-v3Cq-XRLGSB`e2=NLVSrtLA3COl}z-t z=5J>-!#Y*)W))K+fgLFE#%chZtnM*SM(7(+M+?>C++6dez@LU}A3&KWvrUe*t#+qO zZ}GRtn>HH@yOxhU{^%HlV0N-{NZMmRbbXVAtK*_z*C@|OZr>9T$?N19fta_f^QNjKide3A;W!+ z1tPUEr%s+cTZ?yCKXA0?x^?pl5kn#&tViN^@f4s6*N*qByhWy%yO;u<98~VKu0D|9 zyBw1|I%(|npEUx?kFq9SCOmm^Ne1#bDl z035Kjb-sOGH+Aj>teUnS`2w+A6lNMwCoSj7?czQ^b*G?Dq2Y0Ll}f zm5YEi73=-k#`W*n&re)zx1qWFvDC~EIz4?2gI{mLr=x4PqCN^O6iYwvmYx}Fd?+i5 zJt9U?UsFj!O({OUZ(I==^-be}lz80!pgg!3w!h1qCmqMy;QRxwi$X0EHV$ z;;aEeeP1sGm^=`OZ?)c{_|WgQ;=f~1?X%ZIV+CK#yK`&o^M$_jI)5a@R&Fr7R{Tdf z{9liRpJr!Lwes*_{5_NP-)^gYkVX|VxV7Da`0wTaCZhl>;2AxLPfQj?w+Gn!uh&hw zPy@yA;1JvW^_^RPIT#w7m^^S`4`rMGTDn)+eI^gzTIHhsDf5RhKqT6Fv+)0V)E=~~ z!a@avs>CCE_tM(*pXZr*03tapxT>;01sfE(V5S%HmK^!=mUU(QFep=^l zJ1Mv0ojdO!wq&}xfS|#y-&Zz(rkGPSA`E<5RQ`bc0WjatiUvW%reQG2vfB0^<;cm}saR7N*^ffALFHqu@Q}Chj;PG9)qx)yIcvoqyec)@K zKKxa5{MX&?VyC%?TVtf_OOB5r4%odM^Z(%OYo?PwgynQUi)C%5Ke6!oyFd7s;r!-< zb>rb>-H9lIDZn%i^p{!h$-aJ}TO`YSz*n(JKdamyyfRJRf=Bujw!aKU3I_P$Ui@nH z{H>_|+)mwF+A}x)h!IYRWtV)Nw9i+Y@c|euJf>lB=J$vDU)~aKau~!{cCAC^*XH;1 z!6f`X)8Y~TZ!h-MGN+Pi3@kG5nZ*9I0nWWPVP^dD?o5mhQ__$lMsLDaDWNmDD9wmkA5QBuiyOZhkG%AHxGnF zUHh-|{QYu)-Gu^M!Pm@>r{ZF_d_b_{fUvs^tr_K1Xv z{~uiWSBV0p&bo*bK-3slF!*+V26!H#0`ed6ncZKo`GFre4AU{kvU_{q+3so6v!8^l z<;_CuX#!VgQ%c7U&>ee6$L(j`Crh_4)vFfc4IS8+D^C}$nkntih!PA{h-%o+ppUf% zXt^NV*!+$*?aB-=J(~>rqn4cKn&Q*8pQqecnFFHd)opo~sUvf>JKOezL9b5T&ScbwzqVZr-wg1oN9lgHdO~dFa@XMzDKDUa0mLv?Yr|W$4AKB zP^5lhe`BS(@QU$29pL}j=0C^;ewxjX%sB*6C@g?E>>O7P9Eyol zSqM|!963Qv=rxDL1h)dc*|`cnp$>^fjRQnZmHf64(Ik@sk!(Iw3&~iBqU*k9-%_Oy z9!hk)Y0y|^kaSKROij4Qs4%aR*8lYghD^WkR4we7Zpu)JqiI8|$FXmsT9SA$0`dCJ z-AtvO^5;bJDUqhCNt=wY1T{|E^XN`lf1_LxuGTY$v{H?knBbOes#(`tvm0} zy8yxpHd{Bf?kz?GE%*AQ^}?7Sr>1rXT5}R#H*9HkuySekd#ORJG)gY@j$~0?z_sC>=+^{U$}-VK5Q#gR^(I(W)jo}9~x6E3?es`865Sde?r8_DIUgvBN9 z2j)@_!>>*FT?!retl0eR^n-ln;=Iy;VVV5he$~FyTykFb`rOkVg1rz~<{oK*=0UR* zQUOwG45r%XzukGrZ1myATy01n3ukqbJ=cVLYy-xi#GKck+pS_h9{Pof^@p@;ywYa# zimL;LCg|40X*dB^(_hM*pI4R+QrAlL1+3;AU1}P?S6X%x86_zf9nn!X=+pl_y+_$? zxb6WuiR1l87Mmu)2{4qNKE?4art}B*`jlN}Q_ymtvTj+`y7F^$?Sf<3yO0eF*K1GQy$u;&d`Oux= zux-CSh>az3ZLL6m(9m+}`&Ie9W2_3}5p~(I=W-RtJ&LAVjg(w`a?__x84bI0j+8la z8{CqiizS?LuX<^MT)mymr*+>ygUvJFL<^Ax6->r{8U`(DUYF)EC9X8j!F2saC@q;9 zJ0J!0R#6mZ5dYZ$rzCy+$t7|@l2v16FL81&8QR~W=<;I~{m@ua0lyGYvk|Z7g5z~- z5zjtSRw@5rg^0$Mpi;ZyQS-D|x1fPZ z7UQTSd-C*W&p{UI$yfD_F|4@Pc8+8emQ@bnSk;Rd|NV5#ui&^nh=z+t)g|Mjiz0}# zfG>NZ?L>v;Y_;DaLBw` zNU~_7B4emW_~YcKmz2>H%b4ha2tlCBOA15SJ-BYJnhwFm;V;+U`^9tewaX z%7#yZT@b=v5S{`hI`rNbt>Sw4s1L5c}>WZw|m_F#5_#zUxwDZ1IV+6(wxY_UZ>ic91{C?b;HFBdt%#_iNVZG}>o%q4nrTYs50VU%O-h=_yeCOO-8As4$*;dIHe=+-e zS|uQOuR9=F)p}-?d{ap!zxm;03iI`?9<-8_-AR8S8o6scC`=oO{_qE+=nBBPQoDi?H!^N=jp|25jQ3&yF zlx3w)D=u9)U(0wj+q()6KH);9;eT%xWRio1{_rC+&8wnw0OE?(#l==>Ar~YZGD@f& z(pj|+qK(gVm)T2{^w-}g3Vv|n8;eaAaf2jAPd6<&%RUA35nie0FyD##;89usaVf=9 zdXMG0`WLMZ1xs$R2z@8BWi6CyrCHC+mP2_AeP6%y4mNB1QeMWB_pT_S|GXBAX zocwbnau4xAYT3aTA^_3$#FN)A>j?p6@TQF8MHC_ZwZ1|o_XDf1#InxHIA_|3q{IAL zOo4!Nw$E@t`wuZIxR_p1R8BK2Ge}tT3|SlZ*B7IUu&caCgCXB{F9}inkX#@s?lb$J z@yUPG-(Lb-eq8tQQLKEFD-f`2%cbwe8|I*ZH>?j6y*hN2oZjGK1;Q19zWjRhuEjrl z)R+Wuv8dEY7=Z>89WxNjmxoOr1(R&_72owd`QYhNL~agp+H*b>TXWw%g-%sQZ z2V=vrK*v3))1lYh=zMyY!U$NdeCmjHSxr=XQlUf{Ohyy)+SaCH^P z_d2=3xERt1VUj5*F>O56B~9p)d;Tl$&jCv^o_Tz#&15p#{iKw969oI-Y6pO5lYBm8 zKX55TE|yuY?M7#r?0N7ffe zZ$WMQAZvuRQ%PzV=|L~U25GjDzJTFU12l*i52#I)sK^%-c-#4edh}t5qG+E-;q3HG zjyd@`DR5$ATS?~}&~yrxago433JuK}8U0haAGczg1>cUkKZVY)bWh(JAHeV9o}Ec& z__hml2!4Q$ttxc<7%%aOmYFXQ<4tXE%waPpN>a{+Tk_mFlLHRTUv+JC57KRID`CaX zmR#gN2{w)*vBnV1i6p4+7Q~VbR?TfG+t9vJB91Lmes_^Y*_lSkvbFZIjaX81Ny6b+VY!#!yrAOdIYg)h@0 zT`Olwv+O=^!zL8G(^78ms@5*7M?ou3Ym~2@*6<$HWR1nlN<4x#9-6LRhdnhY zc#vGsyN?7#SdDkFDX8%K?aaBTvaK71udc8(7VNB*)LNdRF+siilX_uO2j&RaGLEqGF^L9kVY+ynTyCh|hONzWDDN$)2Jyz{_b1 z0d(=Z0q%XhOeJ;W;32`p_CyM$BIKgU?;X_tfR#!hEky_paK`;MPDc9?G&PN)u-lvC zi|Sa>_IhB(fB_DS^Q<(f=KeW#xF;p@%2R0rubu`<0ZY4+qvPOjfr;mt;5Z%DmCOTi)Ptz|3N=O)b2F-R3LuCDq#K-9jVjnXZOeCmE9V+ zp9oKRPyp-LMom7=;_(lGw7)sr<(Dc(AA{DLp;q}qLYO0tD?Ris3m&%gJm@qJ)=@U) z(yS4Wwelg^ddxy^ZAk4`j5ql21XBgQTLxNBfQ_!U=>@79T@IeV#W!Yu_So+>ULGnv~X1 zxN9}J>*H5PglW;L#!h+J5dR$x&#BL;wk@FSn; z?dhw<5UkYgoUT>weKthSm1Li#<2)eVGM>$Gv5@uCjDQw}Gz`z5=Hg5aUzmm#&A?)q zpXbxX5ge^Rs87xA5r0|ZB#8R7SN}4HOW@$L5N0(fXa$%khyv!%C2a2bcjIh2ZG$ES z5A1>Nho_$izwaiV$32;>Uw)|`$$Yle`3=r_X=`RcwDb}%gwT~^)7?;6*wzT#g0XE| zYem{(V~GwKi_;qY)@g2Z=T})j%B;Xrrb zlyrv&`RS?ua^4XCSh+ z9cIG%W@!BNmmk=ucGv2+3v?kNTR)^(O^Jqs60 zZ#a*Q{_dWv+_P{HR5Mjv37Gj@Wn&%7t;ZdB7MaCn!Bxhx%6ag%ygQ=$Qs(;y5Z6eC zEG&_$Yojf*-ZyB-9b7x-Qnk>OrCq4p{c>T$ahDsUX*PIOW$@D9LFFec3THd)1p~=u zAL&*rV}3vLeWetdY?Urc)7e@~;jp7;lNPsHelqV~+;1g)19l?=s)=xrc1l zMpPyG$r=gm@&t432WDc`bnyi8>$swoO5`& zHXOfYpK-z6+tM9c(ikLO0zTi?ZAVJl7;|o!p*TMNI*nnDcCmF?xBA`PgOiGI2OL2& z$1&sew5l*i_gv%!J6gds+=0|@(n@*x^RK({lds0rBcO{4b^*a@^FB4wuAUbpc%=I@ z-Fz}q9jkYomZIHlJztZCG(9nM85FDfGy_bDd4ddO4qqE$b-Aa42oWtr1UMEy4nX!s zlWZmm;F_yr^R6{g7We_XeCN%Y$n2&_`&&FVpY22&8Wqshe<4NPwG-i0?oibHHITnQ zpG&p>yWH;<3=5)jPbYSk-^)Op4ZO==m6E0l?FWx--LdX-mp^tU2k@960j;}JdJH~g zHZx8C9{BHGlzZZAN{p6dc*V<&Y2z0HEwY_G?n+81IVbUv$=(SQ#)`HsY3w;y61I(K z$C>uZ(K|+SRbpv28&0G^mRUEM22)_6rUvA1X-;;CR8U8whM!i{B z=X@3S>JVBN_Wo&`Qhu|l9@)l9WQ+~jf4#bm^?JdO&Cik+aIN6SuvlVtKr%ZsYluK{ ze-mG%$%_rR!mLQJ%XJeEg&!O_PBliaWL~KIN!D<|QibH&eF66_pD-^W8ZIkq;Zz9WxA&Fwr5$l!6gjX$wh;(#VUXphV#hU{W+*ZDBTh8z)J;;6aP#G%n0vDf!t@cu&*%rYffT zxI$Z9A;JNe#P2LR_+%-lFfS~TFtlC_I)&}xHv%9pD_P$tX}fMljiC~~Sx{^HzKWZA z+LnlSyCC=*-Xv9k)+4-_`+2Uui_#|o#f<(iV3knC{KqmR?AI-iD^fhtMJdAfAwe$O z1(Z$A?lkBYjEvCiUg}xuomlOeL~L$SJkwm$cs-5pt)9xh33=Px5S00*)l>bd%HEnGLdxfEO&Gt# zP{iJlqC0(_`Td zufH*HtL^|UPU}W!oWPg@(ym3yxBDLu>8D0m+tczV-(-lD3UCM&CWs@cZdc!ME~0L= zoo%N6N`Y`bI!9!2Y9(lpy8|qosEWQNlUO5(ju50xZtb?HO^arN6A2q#I1QiC^mMtC ze4r)@ft!@|AG#PEYLO$-6tm=6LJ3SEk#dGY@)wd&Ry>|Hp7(51T3gbF>}m*_J8Pjq z;=pZ;tE#l`i5tljg`ZK2u=ehSajlPIl-D*$#5{aU&(f*o8J->)2&Q`jOC)7~1AEL@1UQ$c61$3}mm<20% z#S$6l*V6Siz`djuSKH^Cu?12@+m%jZXfWbavOkUH|4vEZZO7k-U0V9VpL`10OOt?_ zgO!OZde#tHGIwq_WGv)1K7N>#GIyIMg_$F7qiuI`F^ld#X_Xk<>O>4M0p=g&8l>pV z)AWB}$t9+YRAOUXVk;?Kc@wYI6rU@b?qqj+{6NcxW1VnuIdkr^6O*t0f@&4t!{@Jp zP|ROKsseSVi`_^twQARm#;JrSb0PPP)6(1g^0}>*mgC{4Hl!*p;J2fi-Xn6t-V*v? zy4i%^^{vCl*?WK}&cXP@2ks8Y)1=RUEAE+ z`H`ako~yegvpM2Xox%n9(WrPdYXlv&TJ0t^%3q%WJNSZdCN);&47bDc`!i2y4ly1* zWPh6zp~Yd#KQHj$KL6np_r4V$^;qQ42^>BdNu*`G1PWETaPt4*?akw%ZomKWa_f%j z4nwJI*@;M5vdhkd?E8|T1w-~MLrU5AHOoxdw;|ieuCnih!C=ZZ7)xdh#`+uY`%b;P z-`nT$eLQ~u4aRFZ=UnHU>v^8%T=(C1?K)*!{X>x75z&4wMyi{X0f@u zd1HCx(ypG4EGJ-7v}U=BYD^A6DKL;PLNSQ`}ZFM2sEmcXE}c#R>{z& z)Z3*H(cP@wK)|U=Cv);@cws~SEa`@#K{lD9K^LRW53JFJCDWq@h!U+=8gqog>o|9c z3uz&F_Od&&&Cb^Vu5nZY7}mY$h|*;fo0ZaKs$u`-@ArSlNER0yeSu(^Gr$bV`#46czg^11|Fuft8J!^BRR*sXHd{_@olaK$ieZUbiR@gz3u9#-F%79@Yjr+W@@O zyza>GRdSQp(`*`8?3n+}2y9mE!ujx(@3Fw6Ic|hd5Jx5<&gE{Y9tNfhPBl;0UnNhn9@+*D$@0IqGRs#ss? z*1t?@^!$-J|H!6i_s3(YJlL<6DAOWbAero`=|TvAj><`A)T0jo@;17cJ?p+pqf4`F zs_asl+U!*S(Hj4Hv8H+2Z`L-HvYZ7PoV2J!MU_=HM~%uc48$V852u&ghpNFdo$4>Kz3{U#Pnrw;ePw|MBc@Ru$#`%4ukL}b8Ga{Mu;#J zmz_m=8_sy1-@f0gpPcIgYbt)%de%;Gyg0B-T*xInQYvVnu1~i7T3W-pMJ+|U^*elX z(yM7JhL=63x$QiPdh7d`mzAw$_<5Ym(j~j4YjP=i6{Tf5Uosx6|359gRQV?IDuBCs zRx&L+kh~zTa)(F4C4{0vZNlyxNohDBqSWzmDknmkf%3kqHJJDYe+@0_p8pvUVI*@i z3^U_QmqgWLsktaj4Tyn7%}+#RCSvXYh>P-zyy)< z@rOc=pRE67Q|9m|f#Fw$?DtD$LT~T~IB80y0#?sslwNaE=G6NG);(yHeHd)7Ba`fA ze)~A%otXAN8RNTrat@gxmFFguvaTOn2KS1!{ZK<;4dI+`!k^Fbq+KZC($0V1%c{{* zR8a!B;Im%4DRR15w|oAJ)5hBhr)n3-{Ns&mwZJs|9U?^(cHznSzicI7irjlK|q&CFP<~5uV)5RCodXsRAWLb ze{LYJwg@c3aV;_5JVP2r7iZ~V5%U@ot22Y-c%(@%1wEbXOsIA{EBoF5j#`n`vdxMF z$)A6+)zUs}5qO`{Lu1=#t-K^K_A~P}^>Qt-DM^bCB%*^&whF$5tvW>L%&qWo$F2bR z!6A8V%FnO=FTU?2g(4Z3a$>u-{9W46^StsA0|BVfNcXu$oO(-NX(Le5pu&oQ7GGa{ zC_#TJpT%$ct$vRqC|xwBpj`P=$fZAw!Rk-2sF8_BfC=w%Fmb!a&k~Gyj9fZcekfZ$ zS--M^s`Ba6=u=QmEvEO6$a64##mDsJM|i1VdsiY2)!>+oU*j50c!vo4B4%3-gf{of z)Vyo1$AQy%+Z433IHN79{INC)sQ(m|emJ=P$Y+#7u55;a9`SQr&RLbk!5_`znp;U@ z*^ToZY1|BNdQx#b>QVAbXfm1BBs!3xBv{MoZA>Mz_bYJ-Fb;SyM6~vBu$Qt<=ULGA zA~JTpPOkwcNsywCCZ6w1LFN~P;*Awl46OANP6XZh4ZVy6?;;9?!t>P_;RotpCiMiy z=Pn)ltaD0MBWyNU8_g&7n6@bs;Rp7Zo%BtbXt-k%T(Mt9jXWI~9OY`$9`wKYZZ0x$ zR$Dq+&kJ)N@P~fD_XQLcQ;{LYoXnabLhe&CT!A9%cAb%xb5*>x2X&je8KV;Z`YH#r z$$XX>_E=aaUxz28d+Vu%t(yR6rzWMj{#34!GD3Z44V<-kf!D|{H+H<;Sv8?=E(Al} zFu!ctFrT6&dQqmN$4^~Rz}ZKpS2^9TKQ6PEF2DZO?pjANWVwzqd}S2jE|VNlb5oq9y8%7lnOHHi zGU{jUW>x;!7Mx0Z6kBOX(+wSzd`q>_Lqj@s0>p4i9Kxwk-4`=y{5Yo9;`w(6B0n@zc0c6 z_6oXy?a#0Sy&*F?L&OCG6SoO7a`QDs^)FZ0M|N-;yXMWMI797B*XIkP4>})O=4c%1 zm-J$arzf~r>Kom6c}wA)NJ=<%c`x0k2VCQd#br z3YqlpPDFrP1|KMxq94$;FV!tqJyzI9syttcKg`|?5AaQvP zUoncCnnJ);>zNv36GolNEZQCnEIenA*Ws(H-`X3cwq#jS-X3nt9(H+D`R#sY@z+k5 zhVaNAY)7>fxGUb7+6g%EKNj-Xe=}j~XL7IP1lUT+t4OZ>Yu-Sx(`1eQB0Eh58;cLk zMoq?5;NJ2+^=VF`+Vf*A0lELus|okP%;BCO%JzrO|A(a$z(yv%UV4poy^4bM%Wm(4=KHHyS_$$t56kbM9qZh}I z|6i|cs_^9#m244dShH(ZqoS{Q--@bl z(L$SHv6*oP=7$56v%*tQQ+nZBUiY-L#tZ+TP=fANQ#^U{XWhY^>)&4_{6tK21i9(=AOFiW|9+=8 z!K4d>-O#2uPB`SOI>-eq8_d!r-0e!viaAc?37FSZ%&vZs{L>t)oXOwQ3p%zx`H`di zwc)-f{{?O+Q=%zNwCY1KtTB~Ld2KbzOSNhIc)9?MtKU3naGx|5&O(k%|6L{dv=;W8 z>pfG+3k$c&uSQ?}qNF7OA$5Az>rlkdzH9%>EW_pA^wr-!fXBH;H3qo+J=+P;A!G61 za|REPPL3IYTDGYP${FlF)Iy_Oe`Cc-D1-LFqCNM|j+FUnt$$ZhK+n~ylk4mkVxq-B z!eTk}*@E;~3E%nd*EOF{lSmz_)h{3`-Rn`U7fy@czS{o)x7flhWUKj z_>^IP56{|5>z|HTFIY@*ltAaetCKV)KacO2Nt{Rdu4K*Ynf8|Y@@^SL&D^KVY8{Ev z_)Lr!%a_P^;q;nH%E38D=o71_!cunz=X^tJF-W%tVCqj{{!i-+*d*_T$)Xzu9V1`| z+hM=0mz;}NW?wbwlYC4Q4VmhtwcPnMwk*3_4+*Fccf+naqiiLq19HTrnh(pF+V#7S z@sm5`)T~bZR)YyHWI|`+$bEvNyNK8Gvn)KYnR!X1_Ugi7i+YK$(g)`S9$$o`k)*~C z?~8bkeU8M%fClpWF`h|dzturQPi(!)S2av%w&4A`PR;zJhw4sg`X9yV9(6qRjATXJ zU6%{Fv@UmX$)|l!w2n2T!A;FB3e1CGS97*f4vyVhz{=Gp4kf9fp+!`bB(rV$oi_Rs z5hHu(b%A{j{3K~{{1vraQw{5HYGNbGas$nv!6Y43l#1LmNXfguCMC498lt!$L^9@p z#}pgY^jIWV2liMh_reb={VNA)s-vuf%r(=TESEA zh`{lNJ}jS3iLKftzh)LJ6ENW$jBiy{4K7mLuxJ11K}pV$R_nGn2rz4DgOa=0n`o7r znoo}SC^Z|V0QL6Z%ybg|a#nFAL^JgCEtBGjlN=s)lsq2`*nBWLvv8LieFG*Qeo4+N zI=N@FWwxd#`hp#CeL^Hc8Q8wb=DU7k zp~--{|4J~07vHNC%}7N#dl~G3>Jxeg12#dQ;t3leRL!g4hr5s4#o$if%m~4+9qc{3 z6Qg%$gy7vF&)@;N+e5;Jx!(dr|L&ktRplhkRa{EFUAA$g%|Bff|BI$l-if_=B#WNl z{%qJ1(&-R>^A3(~W$^bSFI2yf*v>}4Hv(*;ufF3T>mK8bFsLpGwK_^OayYNj%ttVY zZ9-{s4xXPz?p1&^?5Rg>NT!y0t0sJIKAcnfKLV8w3;}A2?aT!sG5$LSz2(EX#s) zmVg)CI9UOo?A*tflw2bfiTgGwC3`@=5>w7D0ohgI&+Y+Cev| z!&t}0}pc&;lkBMU0&>6opdbVA^9VMmh2ZGXbjZ~`o2WIHSNQtteVkYqw! zOE!pS*N;(mh1V%uoToNl{Oz77{@$D#mi>+WsGqz!KFg`O_bsNXeOuhoesI)Yzru;V zBCr~4A3~HG8cA-qsN32W9cmc)B)auV0##;MCScLvD~?U-VZeVL$M5s3*B1X#4n~P? zsmQj?1+gug>ZGbqA!EH3z$x(eOxP)E)S}DsK1--tI*TZ`UTb-zd&<08suv5`Q#w&A z>np`}byB%RYbD6_MsH&*c5-i{0aZi4V$!gb1)Ui$G9Ph-!S`sjfK#$vg{W3{@nZS{ zY;`l<962fhV{_$0J>ZA;4xu=UxShMPmo%hdSlnmoJ#iMx*aKRfu0w$c=~ow zh0KX(BRmrS>3Zb^ea}n-Lo|5Zu1ehB;w0N!paYwwU(-$XYFAz)*9s1~Jf_ zy-~M!@0vLXb*2HhpR8M5njGKV*nX!WzIV+i2}F@aF+0M+XWyp>hMjF|uuSoXRP9Ws z@7J@MjyvIB@|d!8Q$ZeQ3m6lHMn+3p%Zg>wOqod&pm43{qJGW6tS*spO%tAvb9L?7 zuF;41q&g79Sx(gqBvM5qRo>fwbQtTae7r+XnE^4?zQqo!dn3NX7&Y^LVt1LZl%nms z%aXGKlSgU{lr`AqI^``gc)F`mnd}&(HJr)`nyBWYWk(WoZ-&~L#io$A54;L&2hisZ zTFMeR5+Kp^5GMeW*qG#v?q24A9Qs6>xaKq7A1q=w+Nv;OO@r;m z7{Ce64qh%SVlzpcLUlj1SHQ-spsL>w6UB>6v+avIE9Yo->*8lvUx!OKCVixnMFOq5 zcOys2CZxSI`!@3hi{gtP=euN+&9fqDdoqODT(9MYV65E9OB;OF?U^N~GT@$(BuH0;c}N6=`J)o5;`@5aE?eY&k{x&vW{bqwMK z0sv>tXAT~=+_t9jHrWy=pHn6W`0b9k>-OD^PnRBQW;XHa=YacM1o`V%MvKSa(J$xI z@A0xMKYV^+t`8Mw^mf&3@$8{qYHFW^bo+8gY0|+5Sd^Ztm849=!fR7Fs!1y7Vk}=C3k*&pEu&sq#Uh^TpxT#_y3;W&#iW;-g3njC-ge$_i|%leV`wH zswl20iv(;gG+e44_xTcg)mT<3#``I0#`?FV%+ojb6_u74tRHxW!YQBoZ?!V0kT-?; z@_#MW3KdSHJ;Rq$I#wf8!4F!E)-z?1GaWB$6;)DI9+Y8om5HglOyfA+l1V=d3?;e}(l%OJycD z;oEg~8^FzwY0|m72&J zvX`;QoLVjxIMP9NHidT4)48unv2w#(h%zBL1Gnm68n=KuZmWgiV z8&2Hd*X~~-)nUtXseIV)xP<)v023le#kaER^%dVq`2+N9N}-T4k)CiOuBCQNz6-i7 z?VF&elK3J&=mRg47G?DCfs>^_L~989vc;VZP0DDVw5+6^Fn)QrefecOfT6HwkmF8S zcB3Dz14=QrYlqnz8LzBksXuI3*_`t8UNPZ2^bxzAagxQ|pl68E_HNN^i=Ov@1shKh zA3JN4*#A8IH z5kmKIP$cvE;oJGGe*0n4YBjY0ciQhQ#mb^>rAunphALAf=)DTNTf*q0g2C|O9tPTe z5A&+Z^K(0IMfV_|$1O0ToN}W66$h=A85?I+9)LnnrOC7NEoqmD_7Zcsvgo-Kt+C}; zddy>b27_E|r4s>D5rMUuWE|SbnnmUf?r!vNb(LN!h_ar3ImT(9A}EMn+F^jO*h#;( ztG11A8p9Rnm`>0*$jU~%EVk_vUdR@@7 zjn=64rqx~(HrCuUwEwnbc%&J(s^&24nwI=mo^Apdy*npp$aWDK;yY8VM{eU}x}vVS z%+ADDAO*T{x6sXA8<#CA&(AF}fOhJQP zGMc6kysegCYzXxaNXOj~tgPpe?ER|8gc|`~jT{@bZ%v!`OoIW0oD5Mk+21nAs~nzTzT17Ff#YBRyc0=*L>B$!HZds0*C4yP@cnykh8_G^XgrT52c>e zr+()Y?1?fND@q%r-%}u%3Kbk|?hdz2}OVE*sEKTR5ku@62uX5c4+g((s z5+m$w9_;c2YS2(X>L(5W^PY7FMxZSfUF7@uXIc^?D)t!}-^L}P0g*&+_g!q-+JIol zTNFhGXrDDI0-Ubl95sM*?;%`{s@WWYII42#_N=+zN>$i(t!c$HDabrQcSI?Me-kjM z7P&4HRAt;4WTJJcYtP7KKKcZHHu{v$KgHuCpe&u7qgUF;yK-&No@Xr^=Bv&7{2k>} zU9$1v6s-6)N=I(=Fbm8&-rBzy+tA#v@qFP@LUk_{i@vdp$k^(V7~$B60kTC1W=`u7#eGMx^6wWSnry@&{3*GccK-~ z=)@J^-tEMGSt-K&R0I%;E-KwE|Db58J!|LM;)=_#DSS9LUooi|P)!a6uWGqoi6Y@& z_pR}6ar0Y7QoG~k7-@LPn(puxc2N)9TbaIn>SU=}NEpF)`m>SsRxF`;_k)r5m1PXY z4XuBL3yP9++`LW`*2^lFx+s_-hupD$Zo}lGT{c|q0vuI$)yY-kUHn8H6P)?YG+YBE7vdLu8>9ZlJ))MtTb zG^`myxLh)FS8`O=F!D_*tVLmR$+#q9dPdoV6s?^dv+51qq`UVr^VUQ2!0y2?UPF7U?RB5^t+BC~H8=Kd* zl-ArP*hn0`w?A=BGSrGOlX;h?E!4ZnW{!j;xU3n`#6WJAmK`N+KsGCFBu56HS1FYC zQA)ZVI^@ag4Ed>Ka$h=mN+56^v3K7uO8gqO{Q8|_nUvF4X1G4&jPTP&ziuz@-6i3l zHJ@KVKTmMoX`;R4HaRJuBntfCj%hg|>j{o5yk5xcQNiV&4 zM*gm9)xd|wi!&Gu;NZ*nM%vYmx^jj-Z2RUUAbO$YY4FBo0xh4sO-K#9%6`gwE%H^o z@Q>Q9COH=kD=p!@SNny8?I}V3F|!--H|{vMTZqS>5I++R3E(k8xN;)k{3r!7K+&~M z8x)=8R296jXO8pLrROk3I++AT%?8LWqU56txia^g>eUum05ma6<2A{ki31}O{cUGs z^(8KF8oTD%OwNW~^qNY0o!E2F6Dz$m6dRM~elBsgHudogA zVkWDP|Apo#@?&Q^uWkjPDQn=wutc++lfD5)X}R-sej{!7zn*v**rX8Rm$~vn*~62= z1EFWw+xZU6^(8a5pu(bNH|bl?MIIq~GVL4A2YbZo_pex}jac8ndPMK%2g*q}ssqzW zud2bGD&zEABV9zhj6Q-_HncUK-V4)7V(r~+vh=*xga2^g8q1A*sfHx3pln&l#L1kQ zX2%YAcn=vf%0oXoA#pFy(i>b`pjT^E*RbaYiC-l4lyyms6|HB9{jBdJ81RPFNm`Ds zGPZSf9&Af_XVkRuT*Pa-i0$RYgX`xm48JerCQ(=#*p?HEl?UYa#_PaIlfoACDD7L|tEn&ME#P_MG|8O@U8jq#tbsN5UL0KFkl z$ivjZQ8p9Gw^$uILV-hppu6ZR8G5CDnZXSbxL+*Hee(7XD78C*wAyWGS%6RLR;bir z7PW|*f(@hqIebZewnRK;fCNI!zUhgl-uW_{xU$gV#o~M?T)yB@9Ap`M`Jlx^ER=u8 zEo+T&`SYe3mITRF59TV`+(gQR&m}bj4lq3+jwaS|CKtagLXZeT@Ph||-Kj^=JS{q<71_y~c_ zGCj`Gc9M6P3N-Ei*!O%xaVlv@|6kkN8%|`kS_V|y>-{RyQy%N3Cl6hNZSs97V-5-Q zjSHO0t84;^_lSk0YI(7~MUiiG^&Lqe@1&X$6|?Aa?f@$5SzArU5SFFbRs*)M?TaB+1A{QmN;DGm}(WG|DVVR{E&$EW1q4UK_U`r4Xd6tr>i@YZwVH;XS z83P>W=hYSdc1uuiYr@Jtc}-p|YlLpM#-naubax)zZ|{&^GLo}Z9;vn{WhdDP*R9|8?h|+v}N5E^rVQmj*pKN6G5d`D--2ggw zIF}ix3#IKnKv2uP61AH-H817a17xZVi)&tvBghqu&d?Le&DCBn+DfomaSl3k)d8juggz@Z+ zDkh4qu3wp)7coGFjIi}_6st`$m2fh=&@+}qCRI74{!z~BKLe56$!U0GzM*El`=|@H zwVT~XZNNPY?Mi|Y;Ml)Io{H8u?5Zt zM=TJbp`Z zJ_upQXRFKa0o@*?*Vthg%XwdXDPKIAbbi3&5kH%Nshr=h=6=r_Nr-l1o2;K(y+wab zNU+9}G`2w{j^&mX^wX~|e=8q>+VV`7F7Muypl|6k@LPu0Gx9&q)fkJHrc|88V3Ah8G_b|?O@!alcTay30D~}qmZ>^yx{2waWb45khXNU|mEx|3 zx*)&erSkKRU85w2Ec?ph#CT#`G&W@X0Y55IZVTskKHfxan76*3^ z5qoSigE4n02dAe+W;xuIZ6<9glc?rQm`mNf@Wl@aFPMo>sT60lQuMjl;--2$5_8IHqp?t<-i8wnd)BID9U7bE zmAT*uP;=8T#{iL=i8_L9dUdLWP^gdA>g$#Kk1Q3MHH9Vn4G+XRrL?bJG$AYz^S0+Rq2(j8QQcd4cFw|IDVh{Klc z&EdVNSzAGU#<4$I7ulLcq9K(JFTQ{an_n=a;jib?GM@>TBjb+4jnNQ|>3i|FfIWsZo zaQ&kKcHDoW8eIFQrN4=OW^s@2wNb{qD=k;wQIK`7DV?L$jJ*4WM4sZi9|DI;=9sxH>tfRNzhUz4>lgsNY`>02GnNzo(2Q}$PPEUU%#+cl$VkFaMY<0 z;7Gm=`(yIGw*6)DWOUah?z+G~{UvED=3AI?+>oF6@vEKOo zsB-7qQk0=trP2Kr(ab~jJsGDakNo34Im6#fm;?yX2b`rB&^u^(m2t|v#_e(K)&74+ z$l2id_74uDH||5g1*JQFm`U2xZO08OCj!K2ZwCkNJ?XWWX80G+S z7U*ips7^<3Z||hf48v>N;xHZG?{$LAm7ByYTxAdR|GQK~Xrf0)V--8plLXAm_z{2m z!e4ilJ9#oB;<{RV(ME4AH-FdZ0zwX<;DJ<;J2ZQiX`*+v)A+7J)`YTud zVN?bbdr1#_^`iEqABq8RpQKOX)PI8e|A!0wqM9P=Q6v*E*mv89itp6_6Q_@h#OdpK zY4(e%{`XhCszBoO{eEujfB%nPgd>;Il)32Oa=gO+t1y}#{K@Hy{QsNN_v67GL<72# z1Pw`Ck8$iQi6&D3OcDTl1T8ZC&EHu4Mo~v%v+oyck+Vu@YGd)QOCgOEn5w(%GUC5*svS4KytwP5 z$*M>iQdacoMUJ?GrHo~eQ^oi7NV@KAI#$_<3C+#Lv8XBkLsbI0eqEUWYup)*@$K5~ zwJ*^pWv-_ri)89O;5#eW5*EhtIPQDbT02bh3Uo@t14U(e)}xfySayTR$Gd6w-@20q z*)5UIf6bd0ZSDT>Nyv6BTF%Z-jFMW=?ERCgfEdn<5hh&PCksXv;_RBf21XZR1!c^R zoqk%OXB^1_E4vbJawTBMcYS8c&F}F(94}T09ZJwj$1m$(t~;f|AUdv{@7*R7UDoVi z-nQgAAZ%OCqOSv|zD(l4`Xzr%mW4ctpp%utUBVs!wm2=xhSj_7&P1pdkQBee`A_z5 z74r}7U&q@2mH9`-{4?{9ezFLW2t|?$=Wx6Z%Nv0=m-X zc`RQUCOcWLid50A>rIz5G_Ut|zXE(aNpwnG zjuSwLMKtLl=W?8}pIM-go&L<#G|D1->DO4axGQs^`);em?MaFvY)x8mP{j{W>mOEO z~wHwj3|ksOoAXMwl#vyuvA<~oTtmz}8o zh***xHEc1~T+uHFm1 z8;4E{lCvbs#}<`nEFJIS|BNEZp-u4G-RCnT?pY%;i@ZHiEP<-xd!r)BpS_zr0!~R> z(f!j?8s4M&!ZwQSpDd-Sld=K&q?S2STvP}blR9WIDe@67&TI1yVYVCs20I9j(W9Ih z(bvdKexqS^8jki{;>XWYGxVJa;van>$8-|fh+R16so9tA-Us!5P$}4%uTMGc0=kuE zXk(fT*W2qTh+p! ze3LmPqt9sNgD`LO-p-4qqngS7&Pt;`m#U*S1fg`eep)se?sWV2qj231bfdhjBYV9l z3C}^nA9BLgLoHK(wJ-y8{&n(EDSZS1xU^F#fiB$O73lW%a#2%Y8deS>`>gpkJxZ7P@hFGJ$QqZf6F3t)`ryb>R>JH%u;+`88O;a@KwMy7?OWH;ubFNGp^p5U+q2OWoF!8v~||SH55YG%#~^r z1x-Ue+*c>66GRE}HCb>jOVO`;q!i20Z{B1kPTe{!g^J61M2n5jMTgf=HZp%RUaXZd zesU=7o?oh09xjVO(=Xy6+gI$B;r>SJinm`Ey=)s;%r76CZrd?>&|IvI^5v5Ih9-8`=J4}u$zox$%wd3?`w)^ zFtR9+?)hVK4Y)S&z&;#1=-@Onf~I%bXCciF5aAy3OT`ZEI=TvslQx?OLQ}~p=Rb6- zh2r+`eZ^Cau^uz-NhToaq^A~y1gRII-MTW$^9DI3=H<8MJ(#c|BT^xe`%-y6j^QAS zwoEq}T9N$=nZ2H}@t+N`1jQsr{C>3gXliN?stC^Wh7w3|ydy z?BpHsD;TBFn7%N-mdf^|h+XV^flR7j`8*52@4Wms?cFFtO}(mBX2ENz*Rr0uNNV|3 zdlnS;L>)fm&nNT?+K6RC>f85otcSNOcY<1PUVCFXo4BdSyW=}kKQp{`_@pRUjp^Z- z7ir((172X6nMHL8X&V#9bSi9#)!+@_N*xJeub!Sg_A&u#ly?D?##Clhds-_o zL69|}bAj{z<5;T^i*c{ovRq%zF#?9aL_^Z&)i$@9oC9G|;+0w^`vbcPT~~Px6Bc1h zH9QyfOE-{tpF+=CDU!5gN4@%Mi7O?yVVYNF^ewHx3chWaRo}*=PJ7dzN4uF$+r?7-0XRIl;Z7(|)oa zEi8eMD#Rc^iekHrK#%>vIMLqU2$g^A3XPqsCsoC?n(uC|G+f3YZu9o_tqYAMj3@T# zO2IZRcimQLvnW&_)Bc-J+oV)&=6hR6-VEqcZ~NL($*U>h^btKo%*V}E33H3XhDjq5 zs%1I?$I4huTRTwkRQZUE2d!sgA^Q`4jA1@72&ZBEkFfwZ!~^Oip2`_+T$h9>XrSL0 z0=@eO72tm{6O}j-!hw&(l(|Jw)$rzaap(0TTB0FXQ1(n(>Yh`XA!_s@bSSKG2-wMZ zrk;ZzBE(;N@Df&)pXAA3wd$k{Dz5_d-s#DlfVgV*q1VHBuB;DY`Spu8 z4C&QJ{t)7?Uu|RT>S;K$>64UlT7z`{_WRKk>E<2jd8rt1k0HJ)Fsf5M99EO4zC@*+ z^9L=l5N94&x_C1&U)-egx_+@6d}-Wp={pYc*EVRBi)`>ga&Q&65qbSp!lm11+*~2| zs%7MD>{YxkqDt(6bNtzCx=D7{I&;2?5A0w3v=^ffP|0;LqB7W7U|meL^nZtQrJbS* zi6PAj-DGy#Jg!$0Q-2syjhd%P=3k;(%~C?f-0PWd6I2s zYwXszLv`EC!<5=g) z*2Kl70ClnkAPp+vQp1w|2Yb=QbST^wnI*5My8&V?lVr^+{2o5O8NPPET;l_vXA&tGL97iAXNC%#EM-7bxOQ zNE2yph-X;VZ`C4{)~OD_XK6r|Lm?()adD4cx{-`N7e+xqmRn8~RjM(j4P81aHL8`z zxOTo$5;Bmq2m})!7`0jOAGuM!E0-TXaGb0hB*Ht1Hv4$5pDHWvfMmTu2c}7Sc0(U3 zGXMvcTSAA*=~~HY3&@6C4lGXYQaU1TD7hC*Vjo=cwN;{ zZ=@=pEYzA&soml#Q`h!Fhn)&oEF{v_X_1#;eZ3(sPOdykRZg2kLzk|H% z$QGQ+fK5eO%oAm{T}RHNZjyQ5e@(0QXiwN;lWdZI-Xb3BYsY*}`g9K!%1$Oy=yZ<^ z>M><=(t>-&7FXXZC^~=hl|^BW2}l=WtTS~FZ*y+S;_CIBgNEEq{>PJpJHs3jiS@j? z>dEmYpkexu=)GG3n+dSmlJMau9oTTg-e*^Zx~gGfjzk0OTB>!1Z+Qs>NaEZ=5zY~z zTR;MkcQ|og$@jqc^se;jsy!Gl6w;dV!g=9UL$1=U0#lp20kRyIG6H=+RnW+(w&~8K zUUUi7kLFk(hnt?wz0wuycfI~@+G%HBxW6;J(iePTxC$65I>We7d*q&NB;BdP{Xq=$ z2~k@Nk`Gb5BOeBR>i59-zf5A&#CGPx#eW9Dnz*RnJ#)%$SonXSQhJ@5Dd&j!i%ALZ zoEkX`Gt_+Y19%xxw7Sk_gEsUD{`|>M&CO<5L;9R|s_wEsi3Yj$s9lnDc2Q`d_{p*} zuSZAE#-Nn%Cq5cGqLkZc1u`o2drTolikS`<_P4-QTL$NL6=POcnx6f>A>Wr9f1|Y* z1@t}~)DfJjdp6qH3O2u7-<=9v+L@M^^IvUoDsa%X@GUjFR`$(f<)wqV+1sQhchKz0 z-BOtMI^1J8h$pL;k}l_)>tk?{z29!${cL+>Qv@l@)?nXs9g$&CiH51TD~&a?eV+Gi z5JAb@y7&=q8#QcMpq=)F9R_T_r6bAg!+>m`fJ_y?eXkk3Xa>0`iSLn36&6bOh9=8i z36nSg?|dndEMKcS@P%OqQOjj47+n&FQUy|AnhBo(Aar{^NLXOg=$*sen8HFVWnHcP zEs;rve&+rV>6Kjab_3U*3xg4M(rJiHKzi;oyFwLF)=$=_ zTVCvfY^=9@XiZA&!RAQ38mu(U1&%|SGb%9c;!)n_Iq#$Y*%zEskeeRlVPtB>Z5!xJ zkFT48(eksYc+>`ub{<^L%iN9IuBsT$BflxF>mwv*sU|#oslO!ZDQfqV%rVA7qTq}x zwU5N?2Q_|LXm@{ZQ&`>$4!>Q*^GW+1YSxnOL@o)#WhfJ5Ep2W~tf}BDb=^QOE5Z0- zVCjHuoDBDYFrWAOMWr{PnpwW2(+M}8-_8+b3o|lo16WkhNM<{PCtxh|a>o0C27;ZD zuDA7r>Ii^fkmzQLP%e=Pg8?8%YY44@{0iOgSm!%xo&t@o?2B;?aCeoU>>|RZ)69qx ztm#Y5o2d=W86r<7NxWE?ZpItN61uqjV$yQ__|9xl3J2*6Vb=FAz~0305lIAi=fv#% zc`MnHHaOGTq=uzQS$oBNLNRPGt4zbcwz={KrjILp&I}pXj&SpB*x&tY*>7G$a3#^JJ97MTyf4eKrug?w`#wPX%(@BJYDS>2o=CSgmqxG~%Q znL~Vh1hUQvwVCO!Tg*NG8;aE4Xx!MA#%;cehZ-%_;4y9EYtx=fDd7&ly_H*uWiV?4 zj0&u>AWJs>*M_(NeKJ75`gVb38Pq=XqZ!eddv=(JKKz;|oC9RZzAq#lw%j_z@k(Z~{2t2Ypy9@1K9ZNJx0pVMw^U?8Y4 za|u;F1T>SZT3tzln2Mz~tY}F$);G%7840Ak5kyxs1`?S{WJgAGw9O+1r#zrVaaFAb z8S&N1$znK8d$|G@>r}vG@+51OcDwF$`8cv(!8L~$?g|wqa+SJ=e5vW^P3ujHM5p;O zqmsn?K9ufG*~luh6r1`?m%F6e=gu16s=R0i!P&Ed#)LCat__a+P!}k_d(ZWCNq3DA zIF0#3%Soe@p8Sz(_CF1j_zPX1rBqGx+1yz2S`>-j8q{jYqq{RoUdMZK#jc0Im_S|? zx3(0eC8SQ8AM0*uy})(HExgkV6BJdz4@+_IB&2#DFNHT$0mi}6oKhoV@27u@UrT0Y zB*2TsrAL)nOW4k|sWvxIx$gpmu(uRr?`B);u7Fi~dAd4>n40hEtACm{Np zwB#I9yfoi93LNhmwOdgn~ZL~edcsVbX%tg zI7zC}7?i5)DO;09kMl_9wtK8P1!x;J0h?BS-Ew#6P!!U>S4+oQvsOZQtXrkf8^@&# zynLABS0UcmyQ|3{i!}D=6o23Amsr8nc=xI(ud}n6DUdvzbEWMj7%AU+6R_+lHS*qL z-L9RG>NRLfzKN}<=hD6Yhft!cX`#+O$1li-919uXbz-m*hWbs<2EFzh`+c!HWs&tf zV@t->oDSLI`Jc1mH|__kHfwKRZ_OtH*g2Ad;lLfa%g4a!4dH;yMsXpxvzL9mt-MJC zI0`Kr_p9pL+p2@4rBxSM_eni=K$)ku-CBwJi>@R&&+Pjy8R=vdR2 z-UafFkAx#|djM&j39y-HfJpL%hRun;Y8oP^6Y16oKl6}SeH|~U@&J$9?T&LFc$b%= zK$+7lXYbe1rZQ({c=(w92sEcA*TEXoF&3t8pA!nqdqQzoIuIqti1Zsll#3!i3eWVK zi2U);AO>M)De zid8A9vD4V3s;8(uW2eKY-5}HoS`|ChlGs`+B}R#ei1GXAIL~>`^ZdTw?|*q^+_^vZ zb=}u}jraAw%^dE!sK2;gT_{7MvE?$4N~AuGU-)!{>7Ga2-_UW~p~0N1+UX+aZGv$<@~RfBz--5bB`_Gj+K|D7fM)+ z)GrJ~#?FL4#%-<>5(RS3eBIvbp|xLgmbo@_1c@Mv;ibU=j8y}u3H zYK{u%6ckuM4r+*Z1Gjv#-7dFn4DhtBgG?5GTuoLz^9+g9{uae_IL0x_)6zKU#*wtd zhqHA&U4fj=*@BsJz|JCHrGK*~`g`BIgYeKF&!{)HUl`GZ&nIiD4GKCmYMv+D5hIyj zxNRjv;G6PuwQI`~gM4eAo#nJ=FN<|)V7YhrLk5{>)FksAUpnM*X6wy*<%Q*8NN-Y} zoD{XbYLr{vz5_bI9dz$+3GDCdrowhTK8Wm&DHw?-yc1qMcfebpOSnLo(dG>iP@KD2 zviQ;4ETp?MEizk_ewL7vM>DrN$@P~{lP0;>Hyt2O<+#rIL?EqfqAzS=#qT~R4!|7x z9NBLP0IwBAb$Hhkl0=yWbl3RY0`2|#y?4|!TYQuukp699 zYVNh>{(ZCd@{S0On=UpJ>x!Lw;L}6VywXHX#4BS;3%|Wo%#~d?esjywWL6@uK=;6- zFYej-!}KJY>Nmty$@(zMVnWBm>VH)Dy0af%;0Hj+5@}hFD{R$@x5RU9kEh+}i@@hB zO}xEn98(|Q4Fr1i+e+L%dghQ4Du7LuNE7@wOy)3FM)V6>plA&yum{0**x!EABGNw? zNWtDfq>UP}#nxXnHdHtwml&fI-??h1cpqHYi84t*^o(c(qko*c<`8u5RTnm=nJ=NrrmGFvjtNA&m^=tLDV zw4b__DE505m7YZnR67HZAae#>LAi#`{3K}o4!Z&#>BsRJ1S)iDAk?$o*27lCTOE8! zigrBnanS$C*K6l#NWPr$7-U0iU+-wZqTP=zMC_fE(m*qAJwQ#s{GT z79o&5v-Y>rXtTo6>-$qHuXn($+m83?vf3bDyfSw*4KA#dU8@y;wEk#1TMTRM;(nv) zEOt_f<=1ar_lH6T-nlSbCLwHbiZhpPJaPa5BzaSb+#+WspRVqqSr@N1R;&??G|*!$ z!XUvD*56`n2NfD$7n5xPL~DC)@WKG*eJ%Y+1XHX=4mCS0csK_-wpR?@%(YF$50DDC z5-pk!>NzC0oZdR|6Vb}oQbxIZZrrwcR!5n9{N0sd3B&_bxnA&}_B)$qsyVl9>UXTG z`p&%i2-C~N+%58-WVG%$aeieiyyGuHaTH>@b~ILq0oIc9r2;w9yiFTY3D79C+Vrra z(Nsnq2&kB0qH2c-ynE3|-PJYU_QAqwl}>tmU7IPTnYhddnshsiLCxdhp#wKV99aH+ zA%A0jA|}-0mgK2KysxXq|56@TXZyJr_OY}?HE;8d{uU?(-$H~}zWB@JJL%h-Bh-eH zQsM#{Bqkx6RkRSg9>StZP(-{q@p1d^W|Z9;mq@`2DMjTo&ntM00@2>4W1=~6eLnr+ z8bE8fdgGfao_l)JRXrLwo~ndD+sr@(QwPZwGQL^gfv^tWfv~0#zj;G061OzoCZb8S z58d9xgHTubIT^}bsd0&f8>Sp*uv7NFiddkV-RGZ0qqOv$%Lydt*yFM@p$ z*R!MC2y8{Snr^(|-WPq*$U&7KK*5e?-RPM}v?VR%mGy81W?G!pD7bGBW4H8_Y{173 zM`*h6Z*5A~*H)kCQs_7DdJ4P0o%*@HE7*5nvmq9+k`g066H=Bhbvq-Rin8m-uUwe( zLo{4g3xFGNiA7~0#{Y0DniV+De}S5!ju~tKtTvh^C0BMiU+#29JbstwhPyg}^%izo zq#s|LQ<|XwnW4CTyK7G#T+omxdJsLV=ELnWq46)Y+p~kA*NWLLpGK-Z@bL;UgrC_; zdHBXa4((YYCi{9-YT}w@YVgs6yFgv$=}TU4ws=sgn<}x5hVIONtXf!orY$l7Q!+}Y zklYmO2M${5Fh_&hs7yCeC-S;F=S1!19m{6k^E4MZE6nJF>xbAq9Xy#%zEcXR@t7Dt z$~)5K5Ou|cskh(nK6_^KWvZ+DmGBhJY5wSSWRR3sv<-~Faf&<>5?hcmlJ9oEcXktX zPIY#xm)-|(6RO+3EJ62NF@;Rrg6fX@l#ZxCu`a0<$cp8Dgi}MGF1p~`E2fCt z9_EX)!xd!Tc4}))<65wnyA{wc`Mz$+WAY<(+%=zIlTCpxbCYRll-zPRSw+4!Y0T~P z4YlXq4kbnn8jAvHbP4J6Tl45ADHA@B4^;@L= zq~i7NSo-tQVcj9_D8Qzz=_Ku3t(GX0yn3HKH*du_10!hZ8V2BOIsd}hrdDHO= z`Zcf6wl~kDx7zkK$yUZHq&I)KW5|H6HNM8Y=B*fuvfU&n>7G?sCtdgtq%GUS|BAF_ z07W*3lD0|dmZ+E{J8-Ew)Q(&Xl(T;TeV>*x+io)93A6HB$=%HKO3k8oENOYF3ly0i^IdtMEW= zO-8gV3rFKvbfX`~H^_gT1^4DDA&aIe4Ml9-g3BJOHTiI{c z^EufHWn~6oR}Uk_PF6I+-8=Mk4+_r`NF?nLzV6TxU*`W8Kv8b zDFp#s8%4G@d?6%&Zkc$&;|yV5B!aAB zr@ICAPUkmW5iaFwM_Wl_5ErOhhV&1L<>ZT%i%{20|4H1v*al)F`}MD;o1-^{nJEoZ z*ekkuZaSyqhbm;Nrs_&_BJ0jTU-p|rAtU8_Q?K1d$|!lUrskO=axCPfeTAU@0dy=0 zD4moZK3Cv%UpLzE=<_XqFT#YZ4R#~3Mg=bqI7VgFBk?C+#z>%yhSx9#L$bsog^-*7 z$cX|iU2NC+GowthDqnnkS0tbN+U(J!N#HqiF|A&@y3fw?Zai{vk2C|K__rwJLnc5# z7AT^2LFmg8kRqU-fB8OVex3qQ@?R45TA30vTGA1ZJ=<`z)^N?0Gd4Kbj=1V5a`jR* zY~=O8L9O6DqOL|1XBmTTzw#PKbyYPw-9_+~Wvaxwks@m@Uhs(W zTp0OqQ6Q;Js;mXwT^B35h9*7v`jV;xO&z4(Xd4eXu6`h$K! zF0OuO_XEdNUiF`E&bnywEP(H?NBZC zeKwR){5-GMaV9-cPvDBp--)8`u9W@EcIH=gU-AiFX#bAOz04HS=u&TXOyQF3Kc>&Z zyfq=zSp|A5z|E?v&HRk@tn%aL1EG82ci5CnLMF%#8+20>bM*I|Z@YApW zs{$SX*23*{vlT{K#6a`!e*JknCgW$yc1A0%N7?ppZ<1ps{d3ik%A=_#W`2F|#G_{P z>1g|Z#7%p?Z77`+pn}s!9&db;&9Zz%)$=~G#J37xxK=( zhpprHyvaQcAnUw5yZ09B$LDGCq1OZp1%{~0U$TN*75}knd$O|Px_QeOV7Y^DyNZ8j zLCa!&ZPw#*;oJUyI*IvbzoUjr*2^c9H86Zt|H@`tamL5xwT}Ga0+{y$sjptAzFMsO zFWlSqL(JR;x4uJzRbGgBdq!B z4@~hK2e;U;W|D%mB@t(QoNz|80Qp>i{`&UFV1aMr7YA;Qg2u zd>8+Dm3@SwKF&{nizt4)>`v1_hMcx z4<=T?{Imi?oZklw%qH}S`7bH_j9R)=e`A^+Vm}=FD}Ve!>*4kG!w;1X|HpVh47^7Y z2%sx<>%=Zi{5w?G{v1=uZPSGO@9O$%zwJ#ZO(Ybk+2`%?Mdd=d1cB6b!yaSQs#^MA z-?Co<76~8x_}f3cRAAmWwY3}|dR&_l0QS72VsMXrENwsVD3*tQH~i=00_+^uU0rXy zxSI!P+#Sn*IXuk{Y-+2Z-E9U(@qJp;*qY$-_VRllX525$|9b%UA1nXQf7$y&=nBBd zI)@ln+-VmX_+nn#2Ic7b>uL5@{{J+}&joJ&gLClM>E&ye#-C~Q{U=f1|8*z;rN;qq z_MHSD`s@P+5yFc-N97$a4+dY3{-CrDW=a2984wR(rd=BF% z0#M~;(_XI+F-6bxc|GbdKC9PrM+&Lpz0ugg{6k5E;#}rFactEz(V+N8A z+&LM)!2<42{x68I@3r^}xKxUFQ4&}D!d;nnYLt6x1^rp1%;X3wYUol@Q! zzsqEe%v7seJN&Uv|mByT1ie*jzW^wRDl|9KRIpMA&cmb;!;4XMgQNnCLg4 zU(viNgy9j0+C#P0)_28?iZc=Z)3m_w)S;+SobhM>n-5R1c1JYl+al#J zH*l7?QWC?iuur;Ptib z#_c_u9*^r?KXNbQ-Og^P2gk911Hbfn5ZKL%M|SpT{v=iahQ3!j6!RvPL=WBx|3%C^ zAE?1Td|=P}-@}81L3~!3b$7))#xLK_R)*y-t+mvixbq+uaX|nehC2|dK)HgrH&*Xk zz6t1%li2KCb^-R{7X}%FUEbT6(Ff!6$*zu2XJ_Z~dt2IpV-y`qKkUO!{G?)8b|SBw zemc5M4lcb$9khc6yA2EohD8$kP`g_s$sV6Mqo7Nrn9o~uilmRS(wXyZ78%r!${K9} zrL`R$Ytgz;@To&_I7oSWNGAa;+`zlR0C@*^^Olm^{ zeQM=81tC)8;ml99{aN#5I|&+g@usGMeY>oie5%?=0WRz>B!33mgYDh7Pc>X8?J#?Z zwA+!aZ=mWEM?qTETR9C+8)Ph4QByn^37t!sR*r4`~s89Bcays5B<^`zAFH_ zKfGmY*!^y&3a2+q(yjC~Ep9#u?-Rn)kt}y!%&vXBBp9iT{~K`GI{Pg-*3(8N%ATcH;Q&v$_{h<_qI1c|nnyo8e4yi^f|B)nq!acC(deuUb z@PcmlwIVS%lT5raD}nMj31U zkF6IPBlLkZqyaC#CGc-)O#oiV@3pvjO8Agq=-)eOn(r}3JRap-+=H3!0q%WE3^4qm zqq`qc-n152E89H*_^skIIlRVCZ~}m*Bk8;eGj1@5K%nrxiWpxtF+Koj4DK+DUD z@2q`M?Qqwe3OOX`&0p(dmajt!lWj9$ssxG&B}Rqlt{51hJwmL_KCxox>`Cv2rOc2b z*DGpKa@ms_ZB{86O@;n4ekb*81Z{9PgH1l3EV+QRGa7_FK?vQ{vM(Z6G#`7~ovh^^ zJngLHtYUxgfh2sw)?P7Dh6Dhx^}J^iuXds~h2UjQHN ziiVyFPi-99Y$k_(frtv(oJ%2Tqmz!jiaSv^cM|+@<1^WZD{ZoF)UaahB-4>WAEw%- z)AZfj?|P&2ozbFOjq*|nJ(a0}SizSC1{9ZQ1@y1pi{F?DI$A2x1|J!lVa^48{4QLxt5_-nN9$=Za$$Pc2 zL0CFWYs-Iyt6cPKY~hu77fN2PYn5g{de%+f6mMRZt;94IOFExArY2ZUIH7-6{y@ab zW~Bj<-Th+O_((kyc!%EZi{@LTiShp&ZO_5xZ!`*fQHghaTu1)LVM+RwTs zTqr97Mt}K>|J9!WeE&1Tcb8xNpoKjSy1p~)zIG8Pe*ovTL}-Svc%lMQYu?#QZ~v1F zP@W@B*l(&W=GZ54M!B`Bm*RJ@x73>%7fIuXFZSQK@aa2|Yy{#5k?am|e>XrR%LdaOzQ5{tv=@ge z_(dYi*1z^C;lGo}78thGLFn=j|1=hU-odaoAtoRsBG@@wiFCQgUHXkd7?m&&8F zHt%(4s)~a&z~V;OufzBiQ{Ft;Htz{b(cirFwnkbySBUvUh~?iQ0%u9dI81SGG$Y zm|J}3Ku>fHDE{R)H*k0_zOMFntG5Sc3z~A~H|G{{XtRlwhSJkz4E2{HTSsdxj>5hT z!4#S%&1gv*-AB5!3Uud>b~m1!IrN7EVd20yznX^26JZte`;Uv*(I6 zz)!2CG;3l)3bT;}p~@g>7gQYb+tdLpe=fDf_EF5&HY@#W zp|!Tn1_{C*r)W3&mh-NzPY)0A?BA??os8~3d4~ezu=`OO(2f%n)txhbODC%s`7t;6 zF7>48ccaiXAu+cQ7h=7F;8G!?v`E>u3h6MV^&(9q3H96`s^8{ExZo6G*y{gWu9FN~ z>}vaPLn97j=5NP{cFcO|FnIPoI^MHdCdS`}U71BREf)G3d&?5}!0nm<*D;Ji#TOE6 zqzPZ5-V-IeYgmabnpo}Is$R!XiPP2u>}gWuGC6UbsN95XWwR>~IZuEqud66=KQCN< z4=I~~#LV0*L7N&rL`ymA-1rp=w}}aHmOn1zI-(~fc`BTTn6LK1|L9JBuThFvQ=W1M zy=3QWLnrmd+3wWCLvn`W`9aq)$1cj-#xIab>r)nc`MlZ}f5ZDnvhv@LrObccXVX`+ zuy*)j@Kl-1+$B8@%;xbl0dGZr-j z^}ns?n=y~41~st5`p$>1Y2wgpCynSIX`(KjvuXa;s{VC)e0tQ}9(4m^R%gu($a&){ zqv8#EHep_63Oa(-Au&Cz!@Pk|Xf8o|1dl1C)KYuq0XNR6{z2x`K{X^v5TeGstN^>Y zFsugctnSQg5?#1$_M*KXZf1grkaJ6Gw@X>hh&Di?^?UkE+zY)8@Cpzcq?=z9tb_kn zKOEJnJm4&O6y+uAV7P)=_3EkF>Nl$%>E)znLLu!VvxRlqvoW$pPu4ti z!4Uki1miNe>+JbixblF?pf9rt?P(n&#shS_Y|hq|8gAQ!A)|~ z*Ad{~J+^#DtN3nH^L+tUAUt9Dyi%Gyt=h?<@B%hnY zBNs?JIP@NJ-6oJXA%HjWzWL<2$OGJ`yGK49T&jcRfv%ajx$D{%p11*e8qBPKSAKt) zBzm<&b{*C{e=W06&aAqNzyOULmo{RG9IT#=oxL^3zc6WJdI|%8h)jp_DTT-|1Najq z&=UvcyIedyV2>L2vcp5wHSaN|i;+>A)~YaGJ<&l@U^}BJWt3_#YVDMJ(Wj8RE{(Ndw-O#b^q#m^CK{4ss*T5q8yHj1cv(=iY z?|}2}nzDw>*=Ip|7%0sgajG?>mHZY(BVO;scFxzn8==9w%}O%QK^*mJ4D=l`D~cQH zF!#IB(Xd-IbG$Th*-udBj$#{psC8tcE#yK^OLBRw%4&-k`d-~~a&%!$q4LKW|KcSN zbR7&%E~bkjqzdutuH|ZA@IpiNO2!(gZCntV6aB?^-s&m&YLPylU0d3O1nSB9$fo%2 zVnCHz^*heA`%(pUGGszs9ZZz``DXu2xSb-dfv1b~oVZ-r<}E&MIv7dwpK!9~+pdK# z%cqhB_6`5MnL#S)I|%-i5sNpJt5tz&!8C2Xxe+(_#s}_}Ki|4q2;8^jO$Q*!L$Pk1 zv8%V1_i$4gFmuc&_6yvGW;In#VxYRS4e6H$ zQvZ&E&)on}@Opyp3b%<-X2B*mrV3V8L8Z40aXC%pnHenF_)8Nx>lX!aX<_JWWdUE# z`9pmiJ-lohTUO6x+k5gpD!hDF0W?hv^B40I4b_M8q8)Xk)2xiD1lp9#>E&A={WbqM ziaAAeSvHL}OSgJCb=|PzO!XL5$u@2U3wadLKX~7I686|RZPg_jt&cH9@&rdf+~6X7 zT|_hE;QHKquzTZ^%gdlu*^54%=0i#$aD2u&K@{|^mWriOxcmd`BE>8VzjHF0n5an#E*wE>*3Aw~DA~2j*xI=*u3`X|H2pf%I+Z_)$W+rtlt(=VwRha;_F!ZwnoH3kDQkM2bJHfq)M+Rj^_JL%QA zoGhR-%so?3C6)kN8}Z81}F~(Ynt|*5Td}g{N7FwH?O5O~J?-MbWwawMMl(rRQGmDu=90>e#7CY*|QrqlKyT zJ+#f}7M(+^a!_Rx`i}&E>JkJ_Eq-ilo6(df&>^XQ`k|&`Zuz)7al8MZ!H|jInJ3>Q zo`Sb(3)g3of=wV0Qk67kmi|nQ$F=Sm6yY}@B>qgkun29qix+ErogwG7xbSHyaIyQ2 zl-{g?HHSCt0#)oHZb}_p)&p3wz!z-T7x#>bE;lj~Z$xTpCmW;Y+p698ATf?$%~>lf zXxYzZrp<7hXi?=)h^}_jro!;q70alwCv_8rV+t-dL`M`_-$rbu%T(eI}dJ ziyt3*JnTKn!qjAxa3t*^+g%qm-ZR|GhfWI~&AeL`(V}~3-(j}9Q+Z~VgX4FbKmXbM z+0|9LVO5SVjO8HH)4QI>IUXgVPce;)w#0e;0s38A=tMMnqG30x8bOen%x5TWK}bQMUF92soHi`3P;6OGmYMC zn-pz)He`LqUGK@n47sIWIk{YszVRh7XUX#2-LEhO7U}hzf?5M;rhd9KT5~vgksKt_ z{Mt6)k-T>Z*tU4SE|og!;mDA+<)HSuS+3g3lTMKy;7P9iccd)*-ALBUrM+F+3^|k- zJxXIpn&s^bOuhiW4D)B?Acq1wWG&|Tr^=3L3GNzp(nP*|2s{j;8#Ou=7p{Sq;?@nb zk#vgReb-XsUFo)tlhkoxJS1*ed-w#&YTJ}_Y_W)D5c6r%f;_^i1X@-lk+=J)tMT|r z(eer8N931ND6+aHaFHdEfg!pVdy=YGBLz z#Sk&;H=3}Foo~|trkC32gRB;U;Lh$YQG?zlSDNm_9|Bd%Z|-0|O=RVa=kJo3(9+TJ zWTvF%0b+FJ3+!om2e*abW_*A#EB%YF0XQ%k+kb;DW>*D?19PHSqV} zy@kL=o_Nej!H-LR7Tg>PtDucQhD*u9*29Y|H8H24f}zSx{w43x^kI3irktwYY=Jzw zOKcw!c0XP4H4bfh$(Bx$icOc-Aj)-6pElQTRtm8|bsE84vieq3i-3_^TCKOVoQpM} zRL9~H*oaSruLde$`Od2HhdSb@a}aU8RHK|$j=>r=R$l9u9$D|F#bcwlz)lcqI}HiL z_tef{4gtiJ{9&~XuRMA+?V6_23WdIAdEgnYDT{%t7Lo==O*L&BR#can`WYpc6a@Q7 ztTGnga_tn7$J4gjfI`(UaV*|!-}3(eGmyd2au;huNSibGP7~XZ9{-vp7K$vmAr670 zZn+vGOS|4wVMm9J{C`NOS%Hc3E?;PQ!75J?xU@I4Ho*yy5`tdCcrMGRl6A1qRnseW zH*NV)3c<}MI0xl)Hr*B*`7T^QM$m(5O+NczlsLY&LXW_n9$4vG9G2dbIkB}x@~GU! z7zNMI26|wJY;Lg&?8FIfJ!1@NAH8bHSzk?2^xW{rpNw^s)5x3q;R}*-iIf|hwrI&n&JZk|9LfuPJ zEH=YCw>YIJCp^kRzB`qm$w%CjTB6e&@l>!KJ8h%)}~*5*c8;XV;8b>=GmKZ?~MRvZKM5H!d*@s zl{br1gHUdbhu3Ja|Bx_HIA;>$e9Rw;TRB`7^!sf^F?aqcuuZ`ONapYUkgH$Rj(Uwf zK~q^BVo{>0tlT>(aY54x#j7Vh=BagAtP!yRB;EvYXdi+xXG9FQ@?gF4`qRy3QxUq3 z`~2Z=HWe$%S`ew_oaR3X3mwXM=rU>H%XS?T=Yv~uwI?Wg%&AJggvA=OrSE&Av|8r_ zE(@JZ#-!fptx4v)!~z9{XO!49VVEo{=_bUYU^PRD6D~JAXc>&?Cj~euFI$;DBxn3B zL_RJcOVvLTPY)RK)dvOJy377C6{3!45tVvtk9sx?t*xp1V7BRI%kKiF6HC*ZDDu19sHro*)t%q7DE#~xf z=BS*v%x{A544*4@QW-zVl z(n+SDo9QDHZFjcyqv)Y&9z}gS`e>ZT&TQ#!!*(k1Lyzs~_4fvw&P`jPvoS=i^-Q;& zFRII&+Zp~wozK%vlpza;N(2ri%Ja%utXN?r($#j6F@Nad!c$IxWmdRcsv?nZnY9z=@`=nyNb||jz z4Xeh^OZ?Vq#~*@7cJY0UD$A$!lQvRdk!q@NIYr_CmLfwgxJO=u3U|~*k^MT3iZ{##t=a{@`7^(MUoe^cU z2tG?N zcdol-H`~;`vPmwVNb1=3YUdI6ZmdxOEnh5xX^+-p<~Mi{D?HiCqoX_TS!wHI)?Du5 zuUj|9U)Mbq_Czy*5y$PMa-VPl8utBAvyRqcZfkRG;C$J4G@c(Vz)9&lkkfb~`Kq?V z@hQ>N^JPfQtqmh`O$~X4*hqzBm^3wlmpd3T z=oHmZR`&qLV$Je6tt@TqrTKhFou6mbV>|Yp2yE5?>sZSq=>pLskkc$#t@@Ajq7xuB z7lx0x6^3~WpKzXdc81iu67XOSYh5hbC?847=PMRVlFg9r$y?)-q@rr2B*5 zkHEux{L9dKT~sli_+ zV<#N4N=6=0z44IByr6$qd67zm$8D16`*Mw=arrCjOWS$7#ATmXc zKs(&O2!dxO(=%WP++a%!L|VZhveuA+aox4_fzb=jV`16V3LP^8B=ESe?sDbGaPUyZ zDXK|1LvI{98}d{(`S&|UF4ie^Rr5CMJ^nF4v9;5TlubQTe|?Z_rLPZJ9Ypcci)~5W zC1TexnP{jDvj=S}u((%*DX8qrIMy9DxUPiRv`4vt7siUG2zG5LQF6lLw=FXQ*R2N zYLZrlK#0$-zsHA3Kk_Hf0G^z6lUrF0Q!Fi8r`A$ySm}0wc)g)1i)2BG%;X{$$I8Jg z~Zq`=r*s+Lk75_+<9pvlQi(*VJ^P+JR0TaXI+JzkS z;;8?yWB~!G4H2bz84~C51ZRjw8Fgn^e-(3%MX)Nm*Ks5@m=|*4kpx-PPK+E(svcKC z<@a`tD^#xvWIV4_#6N$aj^fb9t-GS+ELW`tOi@5j+WkF`uDvR>I4m=B#nY<*_&y$#)ed1A4lBE_#g zUho$FbVR!8yr>gNGu!9&m7O$JF-QIi-Zsk zG5Z7d#ka_6SDBW5N^G;OmQn&SECqo%t`xMHZ$HzpO2s!imo9?qeUi|OaOtu;!HxaM z`%&0KK(VpMkv6dLz_irAJe@KQ01M*-QKoOqq-CwF7R8AVRgTa;knh_NgWRinQ7XZf z_^C6ol5lC4RKFgo#LR3!IR4`d$RAPhSSR}$o}Nh7bRM0qQojU)Z+8aFm9K`BdYP<( z%Aw;3+8{DOztLS8i!7nts$Z}(|NH@~M)0pK>-4TI-?kk6glGgdL#=hwGJvZ<*e;E@ z<9-=)0$0Stk;3LL&nv(!@BDpcgIrI2=3@xE&kX7npL(CWqc>G>lL!Gzpnfd9l3VDA zYO(a$%Vo~$*yPVsbx^@zN+xxrjH(vq&Cea$j`(JdfZsg7s?qYE^OZG=5wWGyCPumP zia!DUYUeb^_3+iG@aKA({F?Ifm8I@#;wQl`JVZ85Yciiy%^z31;1rFtntM&TiyEDVDd+_1kTJL@tTm z56;n12SXa*OJiN0ci&0GE@Skq++r;6fg#VV?XG?`bT=;!F0Eb!ubl7LXOm#g%u>}k zUXx|2LIzj!B6g~uQ3A8@O$qz68x2k%OBS0wsMa&DLmJm-+~&6TUl(fIwl)x}z&$yE~CY0i@#Y8V5pAEUx%E zLu_Ju$xw9{AlF^*Wo#N4g4f?i<0b+rJ*z&Xi%uG`%~NO~f>r*QV*drPHOb@ggejI> zcZJ@xUT8FSJRvUfA*sFG@F*K@J}9$KcejgUcHUuCdq9nG-%NWTWd2tEfV)6!h3j%X?nwH8d)SXVB zBL%sV)qRESUkMx(Z7Rfy&&^_It98KnWe6DVhDWwH)+-BEV7|Pgv^dxGe3Zt^Q`!(v zW<>QjSyjqi5{>h-DLSP$i%ISHfDxG&$U$?Hw|0C;NxLb{kz6G_{skYL_+vH)s7sAJ9d!0a{I>dZLL449v%R9R zT7>)@FIavwGEqD z-HaEFzyv~EJ8*b)qbIAqi;+R(ki}9+uk#$)*Bw!;?!T4d)4%;e#l6&xeo|?jSFVQL zt1MbNZxNocaFj70$WU>!6{M6?q-SC=aH(<=_wVx)Cfs_Rujq);kx zi87C3VA*GxV!Mc)I*C-bVD{<7jz(tAxc$P&XH&rF8LZYa zxRl?f2hBSr=N#ImuA3J`2A5i9bjd=osdoA6$+BW@l1&@?DK|d=T)do*Rk*WEt2t(P z;U_w4ZflNI^F$!-&g?{mZ_k7x%8YaNiLPH0ByL-`>1Zg7gVg^3J6bcUCs7Q{o9Uf% zBV?lA`CF@nHG+Za^S5dwhrLVcRD9X_4j1$z^F%p?WVyF)+D++h`o*y1HijOfdX-Y4 za*?2tL&3dw$s3~)>4_AR*z%^W#JC<@DW}4evC8xO# z=$eu^$;t-3B0z5Lom}eXFzOSaE<4X@fIb&==Pd^l-k4FV#0t_!khOyIzvT^@lTcws zt7t~U1g$~sZdUYw{E}TKyd?Kv5+M8g-b4+Y znY2D+j3=Znb?GUAP;(`f)dc62k9%j}$SxxbS_*km_N6{geLI@spMJYR?1wi}&GqVc zlfW+5QNB<3>tY&9A--_|>+ZeLZxhy2ICiIpS_X!1rpwBEmcf*zm?FcO z62e#c4rs~vv!60w$3YE0d6#}ND!uk0;8d$E3H5tU!D_|N!&AufP$((Z_-kHjt;c6~ z=09+U-ut&rNfg)xa~-KCB!;CB&ymvTZJ?#8mbFBVby|;n$dH>dR%>nIX0vvgO>`!! zPXvoDLxvHH4DPBYOubdc){c+V3>DJ0_)i`*-m%hiH}$YVmc_wHo_(fsU3H?IqeKQT z?_4S{J@}jBNvoDOht=0k(xeiqsr%EOLkt}m!@;~$piYZ`Lpe|FY~ti>1MofGu6WWr ztUppNz?LXJHApPV@iEHdtqYHsBB+o6_mH;u4lSG3WX(BMf9w{&K;D)GNRN5u>N96s zVK;YYL(_4j9B%VPt~vo4#I7&h7rW{&o1(BB_Y5}<)suW!+*`h8>Jc(Ci1sr1*k7)_ zeQZXsVgbBsmJW?sHnY?t)TcDLjj)yUAsMsEw1!bbm!ZTbWn#vi&jBye4)7u?f;AOu zU|S7YBUk5s9b}D6ocyW^dR~&Kv_7R+OS#tyObLOMs0XFI@nHCv_ej&$i05GMOTq1r zske=f{|e$k`{YkAzb9yjGx_42F1QO)A3*u}Go)J8Tay|glh5I57Q75t^%vRon=kx&dMXts5}Szd{kryE(cx-c z7HU`G!i}^qaWeW{m;B~wDZKpl=0%Mt zD`JYbVJc&~usUT6*yAY`Q8$zkFJkq^5cpCAG`d_J8>PKnccqcMRU&9)AA`-xbgsf) ztd1+Fu+ zWqp-(puJJA0r!+r5#w`!I26EtMVgj9_GaudcuzO&^`Bw?z;8>H#l^^3H{o&@e+E9R zSx>aE;gWW5PZf>T8l8~sml-j-_Ss{66JOuCAP<8DNd&ldAii`qf!nGUe*UJ7Ib_Ng zvFt+wjvB$8dUlBN;I+Mcj4zYp@#Ol$W~{E_@y_|3l>_b;DMLESzCInjwIE+`#i;68 znlzr;(1)ZkJ|1VX6w(y>n(d`P`otLbA4*jrl3nXBR_~pt&HSOIno*>F1FN68K%fVT zSy&6U;GAhCK4Y~XyIL!_d_mnQJEuN6W`h5rnxe;F8&I3+QGEDa*B_SDS?EZp96gin z_(zlcE9^Nlrp=1C8}H90G0u|ebnJ4V_(GZ)ldPoI_7NeC5#mnQAH7|r0p`kkDGX2G z>XHp94Hh2wnID4N(+YdOP|e*>sL_ViFQ|!Q$18;pR6fvnW6kAXH5SKxm)Z+PRp+mM ze?x_N5|7Y%Z9@0o1~`^u6Q{ZNugz@R-tnH8wyycw1zS|6+Jc3gY`PI0LcK`oa4ygG)f}4o`QivZ9<$0TlDZad@{$lE0P-u9w*?EP{=jpj$AtmdP zH^Te&wVU@3W&Egu$>=xhxAPF5XK4TRTzfAHM8AFQd)bm6FY8PDA%e~d7&l&#P!~DC{|I0_s0Y9XbN#Ao7*KZe7JCo%9re^=^ z0KkgzocXrZ(*s|+I#6UXlD}S zE}#+Q$Dni=g{<-ymBjvU!~Fa!C5cdyVUfbQf0yY0`s3ys2U~;M@u&xfZ^!;?hM~nr zA}r_0GmMGdot_#jwKO0J&g3jA<3SJ7+2~_ud8uB<7ed!#FpFiCCYb^4qOOIsRML!_RWQ zuZg|eJ`@squP0G?e& zTS%aq7^TT_8)~s+CyCdiFndl=buG(;ApR`v;^{0(@zSdd>T?mK0sr9E0 znB#mV7Q5uh*^`74sM$NT={{O-^FoByuIaJ{eV{aT-|*Y$c`Z*a3SuEwd(X}!AV z0J2`utdJxhxLIi;ON%URb+3+TdC!7jVpWwh(Yl5hB`m8}f5N2BCqWVij$>*OR9bjlVgi!6Pnzrw?z3I^Z*8a83c(-zQJ+s+n zknG+X&mj0=FNwsZf?@>ccB4izv2i+zn(s`cnP=jsg_n!O$SVlQWJ-2xzPMab z&V}d=hxSd=IM)?+<^^R>3_nqtTWQ4J*QTlG7SEhIc+T_In3VNy(( z%%z}E7W-_mxX0fPmA|>P94xBWNBQjv&%l=a0&gH@_FPliEYH}Tezm8~Y%4V$so!$P zxlWA=|2SGV!ZVnH*&~@x!j&OK2wE$1-r_=b8ea5GxZ+)-L7Fgo=#2G+#q`j)KP@|e zxTz3k`fVdw*kq?}e`>mM8XMsfCUIuyr;G)v^3FAdh(~lX6U5|r`3y-Wd7pcxYMc%C3+UB!D zw90=omE_QW40pUFu_(E(y|21Lp=!&NS=~Uhbrfk2W)$Y3a1m(}NUQoq_Y1PxOuapv zemheHWwsuC4ug7cz{w%C&Li4GOVRn$o*njjgA?8q?pviMU4@ZeeHpsslfH@FZ|!P} z__4&sVJyX1G$P};?w2RDl9y9GBZ+NG?!B6BK#ms?;g#es$B34xQDRxci=X82i zg8b0<`3T8wqshAW>q!O$Ex|2ei=`C&Czem`Q#zlJdiDB-u!FXpv}yAFu4dg{9`h>n zk#}`Gs#{BZwF#c7j69uDl%Mcge$P*PRuUp#WCSJn#@&3GuGCeIdG6&H`?A%mLRAii zy-SrMKG9lfL3kxRlUYpOqiRAmA-#)=cj#}R*ZDtD>pNb@1d(to;W$;u+cJmInEyEL zna?4@2vUxr1?zf@mrA}l*{5~?y|!9LB13mdxT^~Uq@U}G?YkApMIu|?dvZxVFB{*4 zB5`48Ezj)~-e?}JN7Y7ooLGZ4SnG;yeG-_Q?!xR)#`-UEGB!@?-@0Rz8jc!SukL(F zW3~k7o1=7Xe=FULUXuRI{sL3_1a~JCo)G=Y0e+iuGGjUO9`MN zF<7nKNBy+uFp9vdw-z6yF#}UQJfd)4n~;Z50M2yoT0F+grCiL}k7XfBGhf)>@lOo24nOV;+U9&<>TXsl(BeBsA`>zMd$t+N(LJE)YTo#9~5x)o`@`$#gnLlK{v~qD$IyHQ99#ZG?h-U z>5x;pVvnr4|EyZ3zutdh&k~6!oLo`=f&mtF_J}DgAVuy@Mvf$1oo| z>8Ngn2Bv78d<9`dm5PkYiy~7{L1qatnn+6WO;&t?|5;QWnJTn9C{tiBK41KJZoFMe z{dE&F8EP|zszMocs|^`}SGvVf@6yQorp!zTN!I-DTeC^0GZ-X)Onr>1vd=cUnJ5Bp ze|DRP2&nGr$`$P>dy)=sJd=RLyV=RXT)+4lOq0jVV;_;oXB&ut%vf=79C(@Tk=QKS z7fwBdFF#nXX>Zk$SQLdbIiOZNsOw=4XSHr(j!3sQyg!Y_W#B)y(#4fRGo8&0J55pf zZxCh#O)XgcM=x(?>^Az~z&l^(Cc<>M{y;cG!NcZM)h&X|#EUwrC;?s)l$}Ukr{Oty zpEcTZzks&sE3R8TUPbov9jOZRC!Lzg#Z7;j4R7|HZZ&y$@7N$X2krMHm`2Y`_$N4& zBj4Cm#GA*L-=4g@rKMH^)r*mRzyHek?KVLlA%pZ0AAb-Vft(lIY7?yPPW|bU;ZIH? z!zG_iVpPrvU3^q)SBbbgpqr6zeY|eAm?yD2XD$X(Ufq0dQ+HnCdh<`$)8fSto7+rW$Lg}L#K?7DBN}p+nJ{<|3JnOUVj!SWdV~lZ~lioC86%TQ|C6_-YIz3Nu zqImbFhZPOiX{GjMmqg_$@zJ4}r)}nB-$ra~{qb@sRLfG07^MjN6#e1*uo#LM)#zgM z`zYgQ3@wj~!Bm{=q3TQ0Np)k`eJZ$ice~`*7}ES zv0mac*{9R+)8pZ-G75C^x$3SkR(!ZkGk(gaNP&3kV%$t)^Je@T%9<|qz6kBx24a0k zjFV;tVtFs@Fb+Ob95JGn%m7s%yG5(AH%@E`C2!6c{TMqOOEIHio!sxAFnpYUy)1uZ zbeXW)1+PA(E#+rKjO=3fzm5I1REWzV4nwA?7x^ZvC-kTpXsIMmqpTY62yjE$2XmAf zUboebd$ea~i2JvQgT=F7z=gX&Z-ElAm1gChd)#*@g=$^@f%-ab&P< z*Pj{2mdGobFw5ZJIAccw&g0g|V}>t99##v-rR&yv*gaE#KQN}gE^8XUr?luod&mpi zW$j2`jJFjmcH40UM9s_Qu=y;22KDj8k{g8F1&@!|fK-CNioT72+kTjem5Cq~;g{ zbFUD#tU6nleeUM8#V0M#lpG1A1huY>efig>6p894o;7tg3W|E==`qYbYxdS)>wEVY zQMi%ZO&SU?OEN3zM6&UOm^H<6ow|g<`cK(+(-~finMLU%@{}{pKJu1X3I?bmXXytD zxo##)zjELL?|w%;-cL>g5=75_+h(3$>J}F0(t|Gt0>Zg(h)+rjy}SBLRm1)00+mfq z?xx4z$&dWVt_;VPW_fp!bGNBFr+t!j4)>cXne-*sA8n-HuBnY4bVX)&bhL|#_)rNyZj!c8KcP1f z5f%5;&QGBAuu|@B-I9&ik-8o|k)E|wtj%O@pTMgVg3krA7Jp!t=>}z@iut+B?X0VE zG6NC|f`^a2j1NxnOn-lu-YkJ$uUk$Rei|xA8E!pnOid`XCTP>PzuG%2uq{`%+%PDG zq^O#^UGvMMe)sL8kEw@NI^D|oU=aCEov*LUoMI6-a@?>uGBcc|*bqdwtCkjDXGr() zb2YEZpzL}{+5+D^keQR)XIftQRt=R_Aa3r=wNhpMZ#)bkAy7LmJSmXO%b~b-Y0M| zxdRb$e-Cs7EILd{Kg z@M`kLo8&`L<(=W1=y^{^uz1fYm+QJ(9j}wEs}LRTB8A`xyW2nc?!a(sRTinkT!Eg# z=eb=$GSJm zR>d#f6Eazcx~Tb}s-!VU=Zdc1D~W~2uuCklFQlFPY(KD;Oen(Du->M9Lx2n2cq*7abB#__dfUvA*l1n{oU+cR?fKOAY^jh~12N2DYHv=RwmHzJZ~2Jk%GLbL627&HlLPTB473=-HYBB*C|!xFUy~ zQ(LJWij~28H9oQvf=Rb(lX14S!^KUeR_Yz{_|6kfU$F4V)8z+)Dp45s5OE~vN(dcM zNVsa(@j8&d`Vxb(hVTro?v=CSCf_Xwd$E3T;wN(}hD-JK^w(IsRAg>dj*}T$e&WUM zoT!PSwB2<*Ufx)rJIy8up&o@*NSwsrl+~+n#wiQB-NljoqU}?N`~!t_b`IS@VDm~` zcB_!T6S5;I9-G@OxHnyQZ-Gp0vje4Bbcg7xLXUt!Q$H*U+j7H#?p*e0zvE#?m$LYC zp!MU^hb>z_nYrtDSsC_+R*qK*?XA*O+%bD7-xEe8>={DX2dd0Tnf&5s-d*;4D=bVN zY)NfGnHN?7AE|DD_-lKzoV7Mwd{PDeZ)GXx8Q*&n@yphS}e?ialxV@9aVheo0j9-s{%_sHRV z_~4RRAWd(y$rZn9;62)uA9TkXJJViZBo5kqW~%ol~%5Hz}6Yj(yi@=Wf-EDEqtk|ZGZPYWIdR>`giWm z8o!vPKnfHe!&rV=JIPF(k^AL+8l(8nKn>qMJgQ~LlzOc}gjtoSdzAM3$IHD>F4oRtJ zb~g2zJUHAwNTO%%M2?uMw>PTtrjAD|8Jc^DQxZ%j;+>9Xw4Dak96OWCPoaG4C$tF7 z#!tPBh~^ic^jS+NjRh1Ndht@QnK>s5Y1!M;i7-NWQk7U$@`t7(r`r1KiAZd*rj`+0 z{gF#ZW;gN(YFKJ8_*0v_ffmlurFhIz2|j(?gi7u(@A9c+z3TV4*;V*~0VBSsybp6t z6Niu0V&Rtd(wjF+5G;Bd^CR%nxSr7_vhWx8m{|3CWTI~f;Z?cYK#+gd%Pa4Y87cLL zO+v;hFTkbd8d>#%t7Wz&YrL8$C~6($>)WD5UxzQI)7LJEI1u0-=f$_v zk1@42zJI2&efW5C=7Uc=N8HsUX}NQUCWc2lH&TyPsni)Vf7!xyMfzUuHu|>LcEn}} zZhnG6-05P?4E-V3;%;}iHnpJRcgDo|zI5Wm%HRK-B29 zw#843=kufcVD)aOO1BpttVbEw{oJk2))+1>?S@?^Ng#v8p25X^j!%cv#V^&z4!}Gz z7`2tgt!L2rgp7}|O)U`_Ne=$XZ-j4;C}0W=De=AQ?8@xziubEqpp28vV46#C`$b?2 z&tz)*^Wk%>OXBN4nM@zot8duZkF_wG4t!GSVdmp2VcsDh(t%u_{^3c=$fl|Rkr`dO zdUtc8M*YP?xP3wHrwL4koM2=ubup&ED=z)cD$MrIB1gtho6ns|R)!jZ75`F`aSGFf zp_fSEn~0j;Bnt(sLVcl1WBgae(^!3DK`W1MaLGB;GXuVwU}VT*TKV+P9b4Tom=xR3 zO_`v>Oi9bACxOzXITyq%Lq|mO=I>H=7N)p7xI2(MKJhuGqlj5s??0V$Nl|?mWK*&V z@2h!_Yx@md9fa{86}CI@+&zUAJITGNgHZMAwPwkYl7wnIr%HZ7g0q#z;~FKI1JTS^ zc2=RJzKBiW3*``hXcZ54z^-V)kwA=i&Gi%efXrvIAm8XVnhc;*W;Xes9TGYqM| z^sI$M48eklN1b!=PgBJC^u-b1Axp-_o$n%?iA}S%SX8JpB15~FZgy$;Sd`bLFR|(< zO(DjUVY|19GPom`T8ti$TVLALk$oaZ-1Dfk;)-U}iD{HYJ;wZSrDnnkz_5uIH{xef zaT+sPja;)jrs|L8sY4CG3I}d@2RDz+rVWqQNLq4vTP%E8s4q^os_*tZ&bVMy+--J? zf?}oX?-)I)b2iZa6l6T8nmvm{#RbltQ4mZ;;&67iYiUd9mKiK(e-# z#HC`XV_f^z6{eqm-?kuE#+J4yEK|cr{4C#MVk2{qwF6i8dSZ-gc*j<8*P!6&&qVJX zO)FI|JCl81rivG4l90Cd?8hzCn~|(LJFL%+q9(5$HElfKQ_hRO887e z#_+NH4+PDgpg0BQc)Ww7*7^P^DY|&I*M$VzV5#Wg0gE82a0xwMxXaxzjO@LvcOY(^ z?D6`7^bz-xgaS)-cLAqEW|-68davRMsyN?#hyJ!uI6Ps}r|-GR{m;3X%3|h&Qp|*g z@p$*Ac;ZQOme*oF5$QrTgjWbxUED|O+pHT+_Li|q?NPSEPZz+tn2z0 ze(mY^l`%y^zHJ3x%-6vZCjG|i)V*H4mbvGZ;G3h-+mXQipzOqwtuAJ`7d)Z{lH#^U zG_Tzbl*0xl;Gbo=6V`5C7?I!6H6^1p6ry}Uz*D19&S2{eg&D*L)Ya1lBIL<+PN4}+ z^pC5`E02Xa^Tmf~*>gTVbqG8)`J11 z7ni-94i?%SKfz#K%so876N}M_4P-JlU^`ZKvpzYnext1`?(4ufJgtiO1{3aWJ;rql zrbkLCF}J!BF5T4C&ahEUIn>>o!!rHyT73yhfAYwez!MptL;u_+Mvkg_s**6S+;Liq z(M61Tmgy3GU}$(YW9Om;syTL*&_7s^TE86Daf!@oJW?Lml)w9`n`X6JG&cV+tFv06 zV~xn(M*4|dEXg^pG@oaGz>&!}3M1eO><^Vo?qL_azTi-qOh;~C)2FswfS-7HhkM-4 z@;5Tu1z(yeFs07+r!IPXw%@|p`RaJx#n_iz+!)dKJ@=b^f(OKO9SDWF;tg?6bZ~wj z7FIemsroB+nZ8;xj95)R*hY9m-&|LcDU;qKc;rQQzC@2$>J-eW_!2o*qwjl8#`PWd2w}*ucgb4=R9%Py6``+MVpKnkeV%YC#NrK$a^`#yq0NeTerMEE^tSs(W_Tgyt?_W%0P__53`@LRm}An=)|c#k|j9R zWjZ8jmhHKl(>uJ5NWpFYVmLs5i)8qsAH2-Rjp1`P6Wv?65Wa6v&G!i@lVw3~D|>qO zIH9zK8Sy>SS==&&g&U8PN$?VS*;Q3#^4f*4q?!uMib6Q3_>xDraEli=Ik!dO` zFx!6S7UqBY*bH$?$Jz|$;<^;p7L-~$h8(`nCf>j(MRpd$SZ3+)9^|`v@1_cu9i_9S zIsU3WjCkLmMsKne&!=!E#VnYCJyfG?wPd#ajN2bCx*;p$`ZB}d zK&M;V$+Coz@qUc9>!=G}tYNEQjfKK&qv?bbym+;15p`QtEmuQ%%ANx)9{2Z{s@Zu6 zx?m<{5L@#kxpr?O%Y?Dg?1Q=k73SK{tn?pzFv7Uk;dSGYDT|Ku1)}irEt?5h=@wQq zMe*-@eBCE>Nx7gwnJJHO3?g{nuvAbBdrtD&LV;7_h^GE(7t)SmDc%%OiR#z5fyEC) zY1wlAAquBbD^x<0Ej=SYtW$CLkdo|#ooFO5<2Cwr-LcWC|FlOvIoQEwYjU4^1(O6L zRFx?ATXnem)~6U7s`tdbw|UKyi)a$Q7?srDEf)rx= z#c+xsY)3~f_+))51JrdKLkzw+UrcT~F!7o@s=wMmO@V)>xjHlj;S zyS=axbr;wFPAhcR1WjY&ko?y|G9CH1_vv{xk(SBT6o)16^dv`{!>=Nxol@mth;79R zOZE~LR?a3R)XNSm$eSxq16_eJOQbNJT|64N$n{A)o71m)!c4m2W$N#VW^K+8yfK*y zPJ699rn{DC=UKRXZ%G^f6!lARrv{v94uDYc>drv}A}!x4$465Wo!jB(lYGK~n}8R-*b`H|eRX9QxnXdL#okTw z37-_{$ckbk%6+X<7++lOmCC@rHe-S>zoP7nrL#E9*r^(yG3-Yfj+;VqMInjB`$-m| zuShvZld7FUMQZU;d3?PK-erzr@-oPi5)OC?_|nM zD2wB|ZNfvvjH&C_DU};wFE=A&--9a^idL8oxXGi;F|AAUZcXV&xhUh*+gVr+#- zqaln^w!03an(=9>O@^RE6Ir@LzUPBoci>q%Za4mrRh=TCOUhk2$TMMLXEF)<64te` z99iA@cG$1)3Fc%;X6Fr=RuMvYlkiQ-q167(a1cJk*S~nGZz*9xXq72vU~r>Jo6p*d z6o^wdB5CINqG?4>{o&DHitPr?LQHi zZ4)?=VTapq^}@#TJ$`xlSkJ_^yNo8-j$Bv*1JQ=hbBdF=<8?15{VFTc#}L09RI0<$ zoTB-ojD=-Gb3 ziB`GPj<~N+={a0E;}=xg;9HN;HX=uAd1_%COyfF^nN7Sf*;9ucj6qRbMtj^Qj8eYl z{2r{?jLx9vG$Cs?P2R1a8YiX4kB4edT+RuhUl-ev_jOE6Ohuy~InTc7vynn-Nm!Of z73<%%zOi^TX8IrC>rK{LQ}Vx9=2g^Y-7f9mk&MrZwEgI7$-M}l^P(6uxzQ9}{r2^^ zK2qaJl{~(?lw48RA5#UpJ;ju2JQh8?tX6dM=>{CA>$US3+AV&eEX_#GRML-ETwBc+ z`}lUCE%rgc3;7T%Mm4=#gh=kSAlsp=(4Swo`3sh=Kpr~Qdfohn0 z&4V#v^U%P^o(Z#tH>}SIXH9cLi+hoJtqmC-VsJB=`o#KQK|mT3N)T4UPEu%;Q7m0p z!B~keC**cOqM9{U!~8m&m3WuhO6+Y^zhcriEb6hf>#^SrtwxN;{cPeXa><8cqsaVT zVM`@yYpQi9>&3(#Q8FPGE>o^Qg%CjG){UGvA4}CGL>x4(N~f$MO4m1=Ie0P^ng-%1s_Ox*l4)rALkN_pD}(kdHi;SI!SflGoji zoxDT|2hDKlr~6}`xx{Iu^Ou#h@t047G<>%W*Oxxu-ZY6lICA8Nh#c>p>5N+Ggiqi` zrD@$M(}o^G6TM`&$>HgD`bi;b8Iyh~MFi2S;HYqaoCV5sy4^UfFVm{rzr`z!U>$Ly z>$!3@wT4JZ+2*^3Vdv)mrbrjZitL;ex9ENZbK(~@^a zmzoO7&;>vESVu`ek{DwaZNn=dY*r)oDBMmv{WYcKYV%j}iSF%{=em!+X=u#ag-7P(UH6U=+)()a)Fxu} z4ezccx!I{#!i;iq?2R*LQ|Mo-H?#UIuG}yvb)$5mu3V#Zekw3bDmr0U<1NZ0Ts&*T zXR`eZ!B3ul2w4>!k#pBZ!?&iSc^jx;3$Y2o*tlX|_GCLsR4FyA=&_&;AuZ9O{esyy zm&gylH$VK`typ0Kq_THz@7raE`l4t`qa(9MBvZ#Kri`hngszXRjj!J}@&(;3d!O;%91ZC1O=zv^a)9dYC<%vUzIajY~*XA|KLFN!)*EGNY;z7 zXIHmANtbnN6CxP|Q43ZWq-E^JS$N!jK_ifP)J`;z2{I$r4$E^|?-7ra>JP2Q zzpVS%thFnLGA!{WB)i7RzA?+=NWFb)1L2u`eO&g0{h^5Qw7M?&D?%0q+f^oZaozKw z5^2L8BG_R;mQVS?xcc20{Gj%|_py^0NJUxyhG=m&cemhOvmMcd5@r~)w$sUnacf@E zf^ZTRqdn<{?M8(@*E_O9z7&Ihu}M-0WL1cN&!l2?TIHgf6hr++M`T~+7V7stAm;bf zMjuyg&Of@2F zu3IkIKwy#sx>Jh!zjxK~i0XFc!&V_v>;~88tw+BCP5SY}-c?^tCvd+>&+fME$*xj6 zj~l*S>%G9ILZJ>mHQV-<>F~Af?d|J&%R*t5;Z7y-`2NCvb?Y&C>irP)$2Ps(vIE4x z=O%Bj3>Eh>Vd6sgrv`=xqMLY~PHc>^EN@08s7zO}?fVo(X!HPJ!L#db!UOjYN| zjF2uZk1CLuFrRoXn-K5T5mBF?B&S#0m642^ZER~3DJTi1@tcid{Znf+y3VWePZd6j zv>>nCds{O>&FzSqUnMS$au%hI-aX;op+Szv5ar}88s5@39#$J&R;`(!;6~Cb_?(<_ zz{ZdlTj*a2P*T3LP35>J66(OU8~=DqqIF!Bsd|dsALVkyxxDROB;8y^V4jpz`*h{ zH9N7V8f!)^&#R_~W`u&;u~3a=?k!#`G5`<9Z!R$%7D$}V%JN`UFG|g{DaDM!M}oSL zGbSo}hZEZ<3Vj0yi`6*>7c-BJpTD zB28bc+C!m???@6liIv( zCQ=;LvkCe1x+&ymRkhvx^p@2Xgy)~Bx?0I(Ykg0Lk$x-jKx0Cbs(XKyRJ!J{Qlya_ zB4q+IdEL6p97m;}ORv3WkYdA)j$$zr;aYv7cGSX1SZ;xS5OTXFs3!5za(0%8%IWrf zLc+M8ZF=9-oPlSZv_{M{AY2rGfv@L7*tANJkH)(d$Z|Szj8n-i8Y$JphWp&XU@vw7BkckwLNed!kuLV3mAN@Z!%=`=p=eb)T-^ zEXp#_Qd|a)^tolwNKx`{ikF%Ypcp%*?)l!?gOMBRWM~gp;#EQ)xq*A3zWA5;v)ky7 ziPvBPH*Z}dL;02a)2oBLC;H;d>=Pf_eXT%PwycpbTCwMRsOGL6XFqPK8m!?4Z6|rg zT`#Gq)!^(nFV~$AL^i7b}`@&w3MHD*RYzPon^o{ottWQhi(+?d8d^Uy&}HPQ zoi{~Yt0dK-Clx9N`})V_JUm+B0h!TXQ+{d6>_WeG** zyxrF$qf$Cg_kv#%77^Yv%)fOJrJs^qa=|+Fswb#Snr-SZe5FVkZ7UOw-@57hd4=me zoi}3Id5FR1M?}BBz_&VyF5Wj7G;O&|PsS?I43oo~o(BaC7Y9AE99uiodC6a0AN1sP zwkGI__ufKSi&EZIpD~&Q;FHA8qXUpj7WCBEQPl6ET%`0FeIz?;HECJu_Kb z2M^6?-yLiWz3~$;W%l^WBCx! z^JX!!)#+BWf(`OZQe2C|qjJ#5Lb`a`a$pvNbV{Q0rt#rdLtz%aE%j5L2j`0F4OV)C zJ`n}%p;q`NF2xbIZEEAHIc3`_z%@yJdn?K>^O%2!FxbW1QZDl88ehHI@5*vZ1-Z?$ z)|b$#wnpr}*{PHzX|!{;6%L&xbff+nsXhR-SahYeK6&vq%=ju|hDYc6;nGaFCH=>$ zCGH)OUHJX{sWTFEQY4&kdAe-&2geNp3s+s)tej}V^ZoAur8jv;xnnKs?6Yso zo>y9i2Gj>ozBtIs%WO2&rC0XO%Cifsy9p;i|3n8h!AbXI?A!u# zJx+5}VE04(G(giquWJcv@?tN)c$)_6*#~4#5uOLn7d3!;F|B=xRf7# z0)IaVJSIm#;9AkIFLr(-{-2-wuYa)&D}}3sDm>kNf37F>r}z2SlV;zgw1CU#Q)oiX zwQWlgR(APwo_Kz%=WRse1+O{&zCCR|bk->eknHx`D)&QP=0#QS4U#-9JLdUbbNjH3 z0&AIB3PF1@NwAVIXCipET#Qq@BEaStpw9J{w58z$h^q70IkU#Ux*m$?Cq`eUjt3JxOsw>?r$587>6lIg>Gp%G`|Jsv_@x*_jIot zse7(AY~Hiiah2TA^xL`e#pdo`LXSe@BhRkI;vGN>bLNGce#fK-HaY_CC3hnsE~glH^d2Ew=xWM0Bp*TM?Qdx=I_eHF(J#U$#DmH@^qA zeoo2%&O&~d*Q>ymFS*#y-uV0m4`zW^(%FAzG27Ff!vjRnwP4gieKP#JD^TY5s#3?w z)@v`@rw8%Yl?7-%fMmrEhC@{Bp(DVAC@phz2a?*IDKbM7vHx&H^Z*Oc5) zS6)dwHHOoJ7WOv-_eh)e4Ef#FUvp3Wi|v2~0rY!8+i%f!3}V`~BQD~XeahS@EXfZ(L|dj`*s9drA9KAYf~8W4qsr8>9F zLO;9QueT1(Uvkh>U>enhd=MJ!J1sZVR@;^8mV{nA5|@2|$!+=QHHD}A7IQ_as6wyAsXMyR3a1rSg=r!=!Ou79Bbzxz|^1Hk#c z>o|+e(d2)bj2iwUot3@#VePNy5cBkxUv0#7Za+czWOvz-3SB*j;ko2nU;x|BW!`~g zY!{%V(ByH{Ck$8MvY@0v$u^IJmf zi;U;g>u(@7S_~}<;s7sYZ^(%C%vT5_-jo>#QP8df3;4?|s1g10WgtJ9^Z(IeoikbR z!0MZ4&j{!!_OMEJQZDQ`zt$vC*xA1=D|>gu@km_qNY=9XIlJ@RL1FgCihkT6ItL2= zl4YeY0t9I!& z%x%krr4)$XP{l}Op>(&%Duo|+n$CwFlFzr# z=!&@*k7s-crKxse*>a69|AlNA5xje3cr7_1h24^|C{a&5ZSN^ z@chtk9S{Y~ccUxHa<|{*%-d{!&TsJflx?f14It+r-K#Vo8Yp#KwPPQNhYW+ZSLEs) z`v$WSWQgI!ali!W*idM?@cC3JPd=eHF6Q@)`P=Q5>H!`EyJ|thy$?=Vb0RsZe9AQAV@;B06ooJ{;~R({F2tVdyr<9 zo<|dv!d#5@`Aw1$6%p4;plPYVcy1|$G_JO9nsHznqQzW*Rs%wNKO&0=m_3UEV%H`EjB{|ij>=Psw7w$`h7Z!nYJwCrzf^3NJ`Sz*ZDWwKecBq*%# z^uoVHl|N6M1%IVWW?_J2KGfW>1W*NuW!ex`VF(SRbIHN&5P@c=ekl(V|C5K!@)TOAF05tBv71psJO4()k9Zn$%S7oKVrfzo*L7UtJLZJ+m5ngDn!3xas zvMPBEjSZ#>zzvaVWTDaJvb^oJHjgPjqdBh3%f8qa13^J5B|wv}x7h)L?gYBJ1|-cx z(}4w})cRievvK>2Uvvmu^@222&jF|`3Rj>?r_2t% zP+6&riLl!c_5HIM2y4h=aS-c_egTGa#RV;B#W)Y_!K`?q7sQn5dI05A9xx%+G{w(` zHO?I^(CFbP0OHVqUTJ6|hFk;U(0r6VG(YluF933j?uSA%>>P&uWZ(W%hUIDTX^%N} z_CsSdPtodo%6QDHh_H^c`9GBYFD&JcKcQ!X`qL}4q4^!jA(Kvrd-1m>$4;z;CMc3` zi%XsS`wvyL&#YMh&6PZ#4Kd;{snB%iGH{V?QyB{uK=a2Gpxy*TKD5(r9R_e)?K4X` zFZN9v{$Y;IrY+iKEg_}=bnskVorfyK2-MHe)UJu=NT{~*KI=!l>`%GVwu%s6j) zcJ>3~Z12*{gv0=z{@KGOrKcIt=;7)K+-jCezwf-a_tkHE0?0-ZX(T|ShiV}pe#?4K zEod%I9fX|J<$V-r^oX?r5q$p&_3u5u^9)4Laf{=DbtWr}c|fBGPpp1tJ;}ROv_rq* zy>=aZzbwQErqhL2BjMU)u5+gkG~ghhI-5|*pSZjZ8d?2k36!z2aITScet--O=e3l; zi`08;Nrw1>w)S5S41ssBH~*(p!nN4HWAt2iTuB>5QI&KRnmgXqI+Pp&Ei=}+87S4G z$L-KgnM)4=%WHJvF${{`1=q4325j7XkpYbxu0mjo5v#rkLzD6lp&k3Q4!5Eps^WgI z#f=B{`~uArJp%Ly4fm9QCf2ebgQ|7t&VM({0Fn?7Ex@p#v0Cz&wXLWIZ@%wMzImFn z?*#8O1>A-exBssBe;%yRL4aAb)q9{JKr{^a%22we3N*I$fLYb2KQDkNkKhPftBKeS zO&%lHj<3Vh>|G&-THJiAhBkID%51*{i6W&UK#uF*K2(CnY}I2xX>=TOp@F_x3Hb$Z zP5yt8YdiLBw@F+Ck&GstcGon-eeAuU0VACUVWst?al31ln@gTT6H1<4;6T$^k6I3G z+9i-NCG;P?1Wj*hfpEpVD}>f+ibisE$-fYEFD7k-R{ZhyB*=HlmBc{H!aS9=y=IxA z1hM&S7tn3zDrzq@D)xb59|GmbS!h%|3an2Itx#J=E_+B^f3Vp)qkO7lze4K8+tbCG|WAnym43^9W0kFH7-4TTuvzjm#yX@E?*i zkNG+wKmZKaLTuXFECn?0;U+0)5e4V9ey|2D#ML3)ow?r>A`JyD$PG1%`3SjJ^R+=M zdehm9Ci1ixhb{(E)+|Xi19ZCJp zd==ajctf?~gAflduYotbdH));{9u^0?X}qVze4PIJPfQd=IJ4bEof?73ew$*vUeda z#&eB#vOm~Hui}hI8B}tfDCJRmu_kf;8a}Jc-2f(%J*7qFq1ZpH0Qw+M@e1>6(1MAu zt$_T*;B(LvXam4f(hh>qf+U@EARo>u;m{I_H$dHUNZNtTP^{!au6*Es^V<(XD{hqJ zFpDitI_aez!sTt3A#zJnVB=7;IB;6Qs2I{I^VMl z^inQD=Dx!amlC+JeTP%1CT~7sH5bHJ0~KSIsR|dNz1ps|AU3i_L(G<3nvIS63?QBY z*3QO8rzP3kpVt6w4wNi=A{-(TfdezuyP9Xt!_ALr52AqWz~UZ5Ln3c20TMwh=CEs) z$bemhYA;fzi8Dk&6i_v_Z58iGxaJt(`y5APo9~XEUz+Fc0+^RVY~H+MAcQL2eT8`d zT1rCae;0@fOQ~G(vVi8?P62IARhEU;BLyM{y^7#YPTcU-w*9AZ1BYE~yZwJ5%=;(V zMPQ-udR|a>+}KUT(mj(AT;2A zg?rjDM53?@BP+F}XXV_@(`=de>j8T9h^qM#H?%B$m>h^uT5g|&w$Zb|M#54Bp|y?a zJOL=}N}e&EgJ1yYWKO8mKaE!$N35;W-fA z+0&(<-5i4U26lJ+7B@8S5(c8y*bjlbesF$1R_7D2yIos_!sZo0&KV?~+33zhqG4X< zmK`wO00DAH#zCDQYC4~-ngP3OhT<@5mO&h5{Sax6X8q7Uj%Klq3^4E%0 z0WHU8%}E7FEph?7X_ zx$biwNQ8)eivm`<`)ybZ4Q9XOjt#T$xd0K-D|B9qO*pvshba6Y#1EYD!^?j2G4cy# zyPL#Y|M>G?Ppw#{Dn*t(0TE>zl=9|h2P*&dqknk5Z^;}Qmth6-<|=5h1BX>?GIChO z7Hy7JvCRNStJqeEV*uwI2Abom*cl;?ubP9`k{nnu7jB=!U;VT>a9{-oR?LBj zxxk$5N_9A}f=vq!tl+>3Hkx1$IIw~PE7)j)J>b9!4y@q73J$FJGobp@FC19GffZ~t z!5(m61qW8J(FA+IffXEB@sGd?`}-r|b9VvEk^Bz}bNm*^Z?WAKd%*Eq9KXeOSL^}D zZ_OD|PE8;?DC8X8vtvO{mYtJjXQK)BfYWNgffZ~t!5(m04LGo34o$E_vVRm-48?_Y zFlsTUptY+lK>MJn*L-abEc(;#*{|_02Wvp{-ddA}J8a-EpMlQ7QeL%P*SD}`WnKf$ zQf%7(uM)6RT}r!t<+CJcSBx&?It7H+QvT`Me<`AD5fb z$AQyq6wMy|lUX`oHz#o}snHPo)OpTvPtTNh@T$Ex6r3|5^R&GUpvCev%~-S3?$`&O^er8gGLKYa2o+> z(>iFEpdAFa5hRn3L;K#QjuE(xAor%;U%ok80Otn({j9>Rq>X44dqO0kWSGGC%zA&> z?)^$K(1b&P6ZOvt2hTrgrvB@%?dafTqB?xdAl`f;kSF*}5M#ESfOcn!fGMzu))q%> zpjjL|FuwRjH)Pofz4;8DZ|b~OlyeUU&3J??jtvW4B49Kh^U3}n+oPqt2q#4pG-8MX zlPJM28P5)n<})b0AFz_vdUisH4MFBJP+jA?PfJ`!1DYe+4dgewY!upk`mWnLulZ^O zcthi`1K_a3?JovwlFnz)X- zGUT5qKqEU0kiBc+8)%YivY=PX|Di?mMu00OoLMt=@6a6xrKWx z^amG|K{IZuDqtG93DyVEKU8pC2@7pocncbEaCHXL>aqAnh%VyJVs0sk{6(vvVTaB( zZf>ari_jE^UP5{q&ps{pC7U6_hkRZzEmzzaA_CK2BXG^Po9`Gz1OZ(B%JTv=&q7W2QxH*QKxxX-q7aq%y%ovkW^`zud)4WDISWZm{GUR+Mmb_FKzlT+ z$5;NWU4Qk9p#g|oF46-b-fygm06~Fl$AK*e=aVa9{}1Qo{sg2Jp#Nje+5RF`QdAUc zQrmd_PrAY;`M(;VBLuz0Tr{qR89njb0__{p0i}m#W1laB#~~hECCh?Y(Ut(W^ST|x&{4TV^KUX9OBaJeQ8gD?N4Cm#3B(K<3;~(do5)Y!VJ>Gf%BJ+SI z349mphv&EaZDQ$XsVl9V6>H}96MO#!1=ytc^B`FUi1o_}U8kQP_jghkTQn=y)D5el zUEA(zJ}cI#+7K0<^K$=!ssA@PcW7x*QBe(&cVGM}6KEnPU@9%ig9r|X_aJk=_-M18ggm#ai_ogpXYi2`K^<= z2vMr;fi24Zx*8%mrsGOI3*#g>V*ES7=7{mnqW6D5jGK6P_E|sL2rV>Q$Yl&P?eTM{ zKzki9#14^ zaP|{91pYH{#!)hklKn0)_~AUi<}8c(R|!!AY3^Ob(7G`^mBE*m5$BzxOqqOyi$3jhyTv8;_N8 z()m9j5j5xM_xFhw^#AP9FDE8r+kmfw{|hPn(m^H@@uaYz;64Rv)rsUWG{LPrSevA& zsd+Ry*QKM*18T{Iz|&HSYFD`gRa`!A4}R}wAFuc~lbU`hQv1 zX&J|sdn-ky-D+G?3v$DnCLJ?l%9$+JiqH(vTySM+nVWZVA^+Xz~fc~3ml<_W>^*4fFU{*H&&y%4+K@?tMwTGKq#`S59oX=!OHU2wf z_z%nf39kOX>aL5?|H;kQKAKe|=ti`zDwdSWrmrOy-Q)K}&%wEFYIn6P#7-9AG#z|K z`F>3!uGK=VO(Yp;6WAl+tz4u|5f~toTY;GNOfg9mKOfeZ%89JKxgcDMRcMJ&Q1s4c z*me$5H!_z-r!xc!#o2xY5ku%K2FigTXt7l?DTQ*7u^QJWY1vqV%lWX(?H@TL2Fhe$Q?p#t zqmqac2BeZD5OjxWR&wGAM0PXmSS+trjBts7z>|H|->bJGBOc?UlBDfPgzL1hBzG$?_E5 zWh%PxOZJAu+|ea+C|;2MQ?_ohT zKrrx*S-L2|x-O3cyOmENq{Ig)LkVX)bqOPHh>fgY=TtNArNTxv;w5k9xprLO2*V6) zKtk!4jg#myU&;gyC_s^1P8f*KCzXvO(p9EMw2bu)cX|{?UTyQS!t7X^)l|0{F0*co zX~Q!9IfAkZ6*Q8i2ok2jrDyq+a2U{P>$Ex|Sb)U!!{&x>fu%Hb0_Iu$f^2n`Ry86~ z3&Tc=IGx-+8Cxph()G^#jUOI^N^4dajkeXa^SQbiw)%1 zrLdJd5aVnYfEP8P2E-24>~l=K_^H~fm3E7Q$NrQL)svMg6ZJ{YU=?E5L@G08`RiGU z$-sl1As!tc7J+nq#;C?j-hBX`Fz;r~ACvFrMf0gf|ZEU3!&-k_T^*rp;P6V?XnxW z!|kOa<(d*bBslWSO7Z^JC5yOV{Yhk!jqmH0mo%2)B;r@rAT_?aHIyGFOX{;|3BtXv z6y-KWDI?4|$r@kb?}LHvV7J30p~Ik;nU}xA>T?)b^je4`u0g-a(D)j1)ERLpctc4v zf9+*5Su{-b2r5^d!rTchwNJT_MGA7th>L1bP5glp@0oM1S4mg6rJ~X?(SGR9^yn zW+Ey=L{y#;-P0uosh%%8us1Mp&W9&nWYlHV*Q%|3_?qW?h+CeUdi7O@mTgV#)F%rG zRV5uhuC6q<_pea14nxT`QBpw`LAlbFN9nJ>q$%|8Nd}V=3p@H(h9!%I_|zb!d7C0g zM6-HY01#4$0>jyfDMZVa8v48P0?Ex&^J+oL$N`ktxj{ft+@fo5-^4a!7#;n$5y!^r z{eH6|>~^p9<1(Fqq2-;vEJRyKVv~W6&e6?092zTps0%J*+X~PevS<~lrg^(^)8w%h zqZRCRs}i0$>RZU9{}Gji$ASKA1FTQXYzwnEiC86PJQkvw!sb6Fzt(2T542lVdNF5I zmoJ|$eTrVv6aX?zh>8dD&BCSpHVOBlDHt+JDKr-?WRMCa6SXn!IZEG; zk}rk!#FjW1o}Ue+;Lv=S3v!lOp`o_Go`eamE`>#WxY1q3=>O(`mUdnN)a;@A;Kk}8 zNvY}%z~V`pho+j6u==r#w-D{} zSLmX*rx{Mv@vL8f8x6q<{kb`AG;L~Sq1%*bPg{xIc$+u!V2iv+;%6fN`*Bu{B26@{qE;HMlJ?2=HF!2C8=*$`Q$Z*Etx@|d=j~70`zQ_t>RfQYk1qMIT^J}SUqKLd;3WFoeP2M+^fBy+;5f;I9c5qm#Q|JArD2MEYHEF@YCZ3y*#Y{!pU2bN%fy z=P+}niT0xQt*<~BxzqujFfMDYF!l!j^y>bYNqpplgLgB(!#$Z_E`zy+^X*`hVVz^X zuGmMCFPwUgTKOp9;a>BKv26WI$ef98XsdoHFs&Y;7{pad4E-TTJg#Z7K@v`DMe?iSIQ>%h%f!_|qpr!q$yYVKY4V z(5GpTUbf?96B6TkIw#yG`kF18(lXhUN~V$zi5Db-2L+c%mzgLj^vJiSC+QKJbTyhsh67$45cZfbVGLEu?^FBZumeJ4S5n zgMp;XT}`$~T%NEVXNmii6MI>?CtVQK6dm7>G?o$;y|$a_1wq*uIyx`jHg?7Qd)wn4 zQyw0wJ#oPkoO=z6X)ey&T*^VD!_xK|+`v%LI6Trmq1!%LeN|kq$#pZQbgT^ha8~L9 zyk*GB|AnfElkj4>gHu$i0`?2da`(eF6?(krb5$Y0IP_R{X%$mXt-Ls8Zz=cW{jK4xm#TXFi28y)IX0;;Fl)bA)4zJx!O#H4eTXW;0*o~c{S{75l zMiwlu0!e5}K{m#zZ^_=di~-G8=)8Occ%v6~RwiVG4_7z@sKH$z$5R81Htw|HXg#z| zHG+wQb(VLhmK?JrYBU$(+1+5M;`d+W0K)3VQm4+GRZ5JgL@vY11G=HS4DA zx8C699in|lvd~oql53CwHl*QJG5Zuxh%f9p*~Oc#moifNrI2fZj=q*1@&;S30$Uxv zEhD)(x*?uA1&@`ksVo&YhZAZ6>mOx~N9!9(h&?9_d%zrdi#5Ik5$N^ihG^I!;WF>} zk;_+JI|aOmubHYi>%_GeU?36%J%&4(qD)C{4|7gRuv(oVQ)dRTmC+;PxoVT!k+r^cdSxG*(}!&ycVj!sDX` z>!(~wOihtel!iW1>=nlXA8Bd4L9_XE4ymN$NNk!%k#mWBaopny-nA7^R!NH=V|Wmx#C4ZT0+9684M4x?7y)so4*CfP8(dQzjriY>x0gvGa_Ij`oR9d|sQZ=A&_}a`Sbr zbPa@vQlkvpZHR2%g8Rm7mGC;rD&G|?D4X|NlCjn$wwhF&C-G0bbh`hqqa9$dJ~fp9 z$Tc--yRfF|b?*MGyR&&Z9~`bfNS$v)+(VFd)Fg*7zNRfd~e*T7K(B-J2sA#qdpw%Lw*@KoM}zQOw@ycipb|Sp z`$yn0-UFRCHvH@y2&56h*{R(v(EN96(W zq!#}OSOemPaW`+Kybg0r>{sYH_J{qjwZF-opQZqlqpn=;9uMmV^l$BlFb;v|VLmUs zNY#lf@{CY!Ck5KI*G~buJFiXMyFUicXy4Ne@2qz>ipqidl4N-REkm=A%YbaIKeI)9 z3Ow!i%+0cunPm=Fdf({puJr_FaP`PQ4<=M{9NQp;dnBa#;Wnm+t$^+|U}(rLF9~Pn zBd?{Mm&}LeyyrDYlEI+(G@Ge#59)*|=COZz#DZbdW8W_^7s|FvNo!43KHDPINWG({ zZlp0A3Pxf6K8e(m_76O0MADk9U6xD(U(7vepud|HAqR-zbMepaDYH~`WdzA_^3y~0 zcm+)DJ~_p1+f|Z~YGxe#}_-7jdMal?A z`Vd;2?fbcr04%aQcBNHpS?qKAlBB7`a`pL=>u#0z7gJx>y$q{3_pzm4$fZS*%$Dw* zG5WL}Qal9Hv3`#rBEC1yEz=FIZnIbq>Me$nBAo?oed{FXkLy~IMtI#X?Ri5U|C+5I zNyJlsJvUD| zMdZQYl-|0$(Nb=zjhzoDt04~}+tUWc1ygQO&l^;|zU%lzY(wLI>P{SM#SE7=V@29oZwPWu<=)}8p<>a)+? zC!ASMYiQ!mEohzEy#rBux2LzbF#?Y2LuJZ)^=GIEpt#+9kvH-84SC{RO#P?zTI?#yp->#J2q*F~;X zE_uPGw!I$4_C1|gcCeEl9VQ#Zv$XZ!=d#zb69W1 zMp$=C&rPG~*!i;SF61Av8>(K8yZH>+ZMwBPYQ^1z_77F{-0~jQ?z@vIXA1Tv_PdC-C-y8z)2{#WOq2(F<4rP`cIa-I2Ql5U+hs37um7>Q9f$@MC<22!rfB+jFa84P~*>(#n`4NLyJ$}I53O4ftH89-HIBrOLl|I zyla@$Jj?UH7f!x@AnT+_@?hZ?Hs&X_-Nsb$jteL52>jd=eu!o~jJ(^;5=uFbo!<#} z6d3EXxvknXe=G^*)FMe4FqK=A$ zmv0XYZOxm(QPqz&P+t^o`mH%cpHtvL>}DF1cl}H=xzPN!aqmp#(_Ulg)@3_GvE@B( z(u0<{akuk>@%yictgSVL8=PDk__Oat;SoWfgNbt&G#T%cswZ`s1GBsIb|WV(01x{} z*@(DwXY$i0oIbs`&_?+$<`>{#ApE<(We2*D|NN$~YWKWI7@2xz=C~lSdzifJAI-0L zyPRbVKw9hjUdBUt0Cttnl{OdMQA17FYWg_ zaY1r;1J>u`arcun%&tROgv`w|fn5JpPFcvA*1&L2s9)W1cJgVf$UD(-zfV;?=xXI0 z(#^h|2b%UmnC_N;?hJfW>vS>d?2P1Hi0W_A-M2~9hw*D9sqI)OJES{(5mlUHq~3hwBgi2Mp#?lK=n! literal 0 HcmV?d00001 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Prompt.png b/.pipelines/store/PDP/PDP-Media/en-US/Prompt.png new file mode 100644 index 0000000000000000000000000000000000000000..a40d6fddfdc44c9f7fb643ebc4e84eda527a395d GIT binary patch literal 132747 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ǟ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િI>b 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�E+=*#$Yf8)8vJb1}=9_dWABXCqD%pWa_q_sbD7Q@=YUrk0Qi3$a5 zS=Fn5S&oE`_j|oFZ_D+yPvE4}!D9m%`DxdI?vkAD0akeTcH_tF-D0v#6bqA-#hksR^_wjm7 zyHWIrZM^A4S~+x3trRbH2sw_R%>kr3D@}`AdQHe^23CtVu4>Z?VW2J{3z)kpX3whDnT;pQ~(JQt=qYXB@J*E z`j)AW*?o(cD5iTyBSl?%1T*pj(Mhn8j{Dn581t?JSt0V5nBup zr#y!T7rD<{n%b)KmcUc)W!X;ML^VqfRTr`;J7%D^sWcAewPS3Ce~Ry+HK#%)_m*%Bm%7Bv(isWuwV62RP1+#>ej!2Qj+T=BZoXm#6Wy3UVW{q2*z< z@rS&i9x~qb_2{|suO76K^2N~rF(LZ$2rNs7eOShLQTmIn zs}!8X)6LuL!GWy)qr&XsXculW*zV%^Ry5-MOb((ryxiJ%Cx`H(sK&F;m6Q~7!O!vC z`|u^VfW1L8oov2Rb`wihRWZ)9!bo!BorY5!dP~IeN!4lP8VE}?c-#Y_F|1E1rkJO> zBWVLXZL-bA1f}|`HzG2gWIPxB5rfkv1m8VAtDcb_5=R!u@k{#%ig#pGw$cHCR+Hr5 zd1G%;zQVt#Y=sQ=)Usc9PfI}KRWvm<#wnKnqi>}xq9`DTU~DRG$XyPwkeG`2E<^~9 z1&q0EFWm84d0}$Qm)aI=vo5>J3`D#EewALs?q%>$ z@M^VD&z-q@4bALulo1vxhQoh~v4TRv=2;hSa6}{Y1|+KPk77;>mo;O=uHxRMw>eAk z7vDV{S2n#u$!h_Sb{UOcO%x1)s1_JLQBdAdGv4_Qi*{X;DY~bykvu!-m0l2MO}oFY zoj?y88S9M%`oTX3PtuJkvjXnXVh z@t49=W46kmh%(uFe23)?AE)?l>z^8!+%2xlBN?%1#N)wfUGsT*XQ2$?CHs z7l_NKoC9Hdf!j0clfh+YVU3pj_<^e6zgUYthHO z@OLWR-Dj4~rz<31GS4IxH>WyWR-MYLi=30VJEB({YJI$KH44~;$Wc3OGGHbm^%0** ziQLKnvC7vZer-+o4bB=FdCD;%0&*Vb>$y@(usr;yEc18C&R7P2#j2hLbxm!ftxlYG zL57dNB2tJlBHmbj4EQLC8|5bYBjlI!K$YGXzdv13h@wQLr^?tUlMl|vf3IO&>>fp} z<)tCo_(&c+s?x`_Au7Wp^*XS3644_m�-ID=%B|=h~b5ZOc}~$w;f(<4)0Z?9))3 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 literal 0 HcmV?d00001 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png b/.pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..c531f719c85429fa6192eae82bb434e0318de801 GIT binary patch literal 13152 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 + + + + + + + + + + + + Shell + + PowerShell + + Terminal + + Command Line + + Automation + + Task Automation + + Scripting + + + PowerShell is a task-based command-line shell and scripting language built on .NET. PowerShell helps system administrators and power-users rapidly automate task that manage operating systems (Linux, macOS, and Windows) and processes. + +PowerShell commands let you manage computers from the command line. PowerShell providers let you access data stores, such as the registry and certificate store, as easily as you access the file system. PowerShell includes a rich expression parser and a fully developed scripting language. + +PowerShell is Open Source. See https://github.com/powershell/powershell + + + + + + + + + + + + + + + + + + + + + + Please see our GitHub releases page for additional details. + + + + + + Prompt + + + + Inline Prediction + + + + Prediction List View + + + + Error Feedback Provider + + + + Feedback Provider + + + + Experimental Features + + + + + + + + + + + + + + + + + + + Interactive Shell + + Scripting Language + + Remote Management + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Microsoft Corporation + + + + + https://github.com/PowerShell/PowerShell + + https://github.com/PowerShell/PowerShell/issues + + https://go.microsoft.com/fwlink/?LinkID=521839 + diff --git a/.pipelines/store/SBConfig.json b/.pipelines/store/SBConfig.json new file mode 100644 index 00000000000..002333cba1d --- /dev/null +++ b/.pipelines/store/SBConfig.json @@ -0,0 +1,67 @@ +{ + "helpUri": "https:\\\\aka.ms\\StoreBroker_Config", + "schemaVersion": 2, + "packageParameters": { + "PDPRootPath": "", + "Release": "", + "PDPInclude": [], + "PDPExclude": [], + "LanguageExclude": [ + "default", + "qps-ploc", + "qps-ploca", + "qps-plocm" + ], + "MediaRootPath": "", + "MediaFallbackLanguage": "en-US", + "PackagePath": [], + "OutPath": "", + "OutName": "", + "DisableAutoPackageNameFormatting": false + }, + "appSubmission": { + "productId": "", + "targetPublishMode": "NotSet", + "targetPublishDate": null, + "visibility": "NotSet", + "pricing": { + "priceId": "NotAvailable", + "trialPeriod": "NoFreeTrial", + "marketSpecificPricings": {}, + "sales": [] + }, + "allowTargetFutureDeviceFamilies": { + "Xbox": false, + "Team": false, + "Holographic": false, + "Desktop": false, + "Mobile": false + }, + "allowMicrosoftDecideAppAvailabilityToFutureDeviceFamilies": false, + "enterpriseLicensing": "None", + "applicationCategory": "NotSet", + "hardwarePreferences": [], + "hasExternalInAppProducts": false, + "meetAccessibilityGuidelines": false, + "canInstallOnRemovableMedia": false, + "automaticBackupEnabled": false, + "isGameDvrEnabled": false, + "gamingOptions": [ + { + "genres": [], + "isLocalMultiplayer": false, + "isLocalCooperative": false, + "isOnlineMultiplayer": false, + "isOnlineCooperative": false, + "localMultiplayerMinPlayers": 0, + "localMultiplayerMaxPlayers": 0, + "localCooperativeMinPlayers": 0, + "localCooperativeMaxPlayers": 0, + "isBroadcastingPrivilegeGranted": false, + "isCrossPlayEnabled": false, + "kinectDataForExternal": "Disabled" + } + ], + "notesForCertification": "" + } +} diff --git a/.pipelines/templates/channelSelection.yml b/.pipelines/templates/channelSelection.yml new file mode 100644 index 00000000000..0e352ef7558 --- /dev/null +++ b/.pipelines/templates/channelSelection.yml @@ -0,0 +1,31 @@ +steps: +- pwsh: | + # Determine LTS, Preview, or Stable + $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json + $LTS = $metadata.LTSRelease.Latest + $Stable = $metadata.StableRelease.Latest + $isPreview = '$(OutputReleaseTag.releaseTag)' -match '-' + + $IsLTS = [bool]$LTS + $IsStable = [bool]$Stable + $IsPreview = [bool]$isPreview + + $channelVars = @{ + IsLTS = $IsLTS + IsStable = $IsStable + IsPreview = $IsPreview + } + + $trueCount = ($channelVars.Values | Where-Object { $_ }) | Measure-Object | Select-Object -ExpandProperty Count + if ($trueCount -gt 1) { + Write-Error "Only one of IsLTS, IsStable, or IsPreview can be true. Current values: IsLTS=$IsLTS, IsStable=$IsStable, IsPreview=$IsPreview" + exit 1 + } + + foreach ($name in $channelVars.Keys) { + $value = if ($channelVars[$name]) { 'true' } else { 'false' } + Write-Verbose -Message "Setting $name variable: $value" -Verbose + Write-Host "##vso[task.setvariable variable=$name;isOutput=true]$value" + } + name: ChannelSelection + displayName: Select Preview, Stable, or LTS Channel diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index c8312ad926e..b97807a7e85 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -7,10 +7,16 @@ jobs: variables: - group: msixTools - group: 'Azure Blob variable group' + - group: 'Store Publish Variables' - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' steps: + - checkout: self + clean: true + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + - template: release-SetReleaseTagandContainerName.yml@self - task: DownloadPipelineArtifact@2 @@ -110,3 +116,125 @@ jobs: Write-Verbose -Verbose "Uploaded Bundle:" Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose displayName: Upload msixbundle to Artifacts + + - pwsh: | + Write-Verbose -Verbose "Pipeline.Workspace: $(Pipeline.Workspace)" + Get-ChildItem -Path $(Pipeline.Workspace) -Recurse | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "System.DefaultWorkingDirectory: $(System.DefaultWorkingDirectory)" + Get-ChildItem -Path $(System.DefaultWorkingDirectory) -Recurse | Select-Object -ExpandProperty FullName + Test-Path -Path '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP-Private.xml' | Write-Verbose -Verbose + displayName: Output Pipeline.Workspace and System.DefaultWorkingDirectory + + - template: channelSelection.yml@self + + - pwsh: | + $IsLTS = '$(ChannelSelection.IsLTS)' -eq 'true' + $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' + $IsPreview = '$(ChannelSelection.IsPreview)' -eq 'true' + + Write-Verbose -Verbose "Channel Selection - LTS: $IsLTS, Stable: $IsStable, Preview: $IsPreview" + + # Define app configurations for each channel + $channelConfigs = @{ + 'LTS' = @{ + AppStoreName = 'PowerShell-LTS' + ProductId = '$(productId-LTS)' + ServiceEndpoint = "StoreAppPublish-Stable" + } + 'Stable' = @{ + AppStoreName = 'PowerShell' + ProductId = '$(productId-Stable)' + ServiceEndpoint = "StoreAppPublish-Stable" + } + 'Preview' = @{ + AppStoreName = 'PowerShell (Preview)' + ProductId = '$(productId-Preview)' + ServiceEndpoint = "StoreAppPublish-Preview" + } + } + + $currentChannel = if ($IsLTS) { 'LTS' } + elseif ($IsStable) { 'Stable' } + elseif ($IsPreview) { 'Preview' } + else { + Write-Error "No valid channel detected" + exit 1 + } + + $config = $channelConfigs[$currentChannel] + Write-Verbose -Verbose "Selected channel: $currentChannel" + Write-Verbose -Verbose "App Store Name: $($config.AppStoreName)" + Write-Verbose -Verbose "Product ID: $($config.ProductId)" + + # Update PDP.xml file + $pdpPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP/en-US/PDP.xml' + if (Test-Path $pdpPath) { + Write-Verbose -Verbose "Updating PDP file: $pdpPath" + + [xml]$pdpXml = Get-Content $pdpPath -Raw + + $appStoreNameElement = $pdpXml.SelectSingleNode("//AppStoreName[@_locID]") + if ($appStoreNameElement) { + $appStoreNameElement.InnerText = $config.AppStoreName + Write-Verbose -Verbose "Updated AppStoreName to: $($config.AppStoreName)" + } else { + Write-Warning "AppStoreName element not found in PDP file" + } + + $pdpXml.Save($pdpPath) + Write-Verbose -Verbose "PDP file updated successfully" + } else { + Write-Error "PDP file not found: $pdpPath" + exit 1 + } + + # Update SBConfig.json file + $sbConfigPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/SBConfig.json' + if (Test-Path $sbConfigPath) { + Write-Verbose -Verbose "Updating SBConfig file: $sbConfigPath" + + $sbConfigJson = Get-Content $sbConfigPath -Raw | ConvertFrom-Json + + $sbConfigJson.appSubmission.productId = $config.ProductId + Write-Verbose -Verbose "Updated productId to: $($config.ProductId)" + + $sbConfigJson | ConvertTo-Json -Depth 100 | Set-Content $sbConfigPath -Encoding UTF8 + Write-Verbose -Verbose "SBConfig file updated successfully" + } else { + Write-Error "SBConfig file not found: $sbConfigPath" + exit 1 + } + + Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" + Write-Host "##vso[task.setvariable variable=SBConfigPath]$($config.SBConfigPath)" + name: UpdateConfigs + displayName: Update PDPs and SBConfig.json + + - task: MS-RDX-MRO.windows-store-publish-dev.package-task.store-package@3 + displayName: 'Create StoreBroker Package' + inputs: + serviceEndpoint: '$(ServiceConnection)' + sbConfigPath: '$(SBConfigPath)' + sourceFolder: '$(BundleDir)' + contents: '*.msixBundle' + outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' + + - pwsh: | + $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" + $jsonFile = "$submissionPackageDir/PowerShellStorePackage.json" + $zipFile = "$submissionPackageDir/PowerShellStorePackage.zip" + + if ((Test-Path $jsonFile) -and (Test-Path $zipFile)) { + Write-Verbose -Verbose "Uploading StoreBroker Package files:" + Write-Verbose -Verbose "JSON File: $jsonFile" + Write-Verbose -Verbose "ZIP File: $zipFile" + + Copy-Item -Path $submissionPackageDir -Destination "$(ob_outputDirectory)" -Verbose -Recurse + } + + else { + Write-Error "Required files not found in $submissionPackageDir" + } + displayName: 'Upload StoreBroker Package' diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml new file mode 100644 index 00000000000..9a0dba8833f --- /dev/null +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -0,0 +1,115 @@ +parameters: + - name: skipMSIXPublish + type: boolean + +jobs: +- job: Store_Publish_MSIX + displayName: Publish MSIX to the Microsoft Store + pool: + type: release + os: windows + templateContext: + inputs: + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_msixbundle_CreateMSIXBundle + variables: + - group: 'Store Publish Variables' + - template: ./variable/release-shared.yml@self + parameters: + RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] + LTS: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsLTS'] ] + STABLE: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsStable'] ] + PREVIEW: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsPreview'] ] + steps: + - task: PowerShell@2 + inputs: + targetType: inline + script: | + Write-Verbose -Verbose "Release Tag: $(ReleaseTag)" + Get-ChildItem $(Pipeline.Workspace) -Recurse | Select-Object -ExpandProperty FullName + displayName: 'Capture ReleaseTag and Downloaded Packages' + + - task: PowerShell@2 + inputs: + targetType: inline + script: | + if ("$(ReleaseTag)" -eq '') { + Write-Error "ReleaseTag is not set. Cannot proceed with publishing to the Store." + exit 1 + } + $middleURL = '' + $tagString = "$(ReleaseTag)" + if ($tagString -match '-') { + $middleURL = "preview" + } + elseif ($tagString -match '(\d+\.\d+)') { + $middleURL = $matches[1] + } + + $endURL = $tagString -replace '[v\.]','' + $message = "Changelog: https://github.com/PowerShell/PowerShell/blob/master/CHANGELOG/$middleURL.md#$endURL" + Write-Verbose -Verbose "Release Notes for the Store:" + Write-Verbose -Verbose "$message" + $jsonPath = "$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json" + $json = Get-Content $jsonPath -Raw | ConvertFrom-Json + + $json.listings.'en-us'.baseListing.releaseNotes = $message + + $json | ConvertTo-Json -Depth 100 | Set-Content $jsonPath -Encoding UTF8 + displayName: 'Update Release Notes in JSON' + + - task: PowerShell@2 + inputs: + targetType: inline + script: | + Write-Verbose -Verbose "Channel Selection - LTS: $(LTS), Stable: $(Stable), Preview: $(Preview)" + + # Define app configurations for each channel using secret variables + $channelConfigs = @{ + 'LTS' = @{ + AppId = '$(AppID-LTS)' + ServiceEndpoint = 'StoreAppPublish-Stable' + } + 'Stable' = @{ + AppId = '$(AppID-Stable)' + ServiceEndpoint = 'StoreAppPublish-Stable' + } + 'Preview' = @{ + AppId = '$(AppID-Preview)' + ServiceEndpoint = 'StoreAppPublish-Preview' + } + } + + # Determine the current channel + $currentChannel = if ($IsLTS) { 'LTS' } + elseif ($IsStable) { 'Stable' } + elseif ($IsPreview) { 'Preview' } + else { + Write-Error "No valid channel detected" + exit 1 + } + + $config = $channelConfigs[$currentChannel] + Write-Verbose -Verbose "Selected channel: $currentChannel" + Write-Verbose -Verbose "App ID: $($config.AppId)" + Write-Verbose -Verbose "Service Endpoint: $($config.ServiceEndpoint)" + + # Set pipeline variables for use in the store-publish task + Write-Host "##vso[task.setvariable variable=SelectedAppId]$($config.AppId)" + Write-Host "##vso[task.setvariable variable=SelectedServiceEndpoint]$($config.ServiceEndpoint)" + Write-Host "##vso[task.setvariable variable=SelectedChannel]$currentChannel" + displayName: 'Set StoreBroker Configurations' + + - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 + displayName: 'Publish LTS StoreBroker Package' + condition: ne('${{ parameters.skipMSIXPublish }}', 'true') + inputs: + serviceEndpoint: '$(SelectedServiceEndpoint)' + appId: '$(SelectedAppId)' + inputMethod: JsonAndZip + jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' + zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' + numberOfPackagesToKeep: 2 + jsonZipUpdateMetadata: true + targetPublishMode: 'Immediate' diff --git a/.pipelines/templates/release-SetTagAndChangelog.yml b/.pipelines/templates/release-SetTagAndChangelog.yml index f0c516dd28f..b33e652b3c7 100644 --- a/.pipelines/templates/release-SetTagAndChangelog.yml +++ b/.pipelines/templates/release-SetTagAndChangelog.yml @@ -19,7 +19,7 @@ jobs: clean: true env: ob_restore_phase: true - + - pwsh: | Write-Verbose -Verbose "Release Tag: $(OutputReleaseTag.releaseTag)" $releaseVersion = '$(OutputReleaseTag.releaseTag)' -replace '^v','' @@ -47,3 +47,5 @@ jobs: New-Item -Path $(ob_outputDirectory)/CHANGELOG -ItemType Directory -Force Copy-Item -Path $filePath -Destination $(ob_outputDirectory)/CHANGELOG displayName: Upload Changelog + + - template: channelSelection.yml@self diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 560a985283b..26300523e9b 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -515,6 +515,7 @@ function Start-PSPackage { Architecture = $WindowsRuntime.Split('-')[1] Force = $Force Private = $Private + LTS = $LTS } if ($PSCmdlet.ShouldProcess("Create MSIX Package")) { @@ -3665,6 +3666,9 @@ function New-MSIXPackage # Produce private package for testing in Store [Switch] $Private, + # Produce LTS package + [Switch] $LTS, + # Force overwrite of package [Switch] $Force, @@ -3709,6 +3713,9 @@ function New-MSIXPackage } elseif ($ProductSemanticVersion.Contains('-')) { $ProductName += 'Preview' $displayName += ' Preview' + } elseif ($LTS) { + $ProductName += '-LTS' + $displayName += '-LTS' } Write-Verbose -Verbose "ProductName: $productName" @@ -3728,6 +3735,10 @@ function New-MSIXPackage # This is the PhoneProductId for the "Microsoft.PowerShellPreview" package. $PhoneProductId = "67859fd2-b02a-45be-8fb5-62c569a3e8bf" Write-Verbose "Using Preview assets" -Verbose + } elseif ($LTS) { + # This is the PhoneProductId for the "Microsoft.PowerShell-LTS" package. + $PhoneProductId = "a9af273a-c636-47ac-bc2a-775edf80b2b9" + Write-Verbose "Using LTS assets" -Verbose } # Appx manifest needs to be in root of source path, but the embedded version needs to be updated From bf11519f6f345d48c4b3000a8c3f6051d564d625 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 9 Oct 2025 13:54:31 -0700 Subject: [PATCH 163/275] [release/v7.5] Remove UseDotnet task and use the dotnet-install script (#26169) --- .pipelines/PowerShell-Packages-Official.yml | 6 ++++ .pipelines/templates/install-dotnet.yml | 19 +++++++++++++ .pipelines/templates/linux-package-build.yml | 4 ++- .pipelines/templates/linux.yml | 7 +---- .pipelines/templates/mac.yml | 8 ++---- .pipelines/templates/nupkg.yml | 10 +------ .../release-validate-fxdpackages.yml | 7 +---- .../release-validate-globaltools.yml | 7 +---- .pipelines/templates/release-validate-sdk.yml | 7 +---- .pipelines/templates/testartifacts.yml | 28 ++++++++----------- .pipelines/templates/windows-hosted-build.yml | 11 ++++---- .../templates/windows-package-build.yml | 11 +++----- build.psm1 | 5 ++-- 13 files changed, 57 insertions(+), 73 deletions(-) create mode 100644 .pipelines/templates/install-dotnet.yml diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 552e7d10a68..9c2dee1c571 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -27,6 +27,9 @@ parameters: # parameters are shown up in ADO UI in a build queue time - name: OfficialBuild type: boolean default: false + - name: disableNetworkIsolation + type: boolean + default: false name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) @@ -66,6 +69,8 @@ variables: - group: MSIXSigningProfile - name: templateFile value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} + - name: disableNetworkIsolation + value: ${{ parameters.disableNetworkIsolation }} resources: pipelines: @@ -96,6 +101,7 @@ extends: Network: KS3 linuxEsrpSigning: true incrementalSDLBinaryAnalysis: true + disableNetworkIsolation: ${{ variables.disableNetworkIsolation }} globalSdl: disableLegacyManifest: true # disabled Armorty as we dont have any ARM templates to scan. It fails on some sample ARM templates. diff --git a/.pipelines/templates/install-dotnet.yml b/.pipelines/templates/install-dotnet.yml new file mode 100644 index 00000000000..c2a2cfebeca --- /dev/null +++ b/.pipelines/templates/install-dotnet.yml @@ -0,0 +1,19 @@ +steps: + - pwsh: | + if (-not (Test-Path '$(RepoRoot)')) { + $psRoot = '$(Build.SourcesDirectory)/PowerShell' + Set-Location $psRoot -Verbose + } + + $version = Get-Content ./global.json | ConvertFrom-Json | Select-Object -ExpandProperty sdk | Select-Object -ExpandProperty version + + Write-Verbose -Verbose "Installing .NET SDK with version $version" + + Import-Module ./build.psm1 -Force + Install-Dotnet -Version $version -Verbose + + displayName: 'Install dotnet SDK' + workingDirectory: $(RepoRoot) + env: + ob_restore_phase: true + diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index a9f4833cc1d..02839c7d650 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -87,6 +87,8 @@ jobs: env: ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + - template: /.pipelines/templates/install-dotnet.yml@self + - pwsh: | $packageType = '$(PackageType)' Write-Verbose -Verbose "packageType = $packageType" @@ -103,7 +105,7 @@ jobs: Import-Module "$repoRoot/build.psm1" Import-Module "$repoRoot/tools/packaging" - Start-PSBootstrap -Scenario Package + Start-PSBootstrap -Scenario Both $psOptionsPath = "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/${unsignedDrop}/psoptions/psoptions.json" diff --git a/.pipelines/templates/linux.yml b/.pipelines/templates/linux.yml index ccfac3fbc8e..cbf63c84b48 100644 --- a/.pipelines/templates/linux.yml +++ b/.pipelines/templates/linux.yml @@ -62,12 +62,7 @@ jobs: AnalyzeInPipeline: true Language: csharp - - task: UseDotNet@2 - inputs: - useGlobalJson: true - workingDirectory: $(PowerShellRoot) - env: - ob_restore_phase: true + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | $runtime = $env:RUNTIME diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index b08becedc22..ff4787b9bcf 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -39,12 +39,8 @@ jobs: sudo chown $env:USER "$(Agent.TempDirectory)/PowerShell" displayName: 'Create $(Agent.TempDirectory)/PowerShell' - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(PowerShellRoot) + ## We cross compile for arm64, so the arch is always x64 + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | Import-Module $(PowerShellRoot)/build.psm1 -Force diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index d7837c5c3dc..175c847944a 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -94,15 +94,7 @@ jobs: parameters: repoRoot: $(PowerShellRoot) - - task: NuGetToolInstaller@1 - displayName: 'Install NuGet.exe' - - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: '$(PowerShellRoot)' + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | Set-Location -Path '$(PowerShellRoot)' diff --git a/.pipelines/templates/release-validate-fxdpackages.yml b/.pipelines/templates/release-validate-fxdpackages.yml index 53657e6414a..191db42d743 100644 --- a/.pipelines/templates/release-validate-fxdpackages.yml +++ b/.pipelines/templates/release-validate-fxdpackages.yml @@ -61,12 +61,7 @@ jobs: Get-ChildItem "$(Pipeline.Workspace)/PSPackagesOfficial/$artifactName" -Recurse displayName: 'Capture Downloaded Artifacts' - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(Build.SourcesDirectory)/PowerShell" + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | $artifactName = '$(artifactName)' diff --git a/.pipelines/templates/release-validate-globaltools.yml b/.pipelines/templates/release-validate-globaltools.yml index 3c88a278791..11e124e33d6 100644 --- a/.pipelines/templates/release-validate-globaltools.yml +++ b/.pipelines/templates/release-validate-globaltools.yml @@ -38,12 +38,7 @@ jobs: Get-ChildItem "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" -Recurse displayName: 'Capture Downloaded Artifacts' - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(REPOROOT) + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | $repoRoot = "$(Build.SourcesDirectory)/PowerShell" diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index d879ab7f06e..3e58101f7e3 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -46,12 +46,7 @@ jobs: Get-ChildItem "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" -Recurse displayName: 'Capture Downloaded Artifacts' - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(REPOROOT) + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | $repoRoot = "$(Build.SourcesDirectory)" diff --git a/.pipelines/templates/testartifacts.yml b/.pipelines/templates/testartifacts.yml index 240ceae80f7..751c9d5a53b 100644 --- a/.pipelines/templates/testartifacts.yml +++ b/.pipelines/templates/testartifacts.yml @@ -25,19 +25,16 @@ jobs: env: ob_restore_phase: true + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self parameters: - repoRoot: $(Build.SourcesDirectory)/PowerShell + repoRoot: $(RepoRoot) ob_restore_phase: true - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(Build.SourcesDirectory)/PowerShell" - env: - ob_restore_phase: true + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | New-Item -Path '$(ob_outputDirectory)' -ItemType Directory -Force @@ -93,19 +90,16 @@ jobs: env: ob_restore_phase: true + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self parameters: repoRoot: $(Build.SourcesDirectory)/PowerShell ob_restore_phase: true - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(Build.SourcesDirectory)/PowerShell" - env: - ob_restore_phase: true + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | New-Item -Path '$(ob_outputDirectory)' -ItemType Directory -Force diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index 1f732a0145c..b3c72a51b33 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -63,12 +63,7 @@ jobs: AnalyzeInPipeline: true Language: csharp - - task: UseDotNet@2 - inputs: - useGlobalJson: true - workingDirectory: $(PowerShellRoot) - env: - ob_restore_phase: true + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | $runtime = switch ($env:Architecture) @@ -142,6 +137,7 @@ jobs: } Import-Module -Name $(PowerShellRoot)/build.psm1 -Force + Find-Dotnet ## Build global tool Write-Verbose -Message "Building PowerShell global tool for Windows.x64" -Verbose @@ -237,6 +233,9 @@ jobs: After that, we repack using Compress-Archive and rename it back to a nupkg. #> + Import-Module -Name $(PowerShellRoot)/build.psm1 -Force + Find-Dotnet + $packagingStrings = Import-PowerShellDataFile "$(PowerShellRoot)\tools\packaging\packaging.strings.psd1" $outputPath = Join-Path '$(ob_outputDirectory)' 'globaltool' diff --git a/.pipelines/templates/windows-package-build.yml b/.pipelines/templates/windows-package-build.yml index 08dd15fc79f..50309c5099b 100644 --- a/.pipelines/templates/windows-package-build.yml +++ b/.pipelines/templates/windows-package-build.yml @@ -78,12 +78,7 @@ jobs: env: ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - - task: UseDotNet@2 - inputs: - useGlobalJson: true - workingDirectory: $(REPOROOT) - env: - ob_restore_phase: true + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | $msixUrl = '$(makeappUrl)' @@ -112,7 +107,9 @@ jobs: Import-Module "$repoRoot\build.psm1" Import-Module "$repoRoot\tools\packaging" - Start-PSBootstrap -Scenario Package + Start-PSBootstrap -Scenario Both + + Find-Dotnet $signedFilesPath, $psoptionsFilePath = if ($env:RUNTIME -eq 'minsize') { "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_x64_${runtime}\$signedFolder" diff --git a/build.psm1 b/build.psm1 index fe7eff67b2f..aa49b6061c3 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2081,8 +2081,8 @@ function Install-Dotnet { # Note that when it is null, Invoke-Expression (but not &) must be used to interpolate properly $sudo = if (!$NoSudo) { "sudo" } - # $installObtainUrl = "https://dot.net/v1" - $installObtainUrl = "https://dotnet.microsoft.com/download/dotnet/scripts/v1" + $installObtainUrl = "https://builds.dotnet.microsoft.com/dotnet/scripts/v1" + #$installObtainUrl = "https://dotnet.microsoft.com/download/dotnet/scripts/v1" $uninstallObtainUrl = "https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain" # Install for Linux and OS X @@ -2173,7 +2173,6 @@ function Install-Dotnet { $installArgs += @{ SkipNonVersionedFiles = $true } $installArgs | Out-String | Write-Verbose -Verbose - & ./$installScript @installArgs } else { From 559291f9d0fd4a1c7e76fe56aac0c8cdabda8eea Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 9 Oct 2025 15:57:12 -0700 Subject: [PATCH 164/275] [release/v7.5] add CodeQL suppressions for UpdatableHelp and NativeCommandProcessor methods (#26171) --- .../engine/NativeCommandProcessor.cs | 2 ++ src/System.Management.Automation/help/UpdatableHelpSystem.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 43113d07425..12186f241ea 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -658,6 +658,8 @@ private void InitNativeProcess() { startInfo.ArgumentList.RemoveAt(0); } + + // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified on the user's system to retrieve process info for, and in the case of remoting, restricted remoting security guidelines should be used. startInfo.FileName = oldFileName; } } diff --git a/src/System.Management.Automation/help/UpdatableHelpSystem.cs b/src/System.Management.Automation/help/UpdatableHelpSystem.cs index 6ab8d469a97..14edabf9613 100644 --- a/src/System.Management.Automation/help/UpdatableHelpSystem.cs +++ b/src/System.Management.Automation/help/UpdatableHelpSystem.cs @@ -419,6 +419,7 @@ private string ResolveUri(string baseUri, bool verbose) using (HttpClient client = new HttpClient(handler)) { client.Timeout = new TimeSpan(0, 0, 30); // Set 30 second timeout + // codeql[cs/ssrf] - This is expected Poweshell behavior and the user assumes trust for the module they download and any URIs it references. The URIs are also not executables or scripts that would be invoked by this method. Task responseMessage = client.GetAsync(uri); using (HttpResponseMessage response = responseMessage.Result) { @@ -783,6 +784,7 @@ private bool DownloadHelpContentHttpClient(string uri, string fileName, Updatabl using (HttpClient client = new HttpClient(handler)) { client.Timeout = _defaultTimeout; + // codeql[cs/ssrf] - This is expected Poweshell behavior and the user assumes trust for the module they download and any URIs it references. The URIs are also not executables or scripts that would be invoked by this method. Task responseMsg = client.GetAsync(new Uri(uri), _cancelTokenSource.Token); // TODO: Should I use a continuation to write the stream to a file? From cf33058c466e0f35cf9f85e2f808d23393c4873b Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 9 Oct 2025 15:57:42 -0700 Subject: [PATCH 165/275] [release/v7.5] add CodeQL suppresion for NativeCommandProcessor (#26173) --- .../engine/NativeCommandProcessor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 12186f241ea..f1fd575609e 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -1468,6 +1468,7 @@ private ProcessStartInfo GetProcessStartInfo( { using (ParameterBinderBase.bindingTracer.TraceScope("BIND argument [{0}]", NativeParameterBinderController.Arguments)) { + // codeql[cs/microsoft/command-line-injection ] - This is intended PowerShell behavior as NativeParameterBinderController.Arguments is what the native parameter binder generates based on the user input when invoking the command and cannot be injected externally. startInfo.Arguments = NativeParameterBinderController.Arguments; } } From 423fd1978f76e73188a31fb921f93830f380ef81 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 14 Oct 2025 18:18:27 -0700 Subject: [PATCH 166/275] [release/v7.5] Mark the 3 consistently failing tests as pending to unblock PRs (#26196) --- test/powershell/Host/ConsoleHost.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Host/ConsoleHost.Tests.ps1 b/test/powershell/Host/ConsoleHost.Tests.ps1 index 9a546302906..f3b25e00dcf 100644 --- a/test/powershell/Host/ConsoleHost.Tests.ps1 +++ b/test/powershell/Host/ConsoleHost.Tests.ps1 @@ -1000,7 +1000,7 @@ public enum ShowWindowCommands : int $global:PSDefaultParameterValues = $defaultParamValues } - It "-WindowStyle should work on Windows" -TestCases @( + It "-WindowStyle should work on Windows" -Pending -TestCases @( @{WindowStyle="Normal"}, @{WindowStyle="Minimized"}, @{WindowStyle="Maximized"} # hidden doesn't work in CI/Server Core From 083f2caf9f2e52b78db15aad8ae6b332abe4b7af Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 14 Oct 2025 18:47:49 -0700 Subject: [PATCH 167/275] [release/v7.5] Update branch for release (#26195) --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 8 +- ...soft.PowerShell.Commands.Management.csproj | 4 +- ...crosoft.PowerShell.Commands.Utility.csproj | 6 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 98 ++++++++-------- .../Microsoft.WSMan.Management.csproj | 4 +- .../System.Management.Automation.csproj | 26 ++--- .../BenchmarkDotNet.Extensions.csproj | 5 +- .../dotnet-tools/Reporting/Reporting.csproj | 2 +- .../ResultsComparer/ResultsComparer.csproj | 7 +- ...soft.PowerShell.NamedPipeConnection.csproj | 27 ++--- .../nested/Test.Isolated.Nested.csproj | 2 +- test/tools/TestService/TestService.csproj | 94 +++++++-------- test/tools/WebListener/WebListener.csproj | 7 +- tools/cgmanifest.json | 108 +++++++++--------- 17 files changed, 204 insertions(+), 200 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index eb802bfec36..6f09eb2d6ed 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "9.0.304", + "sdkImageVersion": "9.0.306", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 4c6e2601f69..345f67e389e 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.304" + "version": "9.0.306" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 0b8a4c35cfc..00eac01d55c 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,11 +7,11 @@ - - - + + + - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index d9f8e52e762..d992c2eab25 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 3e270da4164..1bb01e109e2 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -13,7 +13,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + @@ -41,8 +41,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index a02a0637693..04df0482c35 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index e951707c28b..bd6c95cedd0 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -17,55 +17,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index c820e3f235b..6195d3a80e1 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,11 +7,11 @@ - + - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index f3b62eafb49..c04785cacf3 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -28,29 +28,29 @@ - + - - - - - - + + + + + + - + - - - - + + + + - + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 9b5fb753394..564f890365b 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -13,11 +13,12 @@ - + + - + diff --git a/test/perf/dotnet-tools/Reporting/Reporting.csproj b/test/perf/dotnet-tools/Reporting/Reporting.csproj index 693cc1b6481..e15b95fc853 100644 --- a/test/perf/dotnet-tools/Reporting/Reporting.csproj +++ b/test/perf/dotnet-tools/Reporting/Reporting.csproj @@ -7,7 +7,7 @@ - + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 3eacb22eb51..a8e05fbbb96 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -13,12 +13,13 @@ - - + + + - + diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index 7fa3f53c83d..bcd8e6011df 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -17,21 +17,22 @@ - + - - - - - - - + + + + + + + + - - - - - + + + + + diff --git a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj index 200b284b31a..a3c17907b03 100644 --- a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj +++ b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj @@ -20,7 +20,7 @@ - + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 5508aa6cd9b..7a3d777f431 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,56 +15,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index c65c90a3ff7..b8f1899736a 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,9 +7,10 @@ - - + + + - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index 9b00c6ac230..dd6bf54f46d 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -115,7 +116,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "8.0.19" + "Version": "8.0.21" } }, "DevelopmentDependency": false @@ -155,7 +156,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -165,7 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -175,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -185,7 +186,7 @@ "Type": "nuget", "Nuget": { "Name": "Newtonsoft.Json", - "Version": "13.0.3" + "Version": "13.0.4" } }, "DevelopmentDependency": false @@ -195,7 +196,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -205,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -215,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -225,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -235,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -245,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -255,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -265,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -275,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -285,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -295,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -305,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -315,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -325,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -345,7 +346,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -355,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -365,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -425,7 +426,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -445,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -455,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -465,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -475,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -485,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -505,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.DiagnosticSource", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -515,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -525,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -535,7 +536,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -545,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -555,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -565,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -575,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -585,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -595,7 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -605,7 +606,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -635,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -665,7 +666,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -685,7 +686,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -695,7 +696,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -705,7 +706,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -715,7 +716,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -785,7 +786,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -795,7 +796,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -805,7 +806,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -815,7 +816,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encoding.CodePages", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -825,7 +826,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encodings.Web", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -835,7 +836,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -855,11 +856,10 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.8" + "Version": "9.0.10" } }, "DevelopmentDependency": false } - ], - "$schema": "https://json.schemastore.org/component-detection-manifest.json" + ] } From 83c94d32ca99606817ccac00e727a8d9e518506f Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 16 Oct 2025 13:37:00 -0700 Subject: [PATCH 168/275] [release/v7.5] Update vPack name (#26221) --- .pipelines/PowerShell-vPack-Official.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index f110ff0366a..3b151127cb1 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -11,8 +11,9 @@ parameters: # parameters are shown up in ADO UI in a build queue time - name: vPackName type: string displayName: 'VPack Name:' - default: 'PowerShell' + default: 'PowerShell.BuildTool' values: + - PowerShell.BuildTool - PowerShell - PowerShellDoNotUse - name: 'ReleaseTagVar' From ce09a42fc8f7a3ff1bc35cd86a437f79bbfb8433 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 5 Nov 2025 10:53:59 -0800 Subject: [PATCH 169/275] [release/v7.5] Github Workflow cleanup (#26389) --- .github/workflows/AssignPrs.yml | 30 -------------- .github/workflows/createReminders.yml | 21 ---------- .github/workflows/markdownLink.yml | 52 ------------------------- .github/workflows/markdownLinkDaily.yml | 33 ---------------- .github/workflows/processReminders.yml | 21 ---------- tools/download.sh | 4 +- tools/install-powershell.sh | 6 ++- 7 files changed, 7 insertions(+), 160 deletions(-) delete mode 100644 .github/workflows/AssignPrs.yml delete mode 100644 .github/workflows/createReminders.yml delete mode 100644 .github/workflows/markdownLink.yml delete mode 100644 .github/workflows/markdownLinkDaily.yml delete mode 100644 .github/workflows/processReminders.yml diff --git a/.github/workflows/AssignPrs.yml b/.github/workflows/AssignPrs.yml deleted file mode 100644 index a01c0bb0950..00000000000 --- a/.github/workflows/AssignPrs.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Auto Assign PR Maintainer -on: - issues: - types: [opened, edited] -permissions: - contents: read - -jobs: - run: - if: github.repository_owner == 'PowerShell' - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - steps: - - uses: wow-actions/auto-assign@67fafa03df61d7e5f201734a2fa60d1ab111880d # v3.0.2 - if: github.event.issue.pull_request - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # using the `org/team_slug` or `/team_slug` syntax to add git team as reviewers - assignees: | - TravisEz13 - daxian-dbw - adityapatwardhan - iSazonov - SeeminglyScience - skipDraft: true - skipKeywords: wip, draft - addReviewers: false - numberOfAssignees: 1 diff --git a/.github/workflows/createReminders.yml b/.github/workflows/createReminders.yml deleted file mode 100644 index 0333b635d59..00000000000 --- a/.github/workflows/createReminders.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: 'Create reminder' - -on: - issue_comment: - types: [created, edited] - -permissions: - contents: read - -jobs: - reminder: - if: github.repository_owner == 'PowerShell' - - permissions: - issues: write # for agrc/create-reminder-action to set reminders on issues - pull-requests: write # for agrc/create-reminder-action to set reminders on PRs - runs-on: ubuntu-latest - - steps: - - name: check for reminder - uses: agrc/create-reminder-action@ffa4363460fe5fff73b2b58e66fa7eb01f7465a0 # v1.1.15 diff --git a/.github/workflows/markdownLink.yml b/.github/workflows/markdownLink.yml deleted file mode 100644 index 85b9f51a742..00000000000 --- a/.github/workflows/markdownLink.yml +++ /dev/null @@ -1,52 +0,0 @@ -on: - pull_request: - branches: - - master - - 'release/**' - -name: Check modified markdown files -permissions: - contents: read - -jobs: - markdown-link-check: - runs-on: ubuntu-latest - if: github.repository_owner == 'PowerShell' - - steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1 - with: - use-quiet-mode: 'yes' - use-verbose-mode: 'yes' - check-modified-files-only: 'yes' - config-file: .github/workflows/markdown-link/config.json - markdown-lint: - permissions: - contents: read - packages: read - statuses: write - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - with: - # Full git history is needed to get a proper - # list of changed files within `super-linter` - fetch-depth: 0 - - name: Load super-linter configuration - # Use grep inverse matching to exclude eventual comments in the .env file - # because the GitHub Actions command to set environment variables doesn't - # support comments. - # Ref: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-environment-variable - run: grep -v '^#' tools/super-linter/config/super-linter.env >> "$GITHUB_ENV" - - name: Lint Markdown - uses: super-linter/super-linter@b4515bd4ad9d0aa4681960e053916ab991bdbe96 # v6.8.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Super-Linter correction instructions - if: failure() - uses: actions/github-script@v7.0.1 - with: - script: | - const message = "Super-Linter found issues in the changed files. Please check the logs for details. You can run the linter locally using the command: `./tools/super-lister/super-lister.ps1`."; - core.setFailed(message); diff --git a/.github/workflows/markdownLinkDaily.yml b/.github/workflows/markdownLinkDaily.yml deleted file mode 100644 index 7434bfd852b..00000000000 --- a/.github/workflows/markdownLinkDaily.yml +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT license. - -name: PowerShell Daily Markdown Link Verification - -on: - workflow_dispatch: - schedule: - # At 13:00 UTC every day. - - cron: '0 13 * * *' - -permissions: - contents: read - -jobs: - markdown-link-check: - runs-on: ubuntu-latest - if: github.repository == 'PowerShell/PowerShell' - steps: - - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - name: Check Links - uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1 - with: - use-quiet-mode: 'yes' - use-verbose-mode: 'yes' - config-file: .github/workflows/markdown-link/config.json - - name: Microsoft Teams Notifier - uses: skitionek/notify-microsoft-teams@77cc88b484449e2318245a54c115c5dca0eae4ef # master - if: failure() - with: - webhook_url: ${{ secrets.PS_BUILD_TEAMS_CHANNEL }} - overwrite: "{title: `Failure in .github/markdownLinkDaily.yml validating links. Look at ${workflow_link}`}" diff --git a/.github/workflows/processReminders.yml b/.github/workflows/processReminders.yml deleted file mode 100644 index a2d5b4dbd93..00000000000 --- a/.github/workflows/processReminders.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: 'Process reminders' - -on: - schedule: - - cron: '*/15 * * * *' - workflow_dispatch: - -permissions: - contents: read - -jobs: - reminder: - if: github.repository_owner == 'PowerShell' - permissions: - issues: write # for agrc/reminder-action to set reminders on issues - pull-requests: write # for agrc/reminder-action to set reminders on PRs - runs-on: ubuntu-latest - - steps: - - name: check reminders and notify - uses: agrc/reminder-action@b5cc06580b6a711baddf6a947131f85a422fa263 # v1.0.14 diff --git a/tools/download.sh b/tools/download.sh index 6a6c6436b4b..f1e8c42cdc3 100644 --- a/tools/download.sh +++ b/tools/download.sh @@ -1 +1,3 @@ -bash <(curl -s https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.sh) +# Pin to specific commit for security (OpenSSF Scorecard requirement) +# Pinned commit: 26bb188c8 - "Improve ValidateLength error message consistency and refactor validation tests" (2025-10-12) +bash <(curl -s https://raw.githubusercontent.com/PowerShell/PowerShell/26bb188c8be0cda6cb548ce1a12840ebf67e1331/tools/install-powershell.sh) diff --git a/tools/install-powershell.sh b/tools/install-powershell.sh index 128f5664483..91425c183a8 100755 --- a/tools/install-powershell.sh +++ b/tools/install-powershell.sh @@ -26,7 +26,9 @@ install(){ #gitrepo paths are overrideable to run from your own fork or branch for testing or private distribution local VERSION="1.2.0" - local gitreposubpath="PowerShell/PowerShell/master" + # Pin to specific commit for security (OpenSSF Scorecard requirement) + # Pinned commit: 26bb188c8 - "Improve ValidateLength error message consistency and refactor validation tests" (2025-10-12) + local gitreposubpath="PowerShell/PowerShell/26bb188c8be0cda6cb548ce1a12840ebf67e1331" local gitreposcriptroot="https://raw.githubusercontent.com/$gitreposubpath/tools" local gitscriptname="install-powershell.psh" @@ -125,7 +127,7 @@ install(){ if [[ $osname = *SUSE* ]]; then DistroBasedOn='suse' REV=$(source /etc/os-release; echo $VERSION_ID) - fi + fi OS=$(lowercase $OS) DistroBasedOn=$(lowercase $DistroBasedOn) fi From 053db9864eec7c1b99fe3892f12c3c1594b87cc0 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 5 Nov 2025 11:36:21 -0800 Subject: [PATCH 170/275] [release/v7.5] Integrate Windows packaging into windows-ci workflow using reusable workflow (#26390) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .../infrastructure/path-filters/action.yml | 17 ++++ .github/workflows/windows-ci.yml | 10 +++ .../workflows/windows-packaging-reusable.yml | 88 +++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 .github/workflows/windows-packaging-reusable.yml diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml index 78426bdff03..fd48e8091d6 100644 --- a/.github/actions/infrastructure/path-filters/action.yml +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -26,6 +26,9 @@ outputs: buildModuleChanged: description: 'Build module changes' value: ${{ steps.filter.outputs.buildModuleChanged }} + packagingChanged: + description: 'Packaging related changes' + value: ${{ steps.filter.outputs.packagingChanged }} runs: using: composite steps: @@ -83,6 +86,18 @@ runs: const buildModuleChanged = files.some(file => file.filename.startsWith('build.psm1')); + const packagingChanged = files.some(file => + file.filename === '.github/workflows/windows-ci.yml' || + file.filename.startsWith('assets/wix/') || + file.filename === 'PowerShell.Common.props' || + file.filename.match(/^src\/.*\.csproj$/) || + file.filename.startsWith('test/packaging/windows/') || + file.filename.startsWith('tools/packaging/') || + file.filename.startsWith('tools/wix/') + ) || + buildModuleChanged || + toolsCiPsm1Changed; + const source = mainSourceChanged || toolsChanged || githubChanged || propsChanged || testsChanged; core.setOutput('toolsChanged', toolsChanged); @@ -91,6 +106,7 @@ runs: core.setOutput('testsChanged', testsChanged); core.setOutput('mainSourceChanged', mainSourceChanged); core.setOutput('buildModuleChanged', buildModuleChanged); + core.setOutput('packagingChanged', packagingChanged); core.setOutput('source', source); - name: Capture outputs @@ -102,4 +118,5 @@ runs: Write-Verbose -Verbose "tests: ${{ steps.filter.outputs.testsChanged }}" Write-Verbose -Verbose "mainSource: ${{ steps.filter.outputs.mainSourceChanged }}" Write-Verbose -Verbose "buildModule: ${{ steps.filter.outputs.buildModuleChanged }}" + Write-Verbose -Verbose "packaging: ${{ steps.filter.outputs.packagingChanged }}" shell: pwsh diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 2e392987cb0..e960c0c255f 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -39,6 +39,8 @@ env: POWERSHELL_TELEMETRY_OPTOUT: 1 __SuppressAnsiEscapeSequences: 1 nugetMultiFeedWarnLevel: none + SYSTEM_ARTIFACTSDIRECTORY: ${{ github.workspace }}/artifacts + BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts jobs: changes: name: Change Detection @@ -52,6 +54,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout uses: actions/checkout@v4.1.0 @@ -156,6 +159,12 @@ jobs: fetch-depth: 1000 - name: Verify xUnit test results uses: "./.github/actions/test/verify_xunit" + windows_packaging: + name: Windows Packaging + needs: + - changes + if: ${{ needs.changes.outputs.packagingChanged == 'true' }} + uses: ./.github/workflows/windows-packaging-reusable.yml ready_to_merge: name: windows ready to merge needs: @@ -164,6 +173,7 @@ jobs: - windows_test_elevated_others - windows_test_unelevated_ci - windows_test_unelevated_others + - windows_packaging if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml new file mode 100644 index 00000000000..5a763544c62 --- /dev/null +++ b/.github/workflows/windows-packaging-reusable.yml @@ -0,0 +1,88 @@ +name: Windows Packaging (Reusable) + +on: + workflow_call: + +env: + GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + DOTNET_NOLOGO: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + SYSTEM_ARTIFACTSDIRECTORY: ${{ github.workspace }}/artifacts + BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts + +jobs: + package: + name: ${{ matrix.architecture }} - ${{ matrix.channel }} + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + include: + - architecture: x64 + channel: preview + runtimePrefix: win7 + - architecture: x86 + channel: stable + runtimePrefix: win7 + - architecture: x86 + channel: preview + runtimePrefix: win7 + - architecture: arm64 + channel: preview + runtimePrefix: win + + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 1000 + + - name: Capture Environment + if: success() || failure() + run: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + shell: pwsh + + - name: Capture PowerShell Version Table + if: success() || failure() + run: | + $PSVersionTable + shell: pwsh + + - name: Switch to Public Feeds + if: success() + run: | + Import-Module .\tools\ci.psm1 + Switch-PSNugetConfig -Source Public + shell: pwsh + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + if: success() + run: | + Import-Module .\tools\ci.psm1 + Invoke-CIInstall -SkipUser + shell: pwsh + + - name: Build and Package + run: | + Import-Module .\tools\ci.psm1 + New-CodeCoverageAndTestPackage + Invoke-CIFinish -Runtime ${{ matrix.runtimePrefix }}-${{ matrix.architecture }} -channel ${{ matrix.channel }} + shell: pwsh + + - name: Upload Build Artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: windows-packaging-${{ matrix.architecture }}-${{ matrix.channel }} + path: | + ${{ github.workspace }}/artifacts/**/* + !${{ github.workspace }}/artifacts/**/*.pdb From dcf85e02004377c11d1a867826d96f03f4c1eb87 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 5 Nov 2025 11:40:42 -0800 Subject: [PATCH 171/275] [release/v7.5] Convert Azure DevOps Linux Packaging pipeline to GitHub Actions workflow (#26391) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .../actions/test/linux-packaging/action.yml | 112 +++++++++--------- .github/workflows/linux-ci.yml | 32 +++-- build.psm1 | 2 +- 3 files changed, 73 insertions(+), 73 deletions(-) diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index b4a9c3b55c0..736bddfa7a7 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -1,12 +1,5 @@ name: linux_packaging -description: 'Test very basic Linux packaging' - -# This isn't working yet -# It fails with - -# ERROR: While executing gem ... (Gem::FilePermissionError) -# You don't have write permissions for the /var/lib/gems/2.7.0 directory. -# WARNING: Installation of gem dotenv 2.8.1 failed! Must resolve manually. +description: 'Linux packaging for PowerShell' runs: using: composite @@ -15,58 +8,64 @@ runs: if: success() || failure() run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' shell: pwsh + + - uses: actions/setup-dotnet@v5 + with: + global-json-file: ./global.json + - name: Download Build Artifacts uses: actions/download-artifact@v4 with: - path: "${{ github.workspace }}" + name: build + path: "${{ runner.workspace }}/build" + - name: Capture Artifacts Directory continue-on-error: true - run: Get-ChildItem "${{ github.workspace }}/build/*" -Recurse + run: Get-ChildItem "${{ runner.workspace }}/build/*" -Recurse shell: pwsh - name: Bootstrap run: |- Import-Module ./build.psm1 Start-PSBootstrap -Scenario Package + Write-Verbose -Verbose "Start Sync-PSTags" + Sync-PSTags -AddRemoteIfMissing + Write-Verbose -Verbose "End Sync-PSTags" shell: pwsh - - name: Capture Artifacts Directory - continue-on-error: true - run: Import-Module ./build.psm1 + + - name: Extract Build ZIP + run: |- + $destinationFolder = "${{ runner.workspace }}/bins" + $archiveFile = "${{ runner.workspace }}/build/build.zip" + + Write-Verbose "Extracting $archiveFile to $destinationFolder" -Verbose + New-Item -ItemType Directory -Path $destinationFolder -Force | Out-Null + Expand-Archive -Path $archiveFile -DestinationPath $destinationFolder -Force shell: pwsh - - name: Extract Files - uses: actions/github-script@v7.0.0 - env: - DESTINATION_FOLDER: "${{ github.workspace }}/bins" - ARCHIVE_FILE_PATTERNS: "${{ github.workspace }}/build/build.zip" - with: - script: |- - const fs = require('fs').promises - const path = require('path') - const target = path.resolve(process.env.DESTINATION_FOLDER) - const patterns = process.env.ARCHIVE_FILE_PATTERNS - const globber = await glob.create(patterns) - await io.mkdirP(path.dirname(target)) - for await (const file of globber.globGenerator()) { - if ((await fs.lstat(file)).isDirectory()) continue - await exec.exec(`7z x ${file} -o${target} -aoa`) - } + - name: Fix permissions continue-on-error: true run: |- - find "${{ github.workspace }}/bins" -type d -exec chmod +rwx {} \; - find "${{ github.workspace }}/bins" -type f -exec chmod +rw {} \; + find "${{ runner.workspace }}/bins" -type d -exec chmod +rwx {} \; + find "${{ runner.workspace }}/bins" -type f -exec chmod +rw {} \; shell: bash + - name: Capture Extracted Build ZIP continue-on-error: true - run: Get-ChildItem "${{ github.workspace }}/bins/*" -Recurse -ErrorAction SilentlyContinue + run: Get-ChildItem "${{ runner.workspace }}/bins/*" -Recurse -ErrorAction SilentlyContinue shell: pwsh - - name: Packaging Tests - if: success() + + - name: Create Packages + env: + BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ runner.workspace }}/packages run: |- + # Create the artifacts staging directory + New-Item -ItemType Directory -Path "$env:BUILD_ARTIFACTSTAGINGDIRECTORY" -Force | Out-Null + Import-Module ./tools/ci.psm1 - Restore-PSOptions -PSOptionsPath '${{ github.workspace }}/build/psoptions.json' + Restore-PSOptions -PSOptionsPath '${{ runner.workspace }}/build/psoptions.json' $options = (Get-PSOptions) - $rootPath = '${{ github.workspace }}/bins' + $rootPath = '${{ runner.workspace }}/bins' $originalRootPath = Split-Path -path $options.Output $path = Join-Path -path $rootPath -ChildPath (split-path -leaf -path $originalRootPath) $pwshPath = Join-Path -path $path -ChildPath 'pwsh' @@ -75,21 +74,24 @@ runs: Set-PSOptions $options Invoke-CIFinish shell: pwsh - - name: Upload packages - run: |- - Get-ChildItem "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}/*.deb" -Recurse | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=deb;artifactname=deb]$packagePath" - } - Get-ChildItem "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}/*.rpm" -Recurse | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=rpm;artifactname=rpm]$packagePath" - } - Get-ChildItem "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}/*.tar.gz" -Recurse | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=rpm;artifactname=rpm]$packagePath" - } - shell: pwsh + + - name: Upload deb packages + uses: actions/upload-artifact@v4 + with: + name: packages-deb + path: ${{ runner.workspace }}/packages/*.deb + if-no-files-found: ignore + + - name: Upload rpm packages + uses: actions/upload-artifact@v4 + with: + name: packages-rpm + path: ${{ runner.workspace }}/packages/*.rpm + if-no-files-found: ignore + + - name: Upload tar.gz packages + uses: actions/upload-artifact@v4 + with: + name: packages-tar + path: ${{ runner.workspace }}/packages/*.tar.gz + if-no-files-found: ignore diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 2bf61ca3e48..6cf1e4c67b3 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -227,24 +227,22 @@ jobs: - linux_test_unelevated_ci - linux_test_unelevated_others - analyze + - linux_packaging if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: needs_context: ${{ toJson(needs) }} - # TODO: Enable this when we have a Linux packaging workflow - - # ERROR: While executing gem ... (Gem::FilePermissionError) - # You don't have write permissions for the /var/lib/gems/2.7.0 directory. - # WARNING: Installation of gem dotenv 2.8.1 failed! Must resolve manually. - - # linux_packaging: - # name: Attempt Linux Packaging - # needs: ci_build - # runs-on: ubuntu-20.04 - # steps: - # - name: checkout - # uses: actions/checkout@v4.1.0 - # with: - # fetch-depth: 1000 - # - name: Verify xUnit test results - # uses: "./.github/actions/test/linux-packaging" + linux_packaging: + name: Linux Packaging + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Linux Packaging + uses: "./.github/actions/test/linux-packaging" diff --git a/build.psm1 b/build.psm1 index aa49b6061c3..45705e53fa6 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2241,7 +2241,7 @@ function Install-GlobalGem { # We cannot guess if the user wants to run gem install as root on linux and windows, # but macOs usually requires sudo $gemsudo = '' - if($environment.IsMacOS -or $env:TF_BUILD) { + if($environment.IsMacOS -or $env:TF_BUILD -or $env:GITHUB_ACTIONS) { $gemsudo = $sudo } From 9e56e70e67fa9c463131af7500c1798359cc97a7 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 5 Nov 2025 13:21:22 -0800 Subject: [PATCH 172/275] [release/v7.5] Add network isolation policy parameter to vPack pipeline (#26393) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .pipelines/PowerShell-vPack-Official.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 3b151127cb1..7ba92f4eda9 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -24,6 +24,14 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: 'Enable debug output' type: boolean default: false +- name: netiso + displayName: "Network Isolation Policy" + type: string + values: + - KS4 + - R1 + - Netlock + default: "R1" name: vPack_$(Build.SourceBranchName)_Prod.${{ parameters.OfficialBuild }}_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) @@ -54,6 +62,8 @@ variables: value: ${{ iif ( parameters.OfficialBuild, 'v2/Microsoft.Official.yml@onebranchTemplates', 'v2/Microsoft.NonOfficial.yml@onebranchTemplates' ) }} - group: DotNetPrivateBuildAccess - group: certificate_logical_to_actual + - name: netiso + value: ${{ parameters.netiso }} # We shouldn't be using PATs anymore # - group: mscodehub-feed-read-general @@ -70,6 +80,11 @@ extends: platform: name: 'windows_undocked' # windows undocked + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: ${{ variables.netiso }} + cloudvault: enabled: false From 20b207d4c0211094da814c779dee346993cd288f Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 12 Jan 2026 10:48:25 -0800 Subject: [PATCH 173/275] Update a few packages to use the right version corresponding to .NET 9 (#26671) --- .../Microsoft.PowerShell.Commands.Utility.csproj | 2 +- src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj | 4 ++-- .../PSVersionInfoGenerator/PSVersionInfoGenerator.csproj | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 1bb01e109e2..3edc422be02 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -14,7 +14,7 @@ all - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index bd6c95cedd0..8cb31a949bb 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,8 +16,8 @@ - - + + diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index 9de256a3ba1..7c2fd6a1a2c 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -17,7 +17,7 @@ - - + + From 8d087587c796028e4b9a4c6ea18244628ea53a6b Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:29:58 -0500 Subject: [PATCH 174/275] [release/v7.5] Separate store automation service endpoints and resolve `AppID` (#26266) --- .pipelines/templates/package-create-msix.yml | 26 ++++++++++-- .pipelines/templates/release-MSIX-Publish.yml | 41 +++++++++++++++---- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index b97807a7e85..dedbdf543f9 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -206,14 +206,32 @@ jobs: } Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" - Write-Host "##vso[task.setvariable variable=SBConfigPath]$($config.SBConfigPath)" + Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" + + # These variables are used in the next tasks to determine which ServiceEndpoint to use + Write-Host "##vso[task.setvariable variable=LTS]$($IsLTS.ToString().ToLower())" + Write-Host "##vso[task.setvariable variable=STABLE]$($IsStable.ToString().ToLower())" + Write-Host "##vso[task.setvariable variable=PREVIEW]$($IsPreview.ToString().ToLower())" name: UpdateConfigs displayName: Update PDPs and SBConfig.json - - task: MS-RDX-MRO.windows-store-publish-dev.package-task.store-package@3 - displayName: 'Create StoreBroker Package' + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 + displayName: 'Create StoreBroker Package (Preview)' + condition: eq('$(PREVIEW)', 'true') + inputs: + serviceEndpoint: 'StoreAppPublish-Preview' + sbConfigPath: '$(SBConfigPath)' + sourceFolder: '$(BundleDir)' + contents: '*.msixBundle' + outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' + + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 + displayName: 'Create StoreBroker Package (Stable/LTS)' + condition: or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true')) inputs: - serviceEndpoint: '$(ServiceConnection)' + serviceEndpoint: 'StoreAppPublish-Stable' sbConfigPath: '$(SBConfigPath)' sourceFolder: '$(BundleDir)' contents: '*.msixBundle' diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index 9a0dba8833f..eb51584d9b9 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -47,7 +47,8 @@ jobs: $middleURL = $matches[1] } - $endURL = $tagString -replace '[v\.]','' + + $endURL = $tagString -replace '^v','' -replace '\.','' $message = "Changelog: https://github.com/PowerShell/PowerShell/blob/master/CHANGELOG/$middleURL.md#$endURL" Write-Verbose -Verbose "Release Notes for the Store:" Write-Verbose -Verbose "$message" @@ -81,7 +82,6 @@ jobs: } } - # Determine the current channel $currentChannel = if ($IsLTS) { 'LTS' } elseif ($IsStable) { 'Stable' } elseif ($IsPreview) { 'Preview' } @@ -89,8 +89,20 @@ jobs: Write-Error "No valid channel detected" exit 1 } - - $config = $channelConfigs[$currentChannel] + + # Assign AppID for Store-Publish Task + $appID = $null + if ($IsLTS) { + $appID = '$(AppID-LTS)' + } + elseif ($IsStable) { + $appID = '$(AppID-Stable)' + } + else { + $appID = '$(AppID-Preview)' + } + + Write-Host "##vso[task.setvariable variable=AppID]$appID" Write-Verbose -Verbose "Selected channel: $currentChannel" Write-Verbose -Verbose "App ID: $($config.AppId)" Write-Verbose -Verbose "Service Endpoint: $($config.ServiceEndpoint)" @@ -102,11 +114,24 @@ jobs: displayName: 'Set StoreBroker Configurations' - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 - displayName: 'Publish LTS StoreBroker Package' - condition: ne('${{ parameters.skipMSIXPublish }}', 'true') + displayName: 'Publish StoreBroker Package (Stable/LTS)' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true'))) + inputs: + serviceEndpoint: 'StoreAppPublish-Stable' + appId: '$(AppID)' + inputMethod: JsonAndZip + jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' + zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' + numberOfPackagesToKeep: 2 + jsonZipUpdateMetadata: true + targetPublishMode: 'Immediate' + + - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 + displayName: 'Publish StoreBroker Package (Preview)' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq('$(PREVIEW)', 'true')) inputs: - serviceEndpoint: '$(SelectedServiceEndpoint)' - appId: '$(SelectedAppId)' + serviceEndpoint: 'StoreAppPublish-Preview' + appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' From 8975e1d8d5b826597094c3729bc852e5dd82310c Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 11 Feb 2026 18:46:51 -0500 Subject: [PATCH 175/275] [release/v7.5] Fix path to `metadata.json` in channel selection script (#26400) --- .pipelines/templates/channelSelection.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/channelSelection.yml b/.pipelines/templates/channelSelection.yml index 0e352ef7558..3d1f445c559 100644 --- a/.pipelines/templates/channelSelection.yml +++ b/.pipelines/templates/channelSelection.yml @@ -1,7 +1,7 @@ steps: - pwsh: | # Determine LTS, Preview, or Stable - $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json + $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw | ConvertFrom-Json $LTS = $metadata.LTSRelease.Latest $Stable = $metadata.StableRelease.Latest $isPreview = '$(OutputReleaseTag.releaseTag)' -match '-' From 1b48948275ff2d2c5e40dcd4734d8fed76d5315b Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 11 Feb 2026 19:10:21 -0500 Subject: [PATCH 176/275] [release/v7.5] Fix buildinfo.json uploading for preview, LTS, and stable releases (#26773) --- .../templates/release-upload-buildinfo.yml | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index 1134e1cc016..2f53f99faff 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -58,8 +58,7 @@ jobs: $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) $metadata = Get-Content -LiteralPath "$toolsDirectory/metadata.json" -ErrorAction Stop | ConvertFrom-Json - $stableRelease = $metadata.StableRelease.Latest - $ltsRelease = $metadata.LTSRelease.Latest + $stableReleaseTag = $metadata.StableReleaseTag -Replace 'v','' Write-Verbose -Verbose "Writing $jsonFile contents:" $buildInfoJsonContent = Get-Content $jsonFile -Encoding UTF8NoBom -Raw @@ -67,40 +66,44 @@ jobs: $buildInfo = $buildInfoJsonContent | ConvertFrom-Json $buildInfo.ReleaseDate = $dateTime + $currentReleaseTag = $buildInfo.ReleaseTag -Replace 'v','' $targetFile = "$ENV:PIPELINE_WORKSPACE/$fileName" ConvertTo-Json -InputObject $buildInfo | Out-File $targetFile -Encoding ascii - if ($stableRelease -or $fileName -eq "preview.json") { - Set-BuildVariable -Name CopyMainBuildInfo -Value YES + if ($fileName -eq "preview.json") { + Set-BuildVariable -Name UploadPreview -Value YES } else { - Set-BuildVariable -Name CopyMainBuildInfo -Value NO + Set-BuildVariable -Name UploadPreview -Value NO } - Set-BuildVariable -Name BuildInfoJsonFile -Value $targetFile - - ## Create 'lts.json' if it's the latest stable and also a LTS release. + Set-BuildVariable -Name PreviewBuildInfoFile -Value $targetFile + ## Create 'lts.json' if marked as a LTS release. if ($fileName -eq "stable.json") { + [System.Management.Automation.SemanticVersion] $stableVersion = $stableReleaseTag + [System.Management.Automation.SemanticVersion] $currentVersion = $currentReleaseTag if ($ltsRelease) { $ltsFile = "$ENV:PIPELINE_WORKSPACE/lts.json" Copy-Item -Path $targetFile -Destination $ltsFile -Force - Set-BuildVariable -Name LtsBuildInfoJsonFile -Value $ltsFile - Set-BuildVariable -Name CopyLTSBuildInfo -Value YES + Set-BuildVariable -Name LTSBuildInfoFile -Value $ltsFile + Set-BuildVariable -Name UploadLTS -Value YES } else { - Set-BuildVariable -Name CopyLTSBuildInfo -Value NO + Set-BuildVariable -Name UploadLTS -Value NO } - $releaseTag = $buildInfo.ReleaseTag - $version = $releaseTag -replace '^v' - $semVersion = [System.Management.Automation.SemanticVersion] $version + ## Only update the stable.json if the current version is greater than the stable version. + if ($currentVersion -gt $stableVersion) { + $versionFile = "$ENV:PIPELINE_WORKSPACE/$($currentVersion.Major)-$($currentVersion.Minor).json" + Copy-Item -Path $targetFile -Destination $versionFile -Force + Set-BuildVariable -Name StableBuildInfoFile -Value $versionFile + Set-BuildVariable -Name UploadStable -Value YES + } else { + Set-BuildVariable -Name UploadStable -Value NO + } - $versionFile = "$ENV:PIPELINE_WORKSPACE/$($semVersion.Major)-$($semVersion.Minor).json" - Copy-Item -Path $targetFile -Destination $versionFile -Force - Set-BuildVariable -Name VersionBuildInfoJsonFile -Value $versionFile - Set-BuildVariable -Name CopyVersionBuildInfo -Value YES } else { - Set-BuildVariable -Name CopyVersionBuildInfo -Value NO + Set-BuildVariable -Name UploadStable -Value NO } displayName: Create json files @@ -118,24 +121,27 @@ jobs: $storageContext = New-AzStorageContext -StorageAccountName $storageAccount -UseConnectedAccount - if ($env:CopyMainBuildInfo -eq 'YES') { - $jsonFile = "$env:BuildInfoJsonFile" + #preview + if ($env:UploadPreview -eq 'YES') { + $jsonFile = "$env:PreviewBuildInfoFile" $blobName = Get-Item $jsonFile | Split-Path -Leaf Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - if ($env:CopyLTSBuildInfo -eq 'YES') { - $jsonFile = "$env:LtsBuildInfoJsonFile" + #LTS + if ($env:UploadLTS -eq 'YES') { + $jsonFile = "$env:LTSBuildInfoFile" $blobName = Get-Item $jsonFile | Split-Path -Leaf Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - if ($env:CopyVersionBuildInfo -eq 'YES') { - $jsonFile = "$env:VersionBuildInfoJsonFile" + #stable + if ($env:UploadStable -eq 'YES') { + $jsonFile = "$env:StableBuildInfoFile" $blobName = Get-Item $jsonFile | Split-Path -Leaf Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - condition: and(succeeded(), eq(variables['CopyMainBuildInfo'], 'YES')) + condition: and(succeeded(), or(eq(variables['UploadPreview'], 'YES'), eq(variables['UploadLTS'], 'YES'), eq(variables['UploadStable'], 'YES'))) \ No newline at end of file From d92015e37cc10e391b61055ebbde2bd3e04f681f Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 11 Feb 2026 19:11:31 -0500 Subject: [PATCH 177/275] [release/v7.5] Specify .NET search by build type (#26408) --- PowerShell.Common.props | 21 +++++++++++++++++++++ build.psm1 | 21 ++++++++++++++++----- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/PowerShell.Common.props b/PowerShell.Common.props index 28bc08cc5db..cfaddee74e3 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -176,6 +176,27 @@ portable + + + + EnvironmentVariable;Global + + + + + Global + + + + AppLocal + + true diff --git a/build.psm1 b/build.psm1 index 45705e53fa6..c60bec719f2 100644 --- a/build.psm1 +++ b/build.psm1 @@ -492,13 +492,24 @@ Fix steps: $Arguments += "/property:IsWindows=false" } - # Framework Dependent builds do not support ReadyToRun as it needs a specific runtime to optimize for. - # The property is set in Powershell.Common.props file. - # We override the property through the build command line. - if(($Options.Runtime -like 'fxdependent*' -or $ForMinimalSize) -and $Options.Runtime -notmatch $optimizedFddRegex) { - $Arguments += "/property:PublishReadyToRun=false" + # We pass in the AppDeployment property to indicate which type of deployment we are doing. + # This allows the PowerShell.Common.props to set the correct properties for the build. + $AppDeployment = if(($Options.Runtime -like 'fxdependent*' -or $ForMinimalSize) -and $Options.Runtime -notmatch $optimizedFddRegex) { + # Global and zip files + "FxDependent" + } + elseif($Options.Runtime -like 'fxdependent*' -and $Options.Runtime -match $optimizedFddRegex) { + # These are Optimized and must come from the correct version of the runtime. + # Global + "FxDependentDeployment" + } + else { + # The majority of our packages + # AppLocal + "SelfContained" } + $Arguments += "/property:AppDeployment=$AppDeployment" $Arguments += "--configuration", $Options.Configuration $Arguments += "--framework", $Options.Framework From e697a58c146cae3cc1affca3e3d0e44e338904ec Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 12 Feb 2026 12:41:20 -0500 Subject: [PATCH 178/275] [release/v7.5] Fix up `SSHConnectionInfo` ssh PATH checks (#26165) --- PowerShell.Common.props | 2 +- .../PSVersionInfoGenerator.csproj | 2 +- .../remoting/common/RunspaceConnectionInfo.cs | 44 ++++++++++++++++++- test/Test.Common.props | 2 +- .../ResultsComparer/ResultsComparer.csproj | 2 +- ...soft.PowerShell.NamedPipeConnection.csproj | 2 +- .../WebListener/Controllers/GetController.cs | 4 +- .../Controllers/MultipartController.cs | 2 +- .../Controllers/ResponseHeadersController.cs | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 2 +- .../Microsoft.PowerShell.ConsoleHost.csproj | 2 +- .../System.Management.Automation.csproj | 2 +- 12 files changed, 55 insertions(+), 13 deletions(-) diff --git a/PowerShell.Common.props b/PowerShell.Common.props index cfaddee74e3..7436c42158b 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -145,7 +145,7 @@ PowerShell 7 net9.0 - 11.0 + 13.0 true true diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index 7c2fd6a1a2c..44449ff15bc 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -7,7 +7,7 @@ netstandard2.0 - 11.0 + 13.0 true true RS1035 diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index d18eb249cb7..d9a6d0b317b 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -2206,12 +2206,54 @@ internal int StartSSHProcess( var context = Runspaces.LocalPipeline.GetExecutionContextFromTLS(); if (context != null) { - var cmdInfo = context.CommandDiscovery.LookupCommandInfo(sshCommand, CommandOrigin.Internal) as ApplicationInfo; + var cmdInfo = CommandDiscovery.LookupCommandInfo( + sshCommand, + CommandTypes.Application, + SearchResolutionOptions.None, + CommandOrigin.Internal, + context) as ApplicationInfo; + if (cmdInfo != null) { filePath = cmdInfo.Path; } } + else + { + // A Runspace may not be present in the TLS in SDK hosted apps + // or if running in another thread without a Runspace. While + // 'ProcessStartInfo' can lookup the full path in PATH, it searches + // the process' working directory first. 'LookupCommandInfo' does + // not search the process' working directory and we want to keep that + // behavior. We also get the parent dir of the full path to set as the + // new WorkingDirectory. So, we do a manual lookup here only in PATH. + string[] entries = Environment.GetEnvironmentVariable("PATH")?.Split( + Path.PathSeparator, + StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? []; + foreach (var path in entries) + { + if (!Path.IsPathFullyQualified(path)) + { + continue; + } + + var sshCommandPath = Path.Combine(path, sshCommand); + if (File.Exists(sshCommandPath)) + { + filePath = sshCommandPath; + break; + } + } + } + + if (string.IsNullOrEmpty(filePath)) + { + throw new CommandNotFoundException( + sshCommand, + null, + "CommandNotFoundException", + DiscoveryExceptions.CommandNotFoundException); + } // Create a local ssh process (client) that conects to a remote sshd process (server) using a 'powershell' subsystem. // diff --git a/test/Test.Common.props b/test/Test.Common.props index 769b1b5b275..e28b916f738 100644 --- a/test/Test.Common.props +++ b/test/Test.Common.props @@ -7,7 +7,7 @@ (c) Microsoft Corporation. net9.0 - 11.0 + 13.0 true true diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index a8e05fbbb96..debfbb0e1e3 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -3,7 +3,7 @@ Exe $(PERFLAB_TARGET_FRAMEWORKS) net5.0 - 11.0 + 13.0 diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index bcd8e6011df..87fab6299ec 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -10,7 +10,7 @@ 1.0.0 net9.0 true - 11.0 + 13.0 diff --git a/test/tools/WebListener/Controllers/GetController.cs b/test/tools/WebListener/Controllers/GetController.cs index 631886bb7e1..af563d16c2a 100644 --- a/test/tools/WebListener/Controllers/GetController.cs +++ b/test/tools/WebListener/Controllers/GetController.cs @@ -17,13 +17,13 @@ public JsonResult Index() Hashtable args = new Hashtable(); foreach (var key in Request.Query.Keys) { - args.Add(key, string.Join(Constants.HeaderSeparator, Request.Query[key])); + args.Add(key, string.Join(Constants.HeaderSeparator, (string)Request.Query[key])); } Hashtable headers = new Hashtable(); foreach (var key in Request.Headers.Keys) { - headers.Add(key, string.Join(Constants.HeaderSeparator, Request.Headers[key])); + headers.Add(key, string.Join(Constants.HeaderSeparator, (string)Request.Headers[key])); } Hashtable output = new Hashtable diff --git a/test/tools/WebListener/Controllers/MultipartController.cs b/test/tools/WebListener/Controllers/MultipartController.cs index 56e8c2003d4..5f053597791 100644 --- a/test/tools/WebListener/Controllers/MultipartController.cs +++ b/test/tools/WebListener/Controllers/MultipartController.cs @@ -75,7 +75,7 @@ public JsonResult Index(IFormCollection collection) Hashtable headers = new Hashtable(); foreach (var key in Request.Headers.Keys) { - headers.Add(key, string.Join(Constants.HeaderSeparator, Request.Headers[key])); + headers.Add(key, string.Join(Constants.HeaderSeparator, (string)Request.Headers[key])); } Hashtable output = new Hashtable diff --git a/test/tools/WebListener/Controllers/ResponseHeadersController.cs b/test/tools/WebListener/Controllers/ResponseHeadersController.cs index d5bffaefb70..f8693524714 100644 --- a/test/tools/WebListener/Controllers/ResponseHeadersController.cs +++ b/test/tools/WebListener/Controllers/ResponseHeadersController.cs @@ -23,7 +23,7 @@ public string Index() Hashtable headers = new Hashtable(); foreach (var key in Request.Query.Keys) { - headers.Add(key, string.Join(Constants.HeaderSeparator, Request.Query[key])); + headers.Add(key, string.Join(Constants.HeaderSeparator, (string)Request.Query[key])); if (string.Equals("Content-Type", key, StringComparison.InvariantCultureIgnoreCase)) { diff --git a/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index cda0bb83859..eccdcfa9479 100644 --- a/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -5,7 +5,7 @@ true $(SnkFile) true - 11.0 + 13.0 diff --git a/tools/packaging/projects/reference/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj b/tools/packaging/projects/reference/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj index 37ea87be80f..7f45926e29f 100644 --- a/tools/packaging/projects/reference/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj +++ b/tools/packaging/projects/reference/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj @@ -5,7 +5,7 @@ true $(SnkFile) true - 11.0 + 13.0 diff --git a/tools/packaging/projects/reference/System.Management.Automation/System.Management.Automation.csproj b/tools/packaging/projects/reference/System.Management.Automation/System.Management.Automation.csproj index d4e2b460dcb..3a021bb5517 100644 --- a/tools/packaging/projects/reference/System.Management.Automation/System.Management.Automation.csproj +++ b/tools/packaging/projects/reference/System.Management.Automation/System.Management.Automation.csproj @@ -5,7 +5,7 @@ true $(SnkFile) true - 11.0 + 13.0 From c1545b05ec76d1b047e19b465f4dd6f5197bbf24 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 12 Feb 2026 12:42:12 -0500 Subject: [PATCH 179/275] [release/v7.5] Add markdown link verification for PRs (#26407) --- .../markdownlinks/Parse-MarkdownLink.ps1 | 182 ++++++++++ .../infrastructure/markdownlinks/README.md | 177 ++++++++++ .../markdownlinks/Verify-MarkdownLinks.ps1 | 317 ++++++++++++++++++ .../infrastructure/markdownlinks/action.yml | 139 ++++++++ ...owershell-parameter-naming.instructions.md | 69 ++++ .github/workflows/verify-markdown-links.yml | 32 ++ 6 files changed, 916 insertions(+) create mode 100644 .github/actions/infrastructure/markdownlinks/Parse-MarkdownLink.ps1 create mode 100644 .github/actions/infrastructure/markdownlinks/README.md create mode 100644 .github/actions/infrastructure/markdownlinks/Verify-MarkdownLinks.ps1 create mode 100644 .github/actions/infrastructure/markdownlinks/action.yml create mode 100644 .github/instructions/powershell-parameter-naming.instructions.md create mode 100644 .github/workflows/verify-markdown-links.yml diff --git a/.github/actions/infrastructure/markdownlinks/Parse-MarkdownLink.ps1 b/.github/actions/infrastructure/markdownlinks/Parse-MarkdownLink.ps1 new file mode 100644 index 00000000000..a56d696eb6e --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/Parse-MarkdownLink.ps1 @@ -0,0 +1,182 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +#requires -version 7 +# Markdig is always available in PowerShell 7 +<# +.SYNOPSIS + Parse CHANGELOG files using Markdig to extract links. + +.DESCRIPTION + This script uses Markdig.Markdown.Parse to parse all markdown files in the CHANGELOG directory + and extract different types of links (inline links, reference links, etc.). + +.PARAMETER ChangelogPath + Path to the CHANGELOG directory. Defaults to ./CHANGELOG + +.PARAMETER LinkType + Filter by link type: All, Inline, Reference, AutoLink. Defaults to All. + +.EXAMPLE + .\Parse-MarkdownLink.ps1 + +.EXAMPLE + .\Parse-MarkdownLink.ps1 -LinkType Reference +#> + +param( + [string]$ChangelogPath = "./CHANGELOG", + [ValidateSet("All", "Inline", "Reference", "AutoLink")] + [string]$LinkType = "All" +) + +Write-Verbose "Using built-in Markdig functionality to parse markdown files" + +function Get-LinksFromMarkdownAst { + param( + [Parameter(Mandatory)] + [object]$Node, + [Parameter(Mandatory)] + [string]$FileName, + [System.Collections.ArrayList]$Links + ) + + if ($null -eq $Links) { + return + } + + # Check if current node is a link + if ($Node -is [Markdig.Syntax.Inlines.LinkInline]) { + $linkInfo = [PSCustomObject]@{ + Path = $FileName + Line = $Node.Line + 1 # Convert to 1-based line numbering + Column = $Node.Column + 1 # Convert to 1-based column numbering + Url = $Node.Url ?? "" + Text = $Node.FirstChild?.ToString() ?? "" + Type = "Inline" + IsImage = $Node.IsImage + } + [void]$Links.Add($linkInfo) + } + elseif ($Node -is [Markdig.Syntax.Inlines.AutolinkInline]) { + $linkInfo = [PSCustomObject]@{ + Path = $FileName + Line = $Node.Line + 1 + Column = $Node.Column + 1 + Url = $Node.Url ?? "" + Text = $Node.Url ?? "" + Type = "AutoLink" + IsImage = $false + } + [void]$Links.Add($linkInfo) + } + elseif ($Node -is [Markdig.Syntax.LinkReferenceDefinitionGroup]) { + foreach ($refDef in $Node) { + $linkInfo = [PSCustomObject]@{ + Path = $FileName + Line = $refDef.Line + 1 + Column = $refDef.Column + 1 + Url = $refDef.Url ?? "" + Text = $refDef.Label ?? "" + Type = "Reference" + IsImage = $false + } + [void]$Links.Add($linkInfo) + } + } + elseif ($Node -is [Markdig.Syntax.LinkReferenceDefinition]) { + $linkInfo = [PSCustomObject]@{ + Path = $FileName + Line = $Node.Line + 1 + Column = $Node.Column + 1 + Url = $Node.Url ?? "" + Text = $Node.Label ?? "" + Type = "Reference" + IsImage = $false + } + [void]$Links.Add($linkInfo) + } + + # For MarkdownDocument (root), iterate through all blocks + if ($Node -is [Markdig.Syntax.MarkdownDocument]) { + foreach ($block in $Node) { + Get-LinksFromMarkdownAst -Node $block -FileName $FileName -Links $Links + } + } + # For block containers, iterate through children + elseif ($Node -is [Markdig.Syntax.ContainerBlock]) { + foreach ($child in $Node) { + Get-LinksFromMarkdownAst -Node $child -FileName $FileName -Links $Links + } + } + # For leaf blocks with inlines, process the inline content + elseif ($Node -is [Markdig.Syntax.LeafBlock] -and $Node.Inline) { + Get-LinksFromMarkdownAst -Node $Node.Inline -FileName $FileName -Links $Links + } + # For inline containers, process all child inlines + elseif ($Node -is [Markdig.Syntax.Inlines.ContainerInline]) { + $child = $Node.FirstChild + while ($child) { + Get-LinksFromMarkdownAst -Node $child -FileName $FileName -Links $Links + $child = $child.NextSibling + } + } + # For other inline elements that might have children + elseif ($Node.PSObject.Properties.Name -contains "FirstChild" -and $Node.FirstChild) { + $child = $Node.FirstChild + while ($child) { + Get-LinksFromMarkdownAst -Node $child -FileName $FileName -Links $Links + $child = $child.NextSibling + } + } +} + +function Parse-ChangelogFiles { + param( + [string]$Path + ) + + if (-not (Test-Path $Path)) { + Write-Error "CHANGELOG directory not found: $Path" + return + } + + $markdownFiles = Get-ChildItem -Path $Path -Filter "*.md" -File + + if ($markdownFiles.Count -eq 0) { + Write-Warning "No markdown files found in $Path" + return + } + + $allLinks = [System.Collections.ArrayList]::new() + + foreach ($file in $markdownFiles) { + Write-Verbose "Processing file: $($file.Name)" + + try { + $content = Get-Content -Path $file.FullName -Raw -Encoding UTF8 + + # Parse the markdown content using Markdig + $document = [Markdig.Markdown]::Parse($content, [Markdig.MarkdownPipelineBuilder]::new()) + + # Extract links from the AST + Get-LinksFromMarkdownAst -Node $document -FileName $file.FullName -Links $allLinks + + } catch { + Write-Warning "Error processing file $($file.Name): $($_.Exception.Message)" + } + } + + # Filter by link type if specified + if ($LinkType -ne "All") { + $allLinks = $allLinks | Where-Object { $_.Type -eq $LinkType } + } + + return $allLinks +} + +# Main execution +$links = Parse-ChangelogFiles -Path $ChangelogPath + +# Output PowerShell objects +$links diff --git a/.github/actions/infrastructure/markdownlinks/README.md b/.github/actions/infrastructure/markdownlinks/README.md new file mode 100644 index 00000000000..e566ec2bcc3 --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/README.md @@ -0,0 +1,177 @@ +# Verify Markdown Links Action + +A GitHub composite action that verifies all links in markdown files using PowerShell and Markdig. + +## Features + +- ✅ Parses markdown files using Markdig (built into PowerShell 7) +- ✅ Extracts all link types: inline links, reference links, and autolinks +- ✅ Verifies HTTP/HTTPS links with configurable timeouts and retries +- ✅ Validates local file references +- ✅ Supports excluding specific URL patterns +- ✅ Provides detailed error reporting with file locations +- ✅ Outputs metrics for CI/CD integration + +## Usage + +### Basic Usage + +```yaml +- name: Verify Markdown Links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './CHANGELOG' +``` + +### Advanced Usage + +```yaml +- name: Verify Markdown Links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './docs' + fail-on-error: 'true' + timeout: 30 + max-retries: 2 + exclude-patterns: '*.example.com/*,*://localhost/*' +``` + +### With Outputs + +```yaml +- name: Verify Markdown Links + id: verify-links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './CHANGELOG' + fail-on-error: 'false' + +- name: Display Results + run: | + echo "Total links: ${{ steps.verify-links.outputs.total-links }}" + echo "Passed: ${{ steps.verify-links.outputs.passed-links }}" + echo "Failed: ${{ steps.verify-links.outputs.failed-links }}" + echo "Skipped: ${{ steps.verify-links.outputs.skipped-links }}" +``` + +## Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|---------| +| `path` | Path to the directory containing markdown files to verify | No | `./CHANGELOG` | +| `exclude-patterns` | Comma-separated list of URL patterns to exclude from verification | No | `''` | +| `fail-on-error` | Whether to fail the action if any links are broken | No | `true` | +| `timeout` | Timeout in seconds for HTTP requests | No | `30` | +| `max-retries` | Maximum number of retries for failed requests | No | `2` | + +## Outputs + +| Output | Description | +|--------|-------------| +| `total-links` | Total number of unique links checked | +| `passed-links` | Number of links that passed verification | +| `failed-links` | Number of links that failed verification | +| `skipped-links` | Number of links that were skipped | + +## Excluded Link Types + +The action automatically skips the following link types: + +- **Anchor links** (`#section-name`) - Would require full markdown parsing +- **Email links** (`mailto:user@example.com`) - Cannot be verified without sending email + +## GitHub Workflow Test + +This section provides a workflow example and instructions for testing the link verification action. + +### Testing the Workflow + +To test that the workflow properly detects broken links: + +1. Make change to this file (e.g., this README.md file already contains one in the [Broken Link Test](#broken-link-test) section) +1. The workflow will run and should fail, reporting the broken link(s) +1. Revert your change to this file +1. Push again to verify the workflow passes + +### Example Workflow Configuration + +```yaml +name: Verify Links + +on: + push: + branches: [ main ] + paths: + - '**/*.md' + pull_request: + branches: [ main ] + paths: + - '**/*.md' + schedule: + # Run weekly to catch external link rot + - cron: '0 0 * * 0' + +jobs: + verify-links: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Verify CHANGELOG Links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './CHANGELOG' + fail-on-error: 'true' + + - name: Verify Documentation Links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './docs' + fail-on-error: 'false' + exclude-patterns: '*.internal.example.com/*' +``` + +## How It Works + +1. **Parse Markdown**: Uses `Parse-MarkdownLink.ps1` to extract all links from markdown files using Markdig +2. **Deduplicate**: Groups links by URL to avoid checking the same link multiple times +3. **Verify Links**: + - HTTP/HTTPS links: Makes HEAD/GET requests with configurable timeout and retries + - Local file references: Checks if the file exists relative to the markdown file + - Excluded patterns: Skips links matching the exclude patterns +4. **Report Results**: Displays detailed results with file locations for failed links +5. **Set Outputs**: Provides metrics for downstream steps + +## Error Output Example + +``` +✗ FAILED: https://example.com/broken-link - HTTP 404 + Found in: /path/to/file.md:42:15 + Found in: /path/to/other.md:100:20 + +Link Verification Summary +============================================================ +Total URLs checked: 150 +Passed: 145 +Failed: 2 +Skipped: 3 + +Failed Links: + • https://example.com/broken-link + Error: HTTP 404 + Occurrences: 2 +``` + +## Requirements + +- PowerShell 7+ (includes Markdig) +- Runs on: `ubuntu-latest`, `windows-latest`, `macos-latest` + +## Broken Link Test + +- [Broken Link](https://github.com/PowerShell/PowerShell/wiki/NonExistentPage404) + +## License + +Same as the PowerShell repository. diff --git a/.github/actions/infrastructure/markdownlinks/Verify-MarkdownLinks.ps1 b/.github/actions/infrastructure/markdownlinks/Verify-MarkdownLinks.ps1 new file mode 100644 index 00000000000..f50ab1590b9 --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/Verify-MarkdownLinks.ps1 @@ -0,0 +1,317 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +#Requires -Version 7.0 + +<# +.SYNOPSIS + Verify all links in markdown files. + +.DESCRIPTION + This script parses markdown files to extract links and verifies their accessibility. + It supports HTTP/HTTPS links and local file references. + +.PARAMETER Path + Path to the directory containing markdown files. Defaults to current directory. + +.PARAMETER File + Array of specific markdown files to verify. If provided, Path parameter is ignored. + +.PARAMETER TimeoutSec + Timeout in seconds for HTTP requests. Defaults to 30. + +.PARAMETER MaximumRetryCount + Maximum number of retries for failed requests. Defaults to 2. + +.PARAMETER RetryIntervalSec + Interval in seconds between retry attempts. Defaults to 2. + +.EXAMPLE + .\Verify-MarkdownLinks.ps1 -Path ./CHANGELOG + +.EXAMPLE + .\Verify-MarkdownLinks.ps1 -Path ./docs -FailOnError + +.EXAMPLE + .\Verify-MarkdownLinks.ps1 -File @('CHANGELOG/7.5.md', 'README.md') +#> + +param( + [Parameter(ParameterSetName = 'ByPath', Mandatory)] + [string]$Path = "Q:\src\git\powershell\docs\git", + [Parameter(ParameterSetName = 'ByFile', Mandatory)] + [string[]]$File = @(), + [int]$TimeoutSec = 30, + [int]$MaximumRetryCount = 2, + [int]$RetryIntervalSec = 2 +) + +$ErrorActionPreference = 'Stop' + +# Get the script directory +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path + +# Determine what to process: specific files or directory +if ($File.Count -gt 0) { + Write-Host "Extracting links from $($File.Count) specified markdown file(s)" -ForegroundColor Cyan + + # Process each file individually + $allLinks = @() + $parseScriptPath = Join-Path $scriptDir "Parse-MarkdownLink.ps1" + + foreach ($filePath in $File) { + if (Test-Path $filePath) { + Write-Verbose "Processing: $filePath" + $fileLinks = & $parseScriptPath -ChangelogPath $filePath + $allLinks += $fileLinks + } + else { + Write-Warning "File not found: $filePath" + } + } +} +else { + Write-Host "Extracting links from markdown files in: $Path" -ForegroundColor Cyan + + # Get all links from markdown files using the Parse-ChangelogLinks script + $parseScriptPath = Join-Path $scriptDir "Parse-MarkdownLink.ps1" + $allLinks = & $parseScriptPath -ChangelogPath $Path +} + +if ($allLinks.Count -eq 0) { + Write-Host "No links found in markdown files." -ForegroundColor Yellow + exit 0 +} + +Write-Host "Found $($allLinks.Count) links to verify" -ForegroundColor Green + +# Group links by URL to avoid duplicate checks +$uniqueLinks = $allLinks | Group-Object -Property Url + +Write-Host "Unique URLs to verify: $($uniqueLinks.Count)" -ForegroundColor Cyan + +$results = @{ + Total = $uniqueLinks.Count + Passed = 0 + Failed = 0 + Skipped = 0 + Errors = [System.Collections.ArrayList]::new() +} + +function Test-HttpLink { + param( + [string]$Url + ) + + try { + # Try HEAD request first (faster, doesn't download content) + $response = Invoke-WebRequest -Uri $Url ` + -Method Head ` + -TimeoutSec $TimeoutSec ` + -MaximumRetryCount $MaximumRetryCount ` + -RetryIntervalSec $RetryIntervalSec ` + -UserAgent "Mozilla/5.0 (compatible; GitHubActions/1.0; +https://github.com/PowerShell/PowerShell)" ` + -SkipHttpErrorCheck + + # If HEAD fails with 404 or 405, retry with GET (some servers don't support HEAD) + if ($response.StatusCode -eq 404 -or $response.StatusCode -eq 405) { + Write-Verbose "HEAD request failed with $($response.StatusCode), retrying with GET for: $Url" + $response = Invoke-WebRequest -Uri $Url ` + -Method Get ` + -TimeoutSec $TimeoutSec ` + -MaximumRetryCount $MaximumRetryCount ` + -RetryIntervalSec $RetryIntervalSec ` + -UserAgent "Mozilla/5.0 (compatible; GitHubActions/1.0; +https://github.com)" ` + -SkipHttpErrorCheck + } + + if ($response.StatusCode -ge 200 -and $response.StatusCode -lt 400) { + return @{ Success = $true; StatusCode = $response.StatusCode } + } + else { + return @{ Success = $false; StatusCode = $response.StatusCode; Error = "HTTP $($response.StatusCode)" } + } + } + catch { + return @{ Success = $false; StatusCode = 0; Error = $_.Exception.Message } + } +} + +function Test-LocalLink { + param( + [string]$Url, + [string]$BasePath + ) + + # Strip query parameters (e.g., ?sanitize=true) and anchors (e.g., #section) + $cleanUrl = $Url -replace '\?.*$', '' -replace '#.*$', '' + + # Handle relative paths + $targetPath = Join-Path $BasePath $cleanUrl + + if (Test-Path $targetPath) { + return @{ Success = $true } + } + else { + return @{ Success = $false; Error = "File not found: $targetPath" } + } +} + +# Verify each unique link +$progressCount = 0 +foreach ($linkGroup in $uniqueLinks) { + $progressCount++ + $url = $linkGroup.Name + $occurrences = $linkGroup.Group + Write-Verbose -Verbose "[$progressCount/$($uniqueLinks.Count)] Checking: $url" + + # Determine link type and verify + $verifyResult = $null + if ($url -match '^https?://') { + $verifyResult = Test-HttpLink -Url $url + } + elseif ($url -match '^#') { + Write-Verbose -Verbose "Skipping anchor link: $url" + $results.Skipped++ + continue + } + elseif ($url -match '^mailto:') { + Write-Verbose -Verbose "Skipping mailto link: $url" + $results.Skipped++ + continue + } + else { + $basePath = Split-Path -Parent $occurrences[0].Path + $verifyResult = Test-LocalLink -Url $url -BasePath $basePath + } + if ($verifyResult.Success) { + Write-Host "✓ OK: $url" -ForegroundColor Green + $results.Passed++ + } + else { + $errorMsg = if ($verifyResult.StatusCode) { + "HTTP $($verifyResult.StatusCode)" + } + else { + $verifyResult.Error + } + + # Determine if this status code should be ignored or treated as failure + # Ignore: 401 (Unauthorized), 403 (Forbidden), 429 (Too Many Requests - already retried) + # Fail: 404 (Not Found), 410 (Gone), 406 (Not Acceptable) - these indicate broken links + $shouldIgnore = $false + $ignoreReason = "" + + switch ($verifyResult.StatusCode) { + 401 { + $shouldIgnore = $true + $ignoreReason = "authentication required" + } + 403 { + $shouldIgnore = $true + $ignoreReason = "access forbidden" + } + 429 { + $shouldIgnore = $true + $ignoreReason = "rate limited (already retried)" + } + } + + if ($shouldIgnore) { + Write-Host "⊘ IGNORED: $url - $errorMsg ($ignoreReason)" -ForegroundColor Yellow + Write-Verbose -Verbose "Ignored error details for $url - Status: $($verifyResult.StatusCode) - $ignoreReason" + foreach ($occurrence in $occurrences) { + Write-Verbose -Verbose " Found in: $($occurrence.Path):$($occurrence.Line):$($occurrence.Column)" + } + $results.Skipped++ + } + else { + Write-Host "✗ FAILED: $url - $errorMsg" -ForegroundColor Red + foreach ($occurrence in $occurrences) { + Write-Host " Found in: $($occurrence.Path):$($occurrence.Line):$($occurrence.Column)" -ForegroundColor DarkGray + } + $results.Failed++ + [void]$results.Errors.Add(@{ + Url = $url + Error = $errorMsg + Occurrences = $occurrences + }) + } + } + } + +# Print summary +Write-Host "`n" + ("=" * 60) -ForegroundColor Cyan +Write-Host "Link Verification Summary" -ForegroundColor Cyan +Write-Host ("=" * 60) -ForegroundColor Cyan +Write-Host "Total URLs checked: $($results.Total)" -ForegroundColor White +Write-Host "Passed: $($results.Passed)" -ForegroundColor Green +Write-Host "Failed: $($results.Failed)" -ForegroundColor $(if ($results.Failed -gt 0) { "Red" } else { "Green" }) +Write-Host "Skipped: $($results.Skipped)" -ForegroundColor Gray + +if ($results.Failed -gt 0) { + Write-Host "`nFailed Links:" -ForegroundColor Red + foreach ($failedLink in $results.Errors) { + Write-Host " • $($failedLink.Url)" -ForegroundColor Red + Write-Host " Error: $($failedLink.Error)" -ForegroundColor DarkGray + Write-Host " Occurrences: $($failedLink.Occurrences.Count)" -ForegroundColor DarkGray + } + + Write-Host "`n❌ Link verification failed!" -ForegroundColor Red + exit 1 +} +else { + Write-Host "`n✅ All links verified successfully!" -ForegroundColor Green +} + +# Write to GitHub Actions step summary if running in a workflow +if ($env:GITHUB_STEP_SUMMARY) { + $summaryContent = @" + +# Markdown Link Verification Results + +## Summary +- **Total URLs checked:** $($results.Total) +- **Passed:** ✅ $($results.Passed) +- **Failed:** $(if ($results.Failed -gt 0) { "❌" } else { "✅" }) $($results.Failed) +- **Skipped:** $($results.Skipped) + +"@ + + if ($results.Failed -gt 0) { + $summaryContent += @" + +## Failed Links + +| URL | Error | Occurrences | +|-----|-------|-------------| + +"@ + foreach ($failedLink in $results.Errors) { + $summaryContent += "| $($failedLink.Url) | $($failedLink.Error) | $($failedLink.Occurrences.Count) |`n" + } + + $summaryContent += @" + +

+Click to see all failed link locations + +"@ + foreach ($failedLink in $results.Errors) { + $summaryContent += "`n### $($failedLink.Url)`n" + $summaryContent += "**Error:** $($failedLink.Error)`n`n" + foreach ($occurrence in $failedLink.Occurrences) { + $summaryContent += "- `$($occurrence.Path):$($occurrence.Line):$($occurrence.Column)`n" + } + } + $summaryContent += "`n
`n" + } + else { + $summaryContent += "`n## ✅ All links verified successfully!`n" + } + + Write-Verbose -Verbose "Writing `n $summaryContent `n to ${env:GITHUB_STEP_SUMMARY}" + $summaryContent | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append + Write-Verbose -Verbose "Summary written to GitHub Actions step summary" +} + diff --git a/.github/actions/infrastructure/markdownlinks/action.yml b/.github/actions/infrastructure/markdownlinks/action.yml new file mode 100644 index 00000000000..1d6d0864784 --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/action.yml @@ -0,0 +1,139 @@ +name: 'Verify Markdown Links' +description: 'Verify all links in markdown files using PowerShell and Markdig' +author: 'PowerShell Team' + +inputs: + timeout-sec: + description: 'Timeout in seconds for HTTP requests' + required: false + default: '30' + maximum-retry-count: + description: 'Maximum number of retries for failed requests' + required: false + default: '2' + +outputs: + total-links: + description: 'Total number of unique links checked' + value: ${{ steps.verify.outputs.total }} + passed-links: + description: 'Number of links that passed verification' + value: ${{ steps.verify.outputs.passed }} + failed-links: + description: 'Number of links that failed verification' + value: ${{ steps.verify.outputs.failed }} + skipped-links: + description: 'Number of links that were skipped' + value: ${{ steps.verify.outputs.skipped }} + +runs: + using: 'composite' + steps: + - name: Get changed markdown files + id: changed-files + uses: actions/github-script@v7 + with: + script: | + let changedMarkdownFiles = []; + + if (context.eventName === 'pull_request') { + const { data: files } = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + }); + + changedMarkdownFiles = files + .filter(file => file.filename.endsWith('.md')) + .map(file => file.filename); + } else if (context.eventName === 'push') { + const { data: comparison } = await github.rest.repos.compareCommits({ + owner: context.repo.owner, + repo: context.repo.repo, + base: context.payload.before, + head: context.payload.after, + }); + + changedMarkdownFiles = comparison.files + .filter(file => file.filename.endsWith('.md')) + .map(file => file.filename); + } else { + core.setFailed(`Unsupported event type: ${context.eventName}. This action only supports 'pull_request' and 'push' events.`); + return; + } + + console.log('Changed markdown files:', changedMarkdownFiles); + core.setOutput('files', JSON.stringify(changedMarkdownFiles)); + core.setOutput('count', changedMarkdownFiles.length); + return changedMarkdownFiles; + + - name: Verify markdown links + id: verify + shell: pwsh + run: | + Write-Host "Starting markdown link verification..." -ForegroundColor Cyan + + # Get changed markdown files from previous step + $changedFilesJson = '${{ steps.changed-files.outputs.files }}' + $changedFiles = $changedFilesJson | ConvertFrom-Json + + if ($changedFiles.Count -eq 0) { + Write-Host "No markdown files changed, skipping verification" -ForegroundColor Yellow + "total=0" >> $env:GITHUB_OUTPUT + "passed=0" >> $env:GITHUB_OUTPUT + "failed=0" >> $env:GITHUB_OUTPUT + "skipped=0" >> $env:GITHUB_OUTPUT + exit 0 + } + + Write-Host "Changed markdown files: $($changedFiles.Count)" -ForegroundColor Cyan + $changedFiles | ForEach-Object { Write-Host " - $_" -ForegroundColor Gray } + + # Build parameters for each file + $params = @{ + File = $changedFiles + TimeoutSec = [int]'${{ inputs.timeout-sec }}' + MaximumRetryCount = [int]'${{ inputs.maximum-retry-count }}' + } + + # Run the verification script + $scriptPath = Join-Path '${{ github.action_path }}' 'Verify-MarkdownLinks.ps1' + + # Capture output and parse results + $output = & $scriptPath @params 2>&1 | Tee-Object -Variable capturedOutput + + # Try to extract metrics from output + $totalLinks = 0 + $passedLinks = 0 + $failedLinks = 0 + $skippedLinks = 0 + + foreach ($line in $capturedOutput) { + if ($line -match 'Total URLs checked: (\d+)') { + $totalLinks = $Matches[1] + } + elseif ($line -match 'Passed: (\d+)') { + $passedLinks = $Matches[1] + } + elseif ($line -match 'Failed: (\d+)') { + $failedLinks = $Matches[1] + } + elseif ($line -match 'Skipped: (\d+)') { + $skippedLinks = $Matches[1] + } + } + + # Set outputs + "total=$totalLinks" >> $env:GITHUB_OUTPUT + "passed=$passedLinks" >> $env:GITHUB_OUTPUT + "failed=$failedLinks" >> $env:GITHUB_OUTPUT + "skipped=$skippedLinks" >> $env:GITHUB_OUTPUT + + Write-Host "Action completed" -ForegroundColor Cyan + + # Exit with the same code as the verification script + exit $LASTEXITCODE + +branding: + icon: 'link' + color: 'blue' diff --git a/.github/instructions/powershell-parameter-naming.instructions.md b/.github/instructions/powershell-parameter-naming.instructions.md new file mode 100644 index 00000000000..155fd1a85c3 --- /dev/null +++ b/.github/instructions/powershell-parameter-naming.instructions.md @@ -0,0 +1,69 @@ +--- +applyTo: '**/*.ps1, **/*.psm1' +description: Naming conventions for PowerShell parameters +--- + +# PowerShell Parameter Naming Conventions + +## Purpose + +This instruction defines the naming conventions for parameters in PowerShell scripts and modules. Consistent parameter naming improves code readability, maintainability, and usability for users of PowerShell cmdlets and functions. + +## Parameter Naming Rules + +### General Conventions +- **Singular Nouns**: Use singular nouns for parameter names even if the parameter is expected to handle multiple values (e.g., `File` instead of `Files`). +- **Use PascalCase**: Parameter names must use PascalCase (e.g., `ParameterName`). +- **Descriptive Names**: Parameter names should be descriptive and convey their purpose clearly (e.g., `FilePath`, `UserName`). +- **Avoid Abbreviations**: Avoid using abbreviations unless they are widely recognized (e.g., `ID` for Identifier). +- **Avoid Reserved Words**: Do not use PowerShell reserved words as parameter names (e.g., `if`, `else`, `function`). + +### Units and Precision +- **Include Units in Parameter Names**: When a parameter represents a value with units, include the unit in the parameter name for clarity: + - `TimeoutSec` instead of `Timeout` + - `RetryIntervalSec` instead of `RetryInterval` + - `MaxSizeBytes` instead of `MaxSize` +- **Use Full Words for Clarity**: Spell out common terms to match PowerShell conventions: + - `MaximumRetryCount` instead of `MaxRetries` + - `MinimumLength` instead of `MinLength` + +### Alignment with Built-in Cmdlets +- **Follow Existing PowerShell Conventions**: When your parameter serves a similar purpose to a built-in cmdlet parameter, use the same or similar naming: + - Match `Invoke-WebRequest` parameters when making HTTP requests: `TimeoutSec`, `MaximumRetryCount`, `RetryIntervalSec` + - Follow common parameter patterns like `Path`, `Force`, `Recurse`, `WhatIf`, `Confirm` +- **Consistency Within Scripts**: If multiple parameters relate to the same concept, use consistent naming patterns (e.g., `TimeoutSec`, `RetryIntervalSec` both use `Sec` suffix). + +## Examples + +### Good Parameter Names +```powershell +param( + [string[]]$File, # Singular, even though it accepts arrays + [int]$TimeoutSec = 30, # Unit included + [int]$MaximumRetryCount = 2, # Full word "Maximum" + [int]$RetryIntervalSec = 2, # Consistent with TimeoutSec + [string]$Path, # Standard PowerShell convention + [switch]$Force # Common PowerShell parameter +) +``` + +### Names to Avoid +```powershell +param( + [string[]]$Files, # Should be singular: File + [int]$Timeout = 30, # Missing unit: TimeoutSec + [int]$MaxRetries = 2, # Should be: MaximumRetryCount + [int]$RetryInterval = 2, # Missing unit: RetryIntervalSec + [string]$FileLoc, # Avoid abbreviations: FilePath + [int]$Max # Ambiguous: MaximumWhat? +) +``` + +## Exceptions +- **Common Terms**: Some common terms may be used in plural form if they are widely accepted in the context (e.g., `Credentials`, `Permissions`). +- **Legacy Code**: Existing code that does not follow these conventions may be exempted to avoid breaking changes, but new code should adhere to these guidelines. +- **Well Established Naming Patterns**: If a naming pattern is well established in the PowerShell community, it may be used even if it does not strictly adhere to these guidelines. + +## References +- [PowerShell Cmdlet Design Guidelines](https://learn.microsoft.com/powershell/scripting/developer/cmdlet/strongly-encouraged-development-guidelines) +- [About Parameters - PowerShell Documentation](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_parameters) diff --git a/.github/workflows/verify-markdown-links.yml b/.github/workflows/verify-markdown-links.yml new file mode 100644 index 00000000000..db9fb7e416a --- /dev/null +++ b/.github/workflows/verify-markdown-links.yml @@ -0,0 +1,32 @@ +name: Verify Markdown Links + +on: + push: + branches: [ main, master ] + paths: + - '**/*.md' + - '.github/workflows/verify-markdown-links.yml' + - '.github/actions/infrastructure/markdownlinks/**' + pull_request: + branches: [ main, master ] + paths: + - '**/*.md' + schedule: + # Run weekly on Sundays at midnight UTC to catch external link rot + - cron: '0 0 * * 0' + workflow_dispatch: + +jobs: + verify-markdown-links: + name: Verify Markdown Links + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Verify markdown links + id: verify + uses: ./.github/actions/infrastructure/markdownlinks + with: + timeout-sec: 30 + maximum-retry-count: 2 From 7979a4bc2e892bbc1785c4287fefd75486b7751f Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 12 Feb 2026 12:47:23 -0500 Subject: [PATCH 180/275] [release/v7.5] Update the `Update-Help` tests to use `-Force` to remove read-only files (#26788) --- test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 index d4cbb420066..e6e6b492410 100644 --- a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 @@ -215,7 +215,7 @@ function RunUpdateHelpTests It ('Validate Update-Help for module ''{0}'' in {1}' -F $moduleName, [PSCustomObject] $updateScope) -Skip:(!(Test-CanWriteToPsHome) -and $userscope -eq $false) { # Delete the whole help directory - Remove-Item ($moduleHelpPath) -Recurse + Remove-Item ($moduleHelpPath) -Recurse -Force -ErrorAction SilentlyContinue [hashtable] $UICultureParam = $(if ((Get-UICulture).Name -ne $myUICulture) { @{ UICulture = $myUICulture } } else { @{} }) [hashtable] $sourcePathParam = $(if ($useSourcePath) { @{ SourcePath = Join-Path $PSScriptRoot assets } } else { @{} }) From 8381df3f362783c05d24b4152fdc41327ebb1887 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 12 Feb 2026 13:43:02 -0800 Subject: [PATCH 181/275] [release/v7.5] Fix the progress preference variable in script cmdlets (#26791) --- docs/community/working-group-definitions.md | 2 +- .../engine/SpecialVariables.cs | 2 + .../engine/parser/Compiler.cs | 8 ++++ .../Scripting/CommonParameters.Tests.ps1 | 38 +++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/docs/community/working-group-definitions.md b/docs/community/working-group-definitions.md index e50f54d3cf6..ea77c49df80 100644 --- a/docs/community/working-group-definitions.md +++ b/docs/community/working-group-definitions.md @@ -30,7 +30,7 @@ The PowerShell developer experience includes the **development of modules** (in as well as the experience of **hosting PowerShell and its APIs** in other applications and language runtimes. Special consideration should be given to topics like **backwards compatibility** with Windows PowerShell (e.g. with **PowerShell Standard**) and **integration with related developer tools** -(e.g. .NET CLI or the PowerShell extension for VS Code). +(e.g. .NET CLI or the PowerShell extension for Visual Studio Code). ### Members diff --git a/src/System.Management.Automation/engine/SpecialVariables.cs b/src/System.Management.Automation/engine/SpecialVariables.cs index 420b52d4d22..7563f89a919 100644 --- a/src/System.Management.Automation/engine/SpecialVariables.cs +++ b/src/System.Management.Automation/engine/SpecialVariables.cs @@ -341,6 +341,7 @@ internal static class SpecialVariables SpecialVariables.WarningPreference, SpecialVariables.InformationPreference, SpecialVariables.ConfirmPreference, + SpecialVariables.ProgressPreference, }; internal static readonly Type[] PreferenceVariableTypes = @@ -352,6 +353,7 @@ internal static class SpecialVariables /* WarningPreference */ typeof(ActionPreference), /* InformationPreference */ typeof(ActionPreference), /* ConfirmPreference */ typeof(ConfirmImpact), + /* ProgressPreference */ typeof(ActionPreference), }; // The following variables are created in every session w/ AllScope. We avoid creating local slots when we diff --git a/src/System.Management.Automation/engine/parser/Compiler.cs b/src/System.Management.Automation/engine/parser/Compiler.cs index 30528f99588..d010234edec 100644 --- a/src/System.Management.Automation/engine/parser/Compiler.cs +++ b/src/System.Management.Automation/engine/parser/Compiler.cs @@ -833,6 +833,14 @@ internal class Compiler : ICustomAstVisitor2 static Compiler() { + Diagnostics.Assert(SpecialVariables.AutomaticVariables.Length == (int)AutomaticVariable.NumberOfAutomaticVariables + && SpecialVariables.AutomaticVariableTypes.Length == (int)AutomaticVariable.NumberOfAutomaticVariables, + "The 'AutomaticVariable' enum length does not match both 'AutomaticVariables' and 'AutomaticVariableTypes' length."); + + Diagnostics.Assert(Enum.GetNames(typeof(PreferenceVariable)).Length == SpecialVariables.PreferenceVariables.Length + && Enum.GetNames(typeof(PreferenceVariable)).Length == SpecialVariables.PreferenceVariableTypes.Length, + "The 'PreferenceVariable' enum length does not match both 'PreferenceVariables' and 'PreferenceVariableTypes' length."); + s_functionContext = Expression.Parameter(typeof(FunctionContext), "funcContext"); s_executionContextParameter = Expression.Variable(typeof(ExecutionContext), "context"); diff --git a/test/powershell/Language/Scripting/CommonParameters.Tests.ps1 b/test/powershell/Language/Scripting/CommonParameters.Tests.ps1 index 6f9d80e1677..4b6eda1ef95 100644 --- a/test/powershell/Language/Scripting/CommonParameters.Tests.ps1 +++ b/test/powershell/Language/Scripting/CommonParameters.Tests.ps1 @@ -147,6 +147,44 @@ Describe "Common parameters support for script cmdlets" -Tags "CI" { } } + Context "ProgressAction" { + It "Ignores progress actions on advanced script function with no variables" { + $ps.AddScript( +@' +function test-function { + [CmdletBinding()]param() + + Write-Progress "progress foo" +} +test-function -ProgressAction Ignore +'@).Invoke() + + $ps.Streams.Progress.Count | Should -Be 0 + $ps.Streams.Error | ForEach-Object { + Write-Error -ErrorRecord $_ -ErrorAction Stop + } + } + + It "Ignores progress actions on advanced script function with variables" { + $ps.AddScript( +@' +function test-function { + [CmdletBinding()]param([string]$path) + + switch($false) { default { "echo $path" } } + + Write-Progress "progress foo" +} +test-function -ProgressAction Ignore +'@).Invoke() + + $ps.Streams.Progress.Count | Should -Be 0 + $ps.Streams.Error | ForEach-Object { + Write-Error -ErrorRecord $_ -ErrorAction Stop + } + } + } + Context "SupportShouldprocess" { $script = ' function get-foo From 162bbec3680d7849dca355dfc72f08a3de995846 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 12 Feb 2026 13:43:56 -0800 Subject: [PATCH 182/275] [release/v7.5] Add `libicu76` dependency to support Debian 13 (#26792) --- tools/packaging/packaging.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 26300523e9b..8a17b11a414 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1613,7 +1613,7 @@ function Get-PackageDependencies "libgssapi-krb5-2", "libstdc++6", "zlib1g", - "libicu74|libicu72|libicu71|libicu70|libicu69|libicu68|libicu67|libicu66|libicu65|libicu63|libicu60|libicu57|libicu55|libicu52", + "libicu76|libicu74|libicu72|libicu71|libicu70|libicu69|libicu68|libicu67|libicu66|libicu65|libicu63|libicu60|libicu57|libicu55|libicu52", "libssl3|libssl1.1|libssl1.0.2|libssl1.0.0" ) From 9acb52f78e53e5768bd1dc01a2f77061cb68fc4a Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 12 Feb 2026 13:44:31 -0800 Subject: [PATCH 183/275] [release/v7.5] Replace `fpm` with native `rpmbuild` for RPM package generation (#26793) --- .../actions/test/linux-packaging/action.yml | 13 + .github/workflows/linux-ci.yml | 3 +- build.psm1 | 21 +- .../linux/package-validation.tests.ps1 | 91 +++++ tools/ci.psm1 | 26 +- tools/packaging/packaging.psm1 | 326 ++++++++++++++++-- 6 files changed, 440 insertions(+), 40 deletions(-) create mode 100644 test/packaging/linux/package-validation.tests.ps1 diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index 736bddfa7a7..b7bbdf37185 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -62,6 +62,9 @@ runs: # Create the artifacts staging directory New-Item -ItemType Directory -Path "$env:BUILD_ARTIFACTSTAGINGDIRECTORY" -Force | Out-Null + # Import packaging module to ensure RPM packaging changes are loaded + Import-Module ./build.psm1 -Force + Import-Module ./tools/packaging/packaging.psm1 -Force Import-Module ./tools/ci.psm1 Restore-PSOptions -PSOptionsPath '${{ runner.workspace }}/build/psoptions.json' $options = (Get-PSOptions) @@ -75,6 +78,16 @@ runs: Invoke-CIFinish shell: pwsh + - name: Validate Package Names + run: |- + # Run Pester tests to validate package names + Import-Module Pester -Force + $testResults = Invoke-Pester -Path ./test/packaging/linux/package-validation.tests.ps1 -PassThru + if ($testResults.FailedCount -gt 0) { + throw "Package validation tests failed" + } + shell: pwsh + - name: Upload deb packages uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 6cf1e4c67b3..e5cb91dac64 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -51,6 +51,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout uses: actions/checkout@v4 @@ -237,7 +238,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.packagingChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout diff --git a/build.psm1 b/build.psm1 index c60bec719f2..810709fbf88 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2401,11 +2401,24 @@ function Start-PSBootstrap { } # Install [fpm](https://github.com/jordansissel/fpm) + # Note: fpm is now only needed for DEB and macOS packages; RPM packages use rpmbuild directly if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { - Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" - Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.16.3" - Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" - Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5" + # Install fpm on Debian-based systems, macOS, and Mariner (where DEB packages are built) + if (($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) -or $environment.IsMacOS) { + Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" + Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.16.3" + Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" + Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5" + } + + # For RPM-based systems, ensure rpmbuild is available + if ($environment.IsLinux -and ($environment.IsRedHatFamily -or $environment.IsSUSEFamily -or $environment.IsMariner)) { + Write-Verbose -Verbose "Checking for rpmbuild..." + if (!(Get-Command rpmbuild -ErrorAction SilentlyContinue)) { + Write-Warning "rpmbuild not found. Installing rpm-build package..." + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y rpm-build")) -IgnoreExitcode + } + } } } diff --git a/test/packaging/linux/package-validation.tests.ps1 b/test/packaging/linux/package-validation.tests.ps1 new file mode 100644 index 00000000000..241863de45d --- /dev/null +++ b/test/packaging/linux/package-validation.tests.ps1 @@ -0,0 +1,91 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe "Linux Package Name Validation" { + BeforeAll { + # Determine artifacts directory (GitHub Actions or Azure DevOps) + $artifactsDir = if ($env:GITHUB_ACTIONS -eq 'true') { + "$env:GITHUB_WORKSPACE/../packages" + } else { + $env:SYSTEM_ARTIFACTSDIRECTORY + } + + if (-not $artifactsDir) { + throw "Artifacts directory not found. GITHUB_WORKSPACE or SYSTEM_ARTIFACTSDIRECTORY must be set." + } + + Write-Verbose "Artifacts directory: $artifactsDir" -Verbose + } + + Context "RPM Package Names" { + It "Should have valid RPM package names" { + $rpmPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.rpm -ErrorAction SilentlyContinue + + if ($rpmPackages.Count -eq 0) { + Set-ItResult -Skipped -Because "No RPM packages found in artifacts directory" + return + } + + $invalidPackages = @() + # Regex pattern for valid RPM package names. + # Breakdown: + # ^powershell\- : Starts with 'powershell-' + # (preview-|lts-)? : Optionally 'preview-' or 'lts-' + # \d+\.\d+\.\d+ : Version number (e.g., 7.6.0) + # (_[a-z]*\.\d+)? : Optional underscore, letters, dot, and digits (e.g., _alpha.1) + # -1\. : Literal '-1.' + # (preview\.\d+\.)? : Optional 'preview.' and digits, followed by a dot + # (rh|cm)\. : Either 'rh.' or 'cm.' + # (x86_64|aarch64)\.rpm$ : Architecture and file extension + $rpmPackageNamePattern = 'powershell\-(preview-|lts-)?\d+\.\d+\.\d+(_[a-z]*\.\d+)?-1\.(preview\.\d+\.)?(rh|cm)\.(x86_64|aarch64)\.rpm' + + foreach ($package in $rpmPackages) { + if ($package.Name -notmatch $rpmPackageNamePattern) { + $invalidPackages += "$($package.Name) is not a valid RPM package name" + Write-Warning "$($package.Name) is not a valid RPM package name" + } + } + + if ($invalidPackages.Count -gt 0) { + throw ($invalidPackages | Out-String) + } + + $rpmPackages.Count | Should -BeGreaterThan 0 + } + } + + Context "Tar.Gz Package Names" { + It "Should have valid tar.gz package names" { + $tarPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.tar.gz -ErrorAction SilentlyContinue + + if ($tarPackages.Count -eq 0) { + Set-ItResult -Skipped -Because "No tar.gz packages found in artifacts directory" + return + } + + $invalidPackages = @() + foreach ($package in $tarPackages) { + # Pattern matches: powershell-7.6.0-preview.6-linux-x64.tar.gz or powershell-7.6.0-linux-x64.tar.gz + # Also matches various runtime configurations + if ($package.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?(linux|osx|linux-musl)+\-(x64\-fxdependent|x64|arm32|arm64|x64\-musl-noopt\-fxdependent)\.(tar\.gz)') { + $invalidPackages += "$($package.Name) is not a valid tar.gz package name" + Write-Warning "$($package.Name) is not a valid tar.gz package name" + } + } + + if ($invalidPackages.Count -gt 0) { + throw ($invalidPackages | Out-String) + } + + $tarPackages.Count | Should -BeGreaterThan 0 + } + } + + Context "Package Existence" { + It "Should find at least one package in artifacts directory" { + $allPackages = Get-ChildItem -Path $artifactsDir -Recurse -Include *.rpm, *.tar.gz, *.deb -ErrorAction SilentlyContinue + + $allPackages.Count | Should -BeGreaterThan 0 -Because "At least one package should exist in the artifacts directory" + } + } +} diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 7b13ded1811..9e95e68c843 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -874,16 +874,36 @@ function New-LinuxPackage $packageObj = $package } - Write-Log -message "Artifacts directory: ${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" - Copy-Item $packageObj.FullName -Destination "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" -Force + # Determine artifacts directory (GitHub Actions or Azure DevOps) + $artifactsDir = if ($env:GITHUB_ACTIONS -eq 'true') { + "${env:GITHUB_WORKSPACE}/../packages" + } else { + "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" + } + + # Ensure artifacts directory exists + if (-not (Test-Path $artifactsDir)) { + New-Item -ItemType Directory -Path $artifactsDir -Force | Out-Null + } + + Write-Log -message "Artifacts directory: $artifactsDir" + Copy-Item $packageObj.FullName -Destination $artifactsDir -Force } if ($IsLinux) { + # Determine artifacts directory (GitHub Actions or Azure DevOps) + $artifactsDir = if ($env:GITHUB_ACTIONS -eq 'true') { + "${env:GITHUB_WORKSPACE}/../packages" + } else { + "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" + } + # Create and package Raspbian .tgz + # Build must be clean for Raspbian Start-PSBuild -PSModuleRestore -Clean -Runtime linux-arm -Configuration 'Release' $armPackage = Start-PSPackage @packageParams -Type tar-arm -SkipReleaseChecks - Copy-Item $armPackage -Destination "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" -Force + Copy-Item $armPackage -Destination $artifactsDir -Force } } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 8a17b11a414..195f3e8187e 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1245,40 +1245,124 @@ function New-UnixPackage { # Setup package dependencies $Dependencies = @(Get-PackageDependencies @packageDependenciesParams) - $Arguments = @() - - - $Arguments += Get-FpmArguments ` - -Name $Name ` - -Version $packageVersion ` - -Iteration $Iteration ` - -Description $Description ` - -Type $Type ` - -Dependencies $Dependencies ` - -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` - -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` - -Staging $Staging ` - -Destination $Destination ` - -ManGzipFile $ManGzipInfo.GzipFile ` - -ManDestination $ManGzipInfo.ManFile ` - -LinkInfo $Links ` - -AppsFolder $AppsFolder ` - -Distribution $DebDistro ` - -HostArchitecture $HostArchitecture ` - -ErrorAction Stop - # Build package try { - if ($PSCmdlet.ShouldProcess("Create $type package")) { - Write-Log "Creating package with fpm $Arguments..." - try { - $Output = Start-NativeExecution { fpm $Arguments } + if ($Type -eq 'rpm') { + # Use rpmbuild directly for RPM packages + if ($PSCmdlet.ShouldProcess("Create RPM package with rpmbuild")) { + Write-Log "Creating RPM package with rpmbuild..." + + # Create rpmbuild directory structure + $rpmBuildRoot = Join-Path $env:HOME "rpmbuild" + $specsDir = Join-Path $rpmBuildRoot "SPECS" + $rpmsDir = Join-Path $rpmBuildRoot "RPMS" + + New-Item -ItemType Directory -Path $specsDir -Force | Out-Null + New-Item -ItemType Directory -Path $rpmsDir -Force | Out-Null + + # Generate RPM spec file + $specContent = New-RpmSpec ` + -Name $Name ` + -Version $packageVersion ` + -Iteration $Iteration ` + -Description $Description ` + -Dependencies $Dependencies ` + -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` + -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` + -Staging $Staging ` + -Destination $Destination ` + -ManGzipFile $ManGzipInfo.GzipFile ` + -ManDestination $ManGzipInfo.ManFile ` + -LinkInfo $Links ` + -Distribution $DebDistro ` + -HostArchitecture $HostArchitecture + + $specFile = Join-Path $specsDir "$Name.spec" + $specContent | Out-File -FilePath $specFile -Encoding ascii + Write-Verbose "Generated spec file: $specFile" -Verbose + + # Log the spec file content + if ($env:GITHUB_ACTIONS -eq 'true') { + Write-Host "::group::RPM Spec File Content" + Write-Host $specContent + Write-Host "::endgroup::" + } else { + Write-Verbose "RPM Spec File Content:`n$specContent" -Verbose + } + + # Build RPM package + try { + # Use bash to properly handle rpmbuild arguments + # Add --target for cross-architecture builds + $targetArch = "" + if ($HostArchitecture -ne "x86_64" -and $HostArchitecture -ne "noarch") { + $targetArch = "--target $HostArchitecture" + } + $buildCmd = "rpmbuild -bb --quiet $targetArch --define '_topdir $rpmBuildRoot' --buildroot '$rpmBuildRoot/BUILDROOT' '$specFile'" + Write-Verbose "Running: $buildCmd" -Verbose + $Output = bash -c $buildCmd 2>&1 + $exitCode = $LASTEXITCODE + + if ($exitCode -ne 0) { + throw "rpmbuild failed with exit code $exitCode" + } + + # Find the generated RPM + $rpmFile = Get-ChildItem -Path (Join-Path $rpmsDir $HostArchitecture) -Filter "*.rpm" -ErrorAction Stop | + Sort-Object -Property LastWriteTime -Descending | + Select-Object -First 1 + + if ($rpmFile) { + # Copy RPM to current location + Copy-Item -Path $rpmFile.FullName -Destination $CurrentLocation -Force + $Output = @("Created package {:path=>""$($rpmFile.Name)""}") + } else { + throw "RPM file not found after build" + } + } + catch { + Write-Verbose -Message "!!!Handling error in rpmbuild!!!" -Verbose -ErrorAction SilentlyContinue + if ($Output) { + Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue + } + Get-Error -InputObject $_ + throw + } } - catch { - Write-Verbose -Message "!!!Handling error in FPM!!!" -Verbose -ErrorAction SilentlyContinue - Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue - Get-Error -InputObject $_ - throw + } else { + # Use fpm for DEB and macOS packages + $Arguments = @() + + $Arguments += Get-FpmArguments ` + -Name $Name ` + -Version $packageVersion ` + -Iteration $Iteration ` + -Description $Description ` + -Type $Type ` + -Dependencies $Dependencies ` + -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` + -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` + -Staging $Staging ` + -Destination $Destination ` + -ManGzipFile $ManGzipInfo.GzipFile ` + -ManDestination $ManGzipInfo.ManFile ` + -LinkInfo $Links ` + -AppsFolder $AppsFolder ` + -Distribution $DebDistro ` + -HostArchitecture $HostArchitecture ` + -ErrorAction Stop + + if ($PSCmdlet.ShouldProcess("Create $type package")) { + Write-Log "Creating package with fpm $Arguments..." + try { + $Output = Start-NativeExecution { fpm $Arguments } + } + catch { + Write-Verbose -Message "!!!Handling error in FPM!!!" -Verbose -ErrorAction SilentlyContinue + Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue + Get-Error -InputObject $_ + throw + } } } } finally { @@ -1295,6 +1379,16 @@ function New-UnixPackage { Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo mv $hack_dest $symlink_dest")) -VerboseOutputOnError } } + + # Clean up rpmbuild directory if it was created + if ($Type -eq 'rpm') { + $rpmBuildRoot = Join-Path $env:HOME "rpmbuild" + if (Test-Path $rpmBuildRoot) { + Write-Verbose "Cleaning up rpmbuild directory: $rpmBuildRoot" -Verbose + Remove-Item -Path $rpmBuildRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + if ($AfterScriptInfo.AfterInstallScript) { Remove-Item -ErrorAction 'silentlycontinue' $AfterScriptInfo.AfterInstallScript -Force } @@ -1439,6 +1533,165 @@ Class LinkInfo [string] $Destination } +function New-RpmSpec +{ + param( + [Parameter(Mandatory,HelpMessage='Package Name')] + [String]$Name, + + [Parameter(Mandatory,HelpMessage='Package Version')] + [String]$Version, + + [Parameter(Mandatory)] + [String]$Iteration, + + [Parameter(Mandatory,HelpMessage='Package description')] + [String]$Description, + + [Parameter(Mandatory,HelpMessage='Staging folder for installation files')] + [String]$Staging, + + [Parameter(Mandatory,HelpMessage='Install path on target machine')] + [String]$Destination, + + [Parameter(Mandatory,HelpMessage='The built and gzipped man file.')] + [String]$ManGzipFile, + + [Parameter(Mandatory,HelpMessage='The destination of the man file')] + [String]$ManDestination, + + [Parameter(Mandatory,HelpMessage='Symlink to powershell executable')] + [LinkInfo[]]$LinkInfo, + + [Parameter(Mandatory,HelpMessage='Packages required to install this package')] + [String[]]$Dependencies, + + [Parameter(Mandatory,HelpMessage='Script to run after the package installation.')] + [String]$AfterInstallScript, + + [Parameter(Mandatory,HelpMessage='Script to run after the package removal.')] + [String]$AfterRemoveScript, + + [String]$Distribution = 'rhel.7', + [string]$HostArchitecture + ) + + # RPM doesn't allow hyphens in version, so convert them to underscores + # e.g., "7.6.0-preview.6" becomes Version: 7.6.0_preview.6 + $rpmVersion = $Version -replace '-', '_' + + # Build Release field with distribution suffix (e.g., "1.cm" or "1.rh") + # Don't use RPM macros - build the full release string in PowerShell + $rpmRelease = "$Iteration.$Distribution" + + $specContent = @" +# RPM spec file for PowerShell +# Generated by PowerShell build system + +Name: $Name +Version: $rpmVersion +Release: $rpmRelease +Summary: PowerShell - Cross-platform automation and configuration tool/framework +License: MIT +URL: https://microsoft.com/powershell +AutoReq: no + +"@ + + # Only add BuildArch if not doing cross-architecture build + # For cross-arch builds, we'll rely on --target option + if ($HostArchitecture -eq "x86_64" -or $HostArchitecture -eq "noarch") { + $specContent += "BuildArch: $HostArchitecture`n`n" + } else { + # For cross-architecture builds, don't specify BuildArch in spec + # The --target option will handle the architecture + + # Disable automatic binary stripping for cross-arch builds + # The native /bin/strip on x86_64 cannot process ARM64 binaries and would fail with: + # "Unable to recognise the format of the input file" + # See: https://rpm-software-management.github.io/rpm/manual/macros.html + # __strip: This macro controls the command used for stripping binaries during the build process. + # /bin/true: A command that does nothing and always exits successfully, effectively bypassing the stripping process. + $specContent += "%define __strip /bin/true`n" + + # Disable debug package generation to prevent strip-related errors + # Debug packages require binary stripping which fails for cross-arch builds + # See: https://rpm-packaging-guide.github.io/#debugging + # See: https://docs.fedoraproject.org/en-US/packaging-guidelines/Debuginfo/#_useless_or_incomplete_debuginfo_packages_due_to_other_reasons + $specContent += "%global debug_package %{nil}`n`n" + } + + # Add dependencies + foreach ($dep in $Dependencies) { + $specContent += "Requires: $dep`n" + } + + $specContent += @" + +%description +$Description + +%prep +# No prep needed - files are already staged + +%build +# No build needed - binaries are pre-built + +%install +rm -rf `$RPM_BUILD_ROOT +mkdir -p `$RPM_BUILD_ROOT$Destination +mkdir -p `$RPM_BUILD_ROOT$(Split-Path -Parent $ManDestination) + +# Copy all files from staging to destination +cp -r $Staging/* `$RPM_BUILD_ROOT$Destination/ + +# Copy man page +cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination + +"@ + + # Add symlinks - we need to get the target of the temp symlink + foreach ($link in $LinkInfo) { + $linkDir = Split-Path -Parent $link.Destination + $specContent += "mkdir -p `$RPM_BUILD_ROOT$linkDir`n" + # For RPM, we copy the symlink itself (which fpm does by including it in the source) + # The symlink at $link.Source points to the actual target, so we'll copy it + # The -P flag preserves symlinks rather than copying their targets, which is critical for this operation. + $specContent += "cp -P $($link.Source) `$RPM_BUILD_ROOT$($link.Destination)`n" + } + + # Post-install script + $postInstallContent = Get-Content -Path $AfterInstallScript -Raw + $specContent += "`n%post`n" + $specContent += $postInstallContent + $specContent += "`n" + + # Post-uninstall script + $postUninstallContent = Get-Content -Path $AfterRemoveScript -Raw + $specContent += "%postun`n" + $specContent += $postUninstallContent + $specContent += "`n" + + # Files section + $specContent += "%files`n" + $specContent += "%defattr(-,root,root,-)`n" + $specContent += "$Destination/*`n" + $specContent += "$ManDestination`n" + + # Add symlinks to files + foreach ($link in $LinkInfo) { + $specContent += "$($link.Destination)`n" + } + + # Changelog with correct date format for RPM + $changelogDate = Get-Date -Format "ddd MMM dd yyyy" + $specContent += "`n%changelog`n" + $specContent += "* $changelogDate PowerShell Team - $rpmVersion-$rpmRelease`n" + $specContent += "- Automated build`n" + + return $specContent +} + function Get-FpmArguments { param( @@ -1651,7 +1904,16 @@ function Get-PackageDependencies function Test-Dependencies { - foreach ($Dependency in "fpm") { + # Note: RPM packages no longer require fpm; they use rpmbuild directly + # DEB packages still use fpm + $Dependencies = @() + + # Only check for fpm on Debian-based systems + if ($Environment.IsDebianFamily) { + $Dependencies += "fpm" + } + + foreach ($Dependency in $Dependencies) { if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { # These tools are not added to the path automatically on OpenSUSE 13.2 # try adding them to the path and re-tesing first From 9c8e9eb7e3b72bf82a84fccdd56960e2f1fc16e3 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 12 Feb 2026 13:46:33 -0800 Subject: [PATCH 184/275] [release/v7.5] Refactor: Centralize xUnit tests into reusable workflow and remove legacy verification (#26794) --- .github/actions/build/ci/action.yml | 14 --- .github/actions/test/verify_xunit/action.yml | 21 ---- .../instructions/build-configuration-guide.md | 95 +++++++++++++++++++ .../git-requirements-for-builds.md | 71 ++++++++++++++ .github/instructions/start-psbuild-basics.md | 92 ++++++++++++++++++ .../instructions/troubleshooting-builds.md | 92 ++++++++++++++++++ .../instructions/workflow-prerequisites.md | 91 ++++++++++++++++++ .github/workflows/linux-ci.yml | 22 ++--- .github/workflows/macos-ci.yml | 22 ++--- .github/workflows/windows-ci.yml | 22 ++--- .github/workflows/xunit-tests.yml | 53 +++++++++++ 11 files changed, 521 insertions(+), 74 deletions(-) delete mode 100644 .github/actions/test/verify_xunit/action.yml create mode 100644 .github/instructions/build-configuration-guide.md create mode 100644 .github/instructions/git-requirements-for-builds.md create mode 100644 .github/instructions/start-psbuild-basics.md create mode 100644 .github/instructions/troubleshooting-builds.md create mode 100644 .github/instructions/workflow-prerequisites.md create mode 100644 .github/workflows/xunit-tests.yml diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml index 93adaf6b17a..997be8b264c 100644 --- a/.github/actions/build/ci/action.yml +++ b/.github/actions/build/ci/action.yml @@ -31,22 +31,8 @@ runs: Import-Module .\tools\ci.psm1 Invoke-CIBuild shell: pwsh - - name: xUnit Tests - if: success() - continue-on-error: true - run: |- - Write-Verbose -Verbose "Running xUnit tests..." - Import-Module .\tools\ci.psm1 - Restore-PSOptions - Invoke-CIxUnit -SkipFailing - shell: pwsh - name: Upload build artifact uses: actions/upload-artifact@v4 with: name: build path: ${{ runner.workspace }}/build - - name: Upload xunit artifact - uses: actions/upload-artifact@v4 - with: - name: testResults-xunit - path: ${{ runner.workspace }}/xunit diff --git a/.github/actions/test/verify_xunit/action.yml b/.github/actions/test/verify_xunit/action.yml deleted file mode 100644 index fccca27182f..00000000000 --- a/.github/actions/test/verify_xunit/action.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: verify_xunit -description: 'Verify xUnit Results' - -runs: - using: composite - steps: - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - path: "${{ github.workspace }}" - - name: Capture artifacts directory - continue-on-error: true - run: dir "${{ github.workspace }}\testResults-xunit\*" -Recurse - shell: pwsh - - name: Test - if: success() - run: |- - Import-Module .\tools\ci.psm1 - $xUnitTestResultsFile = "${{ github.workspace }}\testResults-xunit\xUnitTestResults.xml" - Test-XUnitTestResults -TestResultsFile $xUnitTestResultsFile - shell: pwsh diff --git a/.github/instructions/build-configuration-guide.md b/.github/instructions/build-configuration-guide.md new file mode 100644 index 00000000000..d082bcbe774 --- /dev/null +++ b/.github/instructions/build-configuration-guide.md @@ -0,0 +1,95 @@ +# Build Configuration Guide + +## Choosing the Right Configuration + +### For Testing + +**Use: Default (Debug)** + +```yaml +- name: Build for Testing + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` + +**Why Debug:** +- Includes debugging symbols +- Better error messages +- Faster build times +- Suitable for xUnit and Pester tests + +**Do NOT use:** +- `-Configuration 'Release'` (unnecessary for tests) +- `-ReleaseTag` (not needed for tests) +- `-CI` (unless you specifically need Pester module) + +### For Release/Packaging + +**Use: Release with version tag** + +```yaml +- name: Build for Release + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + $releaseTag = Get-ReleaseTag + Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag +``` + +**Why Release:** +- Optimized binaries +- No debug symbols (smaller size) +- Production-ready + +### For Code Coverage + +**Use: CodeCoverage configuration** + +```yaml +- name: Build with Coverage + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild -Configuration 'CodeCoverage' +``` + +## Platform Considerations + +### All Platforms + +Same commands work across Linux, Windows, and macOS: + +```yaml +strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] +runs-on: ${{ matrix.os }} +steps: + - name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` + +### Output Locations + +**Linux/macOS:** +``` +src/powershell-unix/bin/Debug///publish/ +``` + +**Windows:** +``` +src/powershell-win-core/bin/Debug///publish/ +``` + +## Best Practices + +1. Use default configuration for testing +2. Avoid redundant parameters +3. Match configuration to purpose +4. Use `-CI` only when needed +5. Always specify `-ReleaseTag` for release or packaging builds diff --git a/.github/instructions/git-requirements-for-builds.md b/.github/instructions/git-requirements-for-builds.md new file mode 100644 index 00000000000..3c8cd91e7c7 --- /dev/null +++ b/.github/instructions/git-requirements-for-builds.md @@ -0,0 +1,71 @@ +# Git Requirements for Building PowerShell + +## Fetch Depth + +**Required:** `fetch-depth: 1000` + +The PowerShell build process uses `git describe --abbrev=60 --long` to generate version information. This requires access to git history and tags. + +### Problem + +Without sufficient fetch depth, builds fail with: +``` +error MSB3073: The command "git describe --abbrev=60 --long" exited with code 128. +``` + +### Solution + +Always use `fetch-depth: 1000` in the checkout step: + +```yaml +- name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 +``` + +## Tag Synchronization + +**Required:** `Sync-PSTags -AddRemoteIfMissing` + +The build process needs git tags to properly version the build. + +### Problem + +Without tag synchronization: +- Version information is incorrect +- Build versioning fails + +### Solution + +Include tag synchronization in the bootstrap step: + +```yaml +- name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Sync-PSTags -AddRemoteIfMissing +``` + +## Complete Example + +```yaml +steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing +``` diff --git a/.github/instructions/start-psbuild-basics.md b/.github/instructions/start-psbuild-basics.md new file mode 100644 index 00000000000..ae216a1584d --- /dev/null +++ b/.github/instructions/start-psbuild-basics.md @@ -0,0 +1,92 @@ +# Start-PSBuild Basics + +## Purpose + +`Start-PSBuild` builds PowerShell from source. It's defined in `build.psm1` and used in CI/CD workflows. + +## Default Usage + +For most scenarios, use with no parameters: + +```powershell +Import-Module ./tools/ci.psm1 +Start-PSBuild +``` + +**Default behavior:** +- Configuration: `Debug` +- PSModuleRestore: Enabled +- Runtime: Auto-detected for platform + +## Common Configurations + +### Debug Build (Default) + +```powershell +Start-PSBuild +``` + +Use for: +- Testing (xUnit, Pester) +- Development +- Debugging + +### Release Build + +```powershell +Start-PSBuild -Configuration 'Release' +``` + +Use for: +- Production packages +- Distribution +- Performance testing + +### Code Coverage Build + +```powershell +Start-PSBuild -Configuration 'CodeCoverage' +``` + +Use for: +- Code coverage analysis +- Test coverage reports + +## Common Parameters + +### -Configuration + +Values: `Debug`, `Release`, `CodeCoverage`, `StaticAnalysis` + +Default: `Debug` + +### -CI + +Restores Pester module for CI environments. + +```powershell +Start-PSBuild -CI +``` + +### -PSModuleRestore + +Now enabled by default. Use `-NoPSModuleRestore` to skip. + +### -ReleaseTag + +Specifies version tag for release builds: + +```powershell +$releaseTag = Get-ReleaseTag +Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag +``` + +## Workflow Example + +```yaml +- name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` diff --git a/.github/instructions/troubleshooting-builds.md b/.github/instructions/troubleshooting-builds.md new file mode 100644 index 00000000000..37f5df00912 --- /dev/null +++ b/.github/instructions/troubleshooting-builds.md @@ -0,0 +1,92 @@ +# Troubleshooting Build Issues + +## Git Describe Error + +**Error:** +``` +error MSB3073: The command "git describe --abbrev=60 --long" exited with code 128. +``` + +**Cause:** Insufficient git history (shallow clone) + +**Solution:** Add `fetch-depth: 1000` to checkout step + +```yaml +- name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 +``` + +## Version Information Incorrect + +**Symptom:** Build produces wrong version numbers + +**Cause:** Git tags not synchronized + +**Solution:** Run `Sync-PSTags -AddRemoteIfMissing`: + +```yaml +- name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing +``` + +## PowerShell Binary Not Built + +**Error:** +``` +Exception: CoreCLR pwsh.exe was not built +``` + +**Causes:** +1. Build failed (check logs) +2. Wrong configuration used +3. Build output location incorrect + +**Solutions:** +1. Check build logs for errors +2. Verify correct configuration for use case +3. Use default parameters: `Start-PSBuild` + +## Module Restore Issues + +**Symptom:** Slow build or module restore failures + +**Causes:** +- Network issues +- Module cache problems +- Package source unavailable + +**Solutions:** +1. Retry the build +2. Check network connectivity +3. Use `-NoPSModuleRestore` if modules not needed +4. Clear package cache if persistent + +## .NET SDK Not Found + +**Symptom:** Build can't find .NET SDK + +**Solution:** Ensure .NET setup step runs first: + +```yaml +- name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json +``` + +## Bootstrap Failures + +**Symptom:** Invoke-CIInstall fails + +**Causes:** +- Missing dependencies +- Network issues +- Platform-specific requirements not met + +**Solution:** Check prerequisites for your platform in build system docs diff --git a/.github/instructions/workflow-prerequisites.md b/.github/instructions/workflow-prerequisites.md new file mode 100644 index 00000000000..fe88abb384f --- /dev/null +++ b/.github/instructions/workflow-prerequisites.md @@ -0,0 +1,91 @@ +# Workflow Prerequisites for Building PowerShell + +## Required Steps Before Start-PSBuild + +These steps must run before calling `Start-PSBuild`: + +### 1. Checkout + +```yaml +- name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 # Required for version generation +``` + +### 2. Setup .NET + +```yaml +- name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json +``` + +### 3. Bootstrap + +```yaml +- name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing +``` + +## Complete Prerequisites Example + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing + + - name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` + +## Why Each Step Matters + +**Checkout with fetch-depth:** +- Build needs git history for versioning +- Without it: `git describe` fails + +**Setup .NET:** +- Provides SDK for building +- Uses version from global.json + +**Bootstrap:** +- Installs dependencies +- Syncs git tags +- Prepares build environment + +## Optional Steps + +### Environment Capture (Debugging) + +```yaml +- name: Capture Environment + run: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | Write-Verbose -Verbose + shell: pwsh +``` diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index e5cb91dac64..a27c5157eea 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -145,20 +145,16 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others - verify_xunit: - name: Verify xUnit test results + xunit_tests: + name: xUnit Tests needs: - - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v4.1.0 - with: - fetch-depth: 1000 - - name: Verify xUnit test results - uses: "./.github/actions/test/verify_xunit" + uses: ./.github/workflows/xunit-tests.yml + with: + runner_os: ubuntu-latest + test_results_artifact_name: testResults-xunit + analyze: permissions: @@ -222,7 +218,7 @@ jobs: ready_to_merge: name: Linux ready to merge needs: - - verify_xunit + - xunit_tests - linux_test_elevated_ci - linux_test_elevated_others - linux_test_unelevated_ci @@ -246,4 +242,4 @@ jobs: with: fetch-depth: 0 - name: Linux Packaging - uses: "./.github/actions/test/linux-packaging" + uses: "./.github/actions/test/linux-packaging" \ No newline at end of file diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index e0a85042053..996e76750b5 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -141,20 +141,16 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others - verify_xunit: - name: Verify xUnit test results + xunit_tests: + name: xUnit Tests needs: - - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v4.1.0 - with: - fetch-depth: 1000 - - name: Verify xUnit test results - uses: "./.github/actions/test/verify_xunit" + uses: ./.github/workflows/xunit-tests.yml + with: + runner_os: macos-15-large + test_results_artifact_name: testResults-xunit + PackageMac-macos_packaging: name: macOS packaging (bootstrap only) needs: @@ -174,7 +170,7 @@ jobs: ready_to_merge: name: macos ready to merge needs: - - verify_xunit + - xunit_tests - PackageMac-macos_packaging - macos_test_elevated_ci - macos_test_elevated_others @@ -183,4 +179,4 @@ jobs: if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: - needs_context: ${{ toJson(needs) }} + needs_context: ${{ toJson(needs) }} \ No newline at end of file diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index e960c0c255f..a3776fb26a6 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -145,20 +145,16 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others - verify_xunit: - name: Verify xUnit test results + xunit_tests: + name: xUnit Tests needs: - - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: windows-latest - steps: - - name: checkout - uses: actions/checkout@v4.1.0 - with: - fetch-depth: 1000 - - name: Verify xUnit test results - uses: "./.github/actions/test/verify_xunit" + uses: ./.github/workflows/xunit-tests.yml + with: + runner_os: windows-latest + test_results_artifact_name: testResults-xunit + windows_packaging: name: Windows Packaging needs: @@ -168,7 +164,7 @@ jobs: ready_to_merge: name: windows ready to merge needs: - - verify_xunit + - xunit_tests - windows_test_elevated_ci - windows_test_elevated_others - windows_test_unelevated_ci @@ -177,4 +173,4 @@ jobs: if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: - needs_context: ${{ toJson(needs) }} + needs_context: ${{ toJson(needs) }} \ No newline at end of file diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml new file mode 100644 index 00000000000..8bf5fd699d0 --- /dev/null +++ b/.github/workflows/xunit-tests.yml @@ -0,0 +1,53 @@ +name: xUnit Tests (Reusable) + +on: + workflow_call: + inputs: + runner_os: + description: 'Runner OS for xUnit tests' + type: string + required: false + default: ubuntu-latest + test_results_artifact_name: + description: 'Artifact name for xUnit test results directory' + type: string + required: false + default: testResults-xunit + +jobs: + xunit: + name: Run xUnit Tests + runs-on: ${{ inputs.runner_os }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing + + - name: Build PowerShell and run xUnit tests + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild + Write-Host "Running full xUnit test suite (no skipping)..." + Invoke-CIxUnit + Write-Host "Completed xUnit test run." + + - name: Upload xUnit results + uses: actions/upload-artifact@v4 + if: always() + with: + name: ${{ inputs.test_results_artifact_name }} + path: ${{ github.workspace }}/xUnitTestResults.xml From e0b3e8f48530973346601ecf81da5bb1bffcb5dd Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 12 Feb 2026 14:35:19 -0800 Subject: [PATCH 185/275] [release/v7.5] Fix R2R for fxdependent packaging (#26797) --- PowerShell.Common.props | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/PowerShell.Common.props b/PowerShell.Common.props index 7436c42158b..c8994ba2702 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -186,21 +186,25 @@ EnvironmentVariable;Global + false + false Global + true + true AppLocal + true + true - true - true true portable From 487acc58208d54609ad06af8db80b290ac1e418d Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 12 Feb 2026 15:28:51 -0800 Subject: [PATCH 186/275] [release/v7.5] Fix build to only enable ready-to-run for the Release configuration (#26798) --- PowerShell.Common.props | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/PowerShell.Common.props b/PowerShell.Common.props index c8994ba2702..07d22b49cb9 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -193,12 +193,20 @@ Global + + + + true true AppLocal + + + + true true From 6174a09d241768365d240bb953b364a54fa2731e Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 12 Feb 2026 16:10:49 -0800 Subject: [PATCH 187/275] [release/v7.5] Refactor analyze job to reusable workflow and enable on Windows CI (#26799) --- .github/workflows/analyze-reusable.yml | 76 ++++++++++++++++++++++++++ .github/workflows/linux-ci.yml | 64 +++------------------- .github/workflows/windows-ci.yml | 13 ++++- tools/ci.psm1 | 7 ++- 4 files changed, 102 insertions(+), 58 deletions(-) create mode 100644 .github/workflows/analyze-reusable.yml diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml new file mode 100644 index 00000000000..1797e2234a6 --- /dev/null +++ b/.github/workflows/analyze-reusable.yml @@ -0,0 +1,76 @@ +name: CodeQL Analysis (Reusable) + +on: + workflow_call: + inputs: + runner_os: + description: 'Runner OS for CodeQL analysis' + type: string + required: false + default: ubuntu-latest + +permissions: + actions: read # for github/codeql-action/init to get workflow details + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/analyze to upload SARIF results + +env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_NOLOGO: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + +jobs: + analyze: + name: Analyze + runs-on: ${{ inputs.runner_os }} + + strategy: + fail-fast: false + matrix: + # Override automatic language detection by changing the below list + # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] + language: ['csharp'] + # Learn more... + # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection + + steps: + - name: Checkout repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: '0' + + - uses: actions/setup-dotnet@v5 + with: + global-json-file: ./global.json + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + - run: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + name: Capture Environment + shell: pwsh + + - run: | + Import-Module .\tools\ci.psm1 + Invoke-CIInstall -SkipUser + name: Bootstrap + shell: pwsh + + - run: | + Import-Module .\tools\ci.psm1 + Invoke-CIBuild -Configuration 'StaticAnalysis' + name: Build + shell: pwsh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index a27c5157eea..d6b86bfa75f 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -155,65 +155,17 @@ jobs: runner_os: ubuntu-latest test_results_artifact_name: testResults-xunit - analyze: - permissions: - actions: read # for github/codeql-action/init to get workflow details - contents: read # for actions/checkout to fetch code - security-events: write # for github/codeql-action/analyze to upload SARIF results - name: Analyze - runs-on: ubuntu-latest + name: CodeQL Analysis needs: changes if: ${{ needs.changes.outputs.source == 'true' }} - - strategy: - fail-fast: false - matrix: - # Override automatic language detection by changing the below list - # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - language: ['csharp'] - # Learn more... - # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection - - steps: - - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: '0' - - - uses: actions/setup-dotnet@v4 - with: - global-json-file: ./global.json - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - - run: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - name: Capture Environment - shell: pwsh - - - run: | - Import-Module .\tools\ci.psm1 - Invoke-CIInstall -SkipUser - name: Bootstrap - shell: pwsh - - - run: | - Import-Module .\tools\ci.psm1 - Invoke-CIBuild - name: Build - shell: pwsh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 + uses: ./.github/workflows/analyze-reusable.yml + permissions: + actions: read + contents: read + security-events: write + with: + runner_os: ubuntu-latest ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index a3776fb26a6..ac362be7153 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -154,7 +154,17 @@ jobs: with: runner_os: windows-latest test_results_artifact_name: testResults-xunit - + analyze: + name: CodeQL Analysis + needs: changes + if: ${{ needs.changes.outputs.source == 'true' }} + uses: ./.github/workflows/analyze-reusable.yml + permissions: + actions: read + contents: read + security-events: write + with: + runner_os: windows-latest windows_packaging: name: Windows Packaging needs: @@ -169,6 +179,7 @@ jobs: - windows_test_elevated_others - windows_test_unelevated_ci - windows_test_unelevated_others + - analyze - windows_packaging if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 9e95e68c843..44651c26109 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -101,6 +101,11 @@ function Invoke-CIFull # Implements the CI 'build_script' step function Invoke-CIBuild { + param( + [ValidateSet('Debug', 'Release', 'CodeCoverage', 'StaticAnalysis')] + [string]$Configuration = 'Release' + ) + $releaseTag = Get-ReleaseTag # check to be sure our test tags are correct $result = Get-PesterTag @@ -115,7 +120,7 @@ function Invoke-CIBuild Start-PSBuild -Configuration 'CodeCoverage' -PSModuleRestore -CI -ReleaseTag $releaseTag } - Start-PSBuild -PSModuleRestore -Configuration 'Release' -CI -ReleaseTag $releaseTag -UseNuGetOrg + Start-PSBuild -PSModuleRestore -Configuration $Configuration -CI -ReleaseTag $releaseTag -UseNuGetOrg Save-PSOptions $options = (Get-PSOptions) From c96a282536dd8abb4a03fb0db71f8b512669c490 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 12 Feb 2026 16:11:06 -0800 Subject: [PATCH 188/275] [release/v7.5] Replace fpm with native macOS packaging tools (pkgbuild/productbuild) (#26801) --- .../instructions/build-configuration-guide.md | 48 ++- .../start-native-execution.instructions.md | 149 ++++++++ .github/workflows/macos-ci.yml | 59 ++- docs/maintainers/releasing.md | 17 +- tools/packaging/packaging.psm1 | 360 ++++++++++++++---- .../releaseTests/macOSPackage.tests.ps1 | 162 ++++++++ 6 files changed, 707 insertions(+), 88 deletions(-) create mode 100644 .github/instructions/start-native-execution.instructions.md create mode 100644 tools/packaging/releaseTests/macOSPackage.tests.ps1 diff --git a/.github/instructions/build-configuration-guide.md b/.github/instructions/build-configuration-guide.md index d082bcbe774..c31f8139c62 100644 --- a/.github/instructions/build-configuration-guide.md +++ b/.github/instructions/build-configuration-guide.md @@ -27,13 +27,15 @@ ### For Release/Packaging -**Use: Release with version tag** +**Use: Release with version tag and public NuGet feeds** ```yaml - name: Build for Release shell: pwsh run: | + Import-Module ./build.psm1 Import-Module ./tools/ci.psm1 + Switch-PSNugetConfig -Source Public $releaseTag = Get-ReleaseTag Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag ``` @@ -43,6 +45,11 @@ - No debug symbols (smaller size) - Production-ready +**Why Switch-PSNugetConfig -Source Public:** +- Switches NuGet package sources to public feeds (nuget.org and public Azure DevOps feeds) +- Required for CI/CD environments that don't have access to private feeds +- Uses publicly available packages instead of Microsoft internal feeds + ### For Code Coverage **Use: CodeCoverage configuration** @@ -93,3 +100,42 @@ src/powershell-win-core/bin/Debug///publish/ 3. Match configuration to purpose 4. Use `-CI` only when needed 5. Always specify `-ReleaseTag` for release or packaging builds +6. Use `Switch-PSNugetConfig -Source Public` in CI/CD for release builds + +## NuGet Feed Configuration + +### Switch-PSNugetConfig + +The `Switch-PSNugetConfig` function in `build.psm1` manages NuGet package source configuration. + +**Available Sources:** + +- **Public**: Uses public feeds (nuget.org and public Azure DevOps feeds) + - Required for: CI/CD environments, public builds, packaging + - Does not require authentication + +- **Private**: Uses internal PowerShell team feeds + - Required for: Internal development with preview packages + - Requires authentication credentials + +- **NuGetOnly**: Uses only nuget.org + - Required for: Minimal dependency scenarios + +**Usage:** + +```powershell +# Switch to public feeds (most common for CI/CD) +Switch-PSNugetConfig -Source Public + +# Switch to private feeds with authentication +Switch-PSNugetConfig -Source Private -UserName $userName -ClearTextPAT $pat + +# Switch to nuget.org only +Switch-PSNugetConfig -Source NuGetOnly +``` + +**When to Use:** + +- **Always use `-Source Public`** before building in CI/CD workflows +- Use before any build that will create packages for distribution +- Use in forks or environments without access to Microsoft internal feeds diff --git a/.github/instructions/start-native-execution.instructions.md b/.github/instructions/start-native-execution.instructions.md new file mode 100644 index 00000000000..347e496b3bf --- /dev/null +++ b/.github/instructions/start-native-execution.instructions.md @@ -0,0 +1,149 @@ +--- +applyTo: + - "**/*.ps1" + - "**/*.psm1" +--- + +# Using Start-NativeExecution for Native Command Execution + +## Purpose + +`Start-NativeExecution` is the standard function for executing native commands (external executables) in PowerShell scripts within this repository. It provides consistent error handling and better diagnostics when native commands fail. + +## When to Use + +Use `Start-NativeExecution` whenever you need to: +- Execute external commands (e.g., `git`, `dotnet`, `pkgbuild`, `productbuild`, `fpm`, `rpmbuild`) +- Ensure proper exit code checking +- Get better error messages with caller information +- Handle verbose output on error + +## Basic Usage + +```powershell +Start-NativeExecution { + git clone https://github.com/PowerShell/PowerShell.git +} +``` + +## With Parameters + +Use backticks for line continuation within the script block: + +```powershell +Start-NativeExecution { + pkgbuild --root $pkgRoot ` + --identifier $pkgIdentifier ` + --version $Version ` + --scripts $scriptsDir ` + $outputPath +} +``` + +## Common Parameters + +### -VerboseOutputOnError + +Captures command output and displays it only if the command fails: + +```powershell +Start-NativeExecution -VerboseOutputOnError { + dotnet build --configuration Release +} +``` + +### -IgnoreExitcode + +Allows the command to fail without throwing an exception: + +```powershell +Start-NativeExecution -IgnoreExitcode { + git diff --exit-code # Returns 1 if differences exist +} +``` + +## Availability + +The function is defined in `tools/buildCommon/startNativeExecution.ps1` and is available in: +- `build.psm1` (dot-sourced automatically) +- `tools/packaging/packaging.psm1` (dot-sourced automatically) +- Test modules that include `HelpersCommon.psm1` + +To use in other scripts, dot-source the function: + +```powershell +. "$PSScriptRoot/../buildCommon/startNativeExecution.ps1" +``` + +## Error Handling + +When a native command fails (non-zero exit code), `Start-NativeExecution`: +1. Captures the exit code +2. Identifies the calling location (file and line number) +3. Throws a descriptive error with full context + +Example error message: +``` +Execution of {git clone ...} by /path/to/script.ps1: line 42 failed with exit code 1 +``` + +## Examples from the Codebase + +### Git Operations +```powershell +Start-NativeExecution { + git fetch --tags --quiet upstream +} +``` + +### Build Operations +```powershell +Start-NativeExecution -VerboseOutputOnError { + dotnet publish --configuration Release +} +``` + +### Packaging Operations +```powershell +Start-NativeExecution -VerboseOutputOnError { + pkgbuild --root $pkgRoot --identifier $pkgId --version $version $outputPath +} +``` + +### Permission Changes +```powershell +Start-NativeExecution { + find $staging -type d | xargs chmod 755 + find $staging -type f | xargs chmod 644 +} +``` + +## Anti-Patterns + +**Don't do this:** +```powershell +& somecommand $args +if ($LASTEXITCODE -ne 0) { + throw "Command failed" +} +``` + +**Do this instead:** +```powershell +Start-NativeExecution { + somecommand $args +} +``` + +## Best Practices + +1. **Always use Start-NativeExecution** for native commands to ensure consistent error handling +2. **Use -VerboseOutputOnError** for commands with useful diagnostic output +3. **Use backticks for readability** when commands have multiple arguments +4. **Don't capture output unnecessarily** - let the function handle it +5. **Use -IgnoreExitcode sparingly** - only when non-zero exit codes are expected and acceptable + +## Related Documentation + +- Source: `tools/buildCommon/startNativeExecution.ps1` +- Blog post: https://mnaoumov.wordpress.com/2015/01/11/execution-of-external-commands-in-powershell-done-right/ diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 996e76750b5..bb7faacfde0 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -152,7 +152,7 @@ jobs: test_results_artifact_name: testResults-xunit PackageMac-macos_packaging: - name: macOS packaging (bootstrap only) + name: macOS packaging and testing needs: - changes if: ${{ needs.changes.outputs.source == 'true' }} @@ -160,13 +160,64 @@ jobs: - macos-latest steps: - name: checkout - uses: actions/checkout@v4.1.0 - - name: Bootstrap packaging - if: success() || failure() + uses: actions/checkout@v5 + with: + fetch-depth: 1000 + - uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + if: success() run: |- import-module ./build.psm1 start-psbootstrap -Scenario package shell: pwsh + - name: Build PowerShell and Create macOS package + if: success() + run: |- + import-module ./build.psm1 + import-module ./tools/ci.psm1 + import-module ./tools/packaging/packaging.psm1 + Switch-PSNugetConfig -Source Public + Sync-PSTags -AddRemoteIfMissing + $releaseTag = Get-ReleaseTag + Start-PSBuild -Configuration Release -PSModuleRestore -ReleaseTag $releaseTag + $macOSRuntime = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'osx-arm64' } else { 'osx-x64' } + Start-PSPackage -Type osxpkg -ReleaseTag $releaseTag -MacOSRuntime $macOSRuntime -SkipReleaseChecks + shell: pwsh + - name: Test package contents + if: success() + run: |- + $env:PACKAGE_FOLDER = Get-Location + $testResultsPath = Join-Path $env:RUNNER_WORKSPACE "testResults" + if (-not (Test-Path $testResultsPath)) { + New-Item -ItemType Directory -Path $testResultsPath -Force | Out-Null + } + Import-Module Pester + $pesterConfig = New-PesterConfiguration + $pesterConfig.Run.Path = './tools/packaging/releaseTests/macOSPackage.tests.ps1' + $pesterConfig.Run.PassThru = $true + $pesterConfig.Output.Verbosity = 'Detailed' + $pesterConfig.TestResult.Enabled = $true + $pesterConfig.TestResult.OutputFormat = 'NUnitXml' + $pesterConfig.TestResult.OutputPath = Join-Path $testResultsPath "macOSPackage.xml" + $result = Invoke-Pester -Configuration $pesterConfig + if ($result.FailedCount -gt 0) { + throw "Package validation failed with $($result.FailedCount) failed test(s)" + } + shell: pwsh + - name: Publish and Upload Pester Test Results + if: always() + uses: "./.github/actions/test/process-pester-results" + with: + name: "macOSPackage" + testResultsFolder: "${{ runner.workspace }}/testResults" + - name: Upload package artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: macos-package + path: "*.pkg" ready_to_merge: name: macos ready to merge needs: diff --git a/docs/maintainers/releasing.md b/docs/maintainers/releasing.md index 5aae87582c9..3562962e68f 100644 --- a/docs/maintainers/releasing.md +++ b/docs/maintainers/releasing.md @@ -72,11 +72,18 @@ The output of `Start-PSBuild` includes a `powershell.exe` executable which can s #### Linux / macOS The `Start-PSPackage` function delegates to `New-UnixPackage`. -It relies on the [Effing Package Management][fpm] project, -which makes building packages for any (non-Windows) platform a breeze. -Similarly, the PowerShell man-page is generated from the Markdown-like file + +For **Linux** (Debian-based distributions), it relies on the [Effing Package Management][fpm] project, +which makes building packages a breeze. + +For **macOS**, it uses native packaging tools (`pkgbuild` and `productbuild`) from Xcode Command Line Tools, +eliminating the need for Ruby or fpm. + +For **Linux** (Red Hat-based distributions), it uses `rpmbuild` directly. + +The PowerShell man-page is generated from the Markdown-like file [`assets/pwsh.1.ronn`][man] using [Ronn][]. -The function `Start-PSBootstrap -Package` will install both these tools. +The function `Start-PSBootstrap -Package` will install these tools. To modify any property of the packages, edit the `New-UnixPackage` function. Please also refer to the function for details on the package properties @@ -131,7 +138,7 @@ Without `-Name` specified, the primary `powershell` package will instead be created. [fpm]: https://github.com/jordansissel/fpm -[man]: ../../assets/pwsh.1.ronn +[man]: ../../assets/manpage/pwsh.1.ronn [ronn]: https://github.com/rtomayko/ronn ### Build and Packaging Examples diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 195f3e8187e..b6d2b046509 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1,6 +1,8 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +. "$PSScriptRoot\..\buildCommon\startNativeExecution.ps1" + $Environment = Get-EnvironmentInformation $RepoRoot = (Resolve-Path -Path "$PSScriptRoot/../..").Path @@ -1197,19 +1199,7 @@ function New-UnixPackage { # Generate After Install and After Remove scripts $AfterScriptInfo = New-AfterScripts -Link $Link -Distribution $DebDistro -Destination $Destination - # there is a weird bug in fpm - # if the target of the powershell symlink exists, `fpm` aborts - # with a `utime` error on macOS. - # so we move it to make symlink broken - # refers to executable, does not vary by channel - $symlink_dest = "$Destination/pwsh" - $hack_dest = "./_fpm_symlink_hack_powershell" - if ($Environment.IsMacOS) { - if (Test-Path $symlink_dest) { - Write-Warning "Move $symlink_dest to $hack_dest (fpm utime bug)" - Start-NativeExecution ([ScriptBlock]::Create("$sudo mv $symlink_dest $hack_dest")) - } - } + # Note: The fpm symlink workaround is no longer needed with native macOS packaging tools # Generate gzip of man file $ManGzipInfo = New-ManGzip -IsPreview:$IsPreview -IsLTS:$LTS @@ -1329,8 +1319,38 @@ function New-UnixPackage { throw } } + } elseif ($Type -eq 'osxpkg') { + # Use native macOS packaging tools + if ($PSCmdlet.ShouldProcess("Create macOS package with pkgbuild/productbuild")) { + Write-Log "Creating macOS package with native tools..." + + $macPkgArgs = @{ + Name = $Name + Version = $packageVersion + Iteration = $Iteration + Staging = $Staging + Destination = $Destination + ManGzipFile = $ManGzipInfo.GzipFile + ManDestination = $ManGzipInfo.ManFile + LinkInfo = $Links + AfterInstallScript = $AfterScriptInfo.AfterInstallScript + AppsFolder = $AppsFolder + HostArchitecture = $HostArchitecture + CurrentLocation = $CurrentLocation + } + + try { + $packageFile = New-MacOSPackage @macPkgArgs + $Output = @("Created package {:path=>""$($packageFile.Name)""}") + } + catch { + Write-Verbose -Message "!!!Handling error in macOS packaging!!!" -Verbose -ErrorAction SilentlyContinue + Get-Error -InputObject $_ + throw + } + } } else { - # Use fpm for DEB and macOS packages + # Use fpm for DEB packages $Arguments = @() $Arguments += Get-FpmArguments ` @@ -1372,12 +1392,6 @@ function New-UnixPackage { { Clear-MacOSLauncher } - - # this is continuation of a fpm hack for a weird bug - if (Test-Path $hack_dest) { - Write-Warning "Move $hack_dest to $symlink_dest (fpm utime bug)" - Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo mv $hack_dest $symlink_dest")) -VerboseOutputOnError - } } # Clean up rpmbuild directory if it was created @@ -1401,12 +1415,9 @@ function New-UnixPackage { # Magic to get path output $createdPackage = Get-Item (Join-Path $CurrentLocation (($Output[-1] -split ":path=>")[-1] -replace '["{}]')) - if ($Environment.IsMacOS) { - if ($PSCmdlet.ShouldProcess("Add distribution information and Fix PackageName")) - { - $createdPackage = New-MacOsDistributionPackage -FpmPackage $createdPackage -HostArchitecture $HostArchitecture -IsPreview:$IsPreview - } - } + # For macOS with native tools, the package is already in the correct format + # For macOS with fpm (no longer used), we would need New-MacOsDistributionPackage + # For other platforms, the package name from fpm/rpmbuild is sufficient if (Test-Path $createdPackage) { @@ -1451,14 +1462,27 @@ Function New-LinkInfo function New-MacOsDistributionPackage { + [CmdletBinding(SupportsShouldProcess=$true)] param( - [Parameter(Mandatory,HelpMessage='The FileInfo of the file created by FPM')] - [System.IO.FileInfo]$FpmPackage, + [Parameter(Mandatory,HelpMessage='The FileInfo of the component package')] + [System.IO.FileInfo]$ComponentPackage, + + [Parameter(Mandatory,HelpMessage='Package name for the output file')] + [string]$PackageName, + + [Parameter(Mandatory,HelpMessage='Package version')] + [string]$Version, + + [Parameter(Mandatory,HelpMessage='Output directory for the final package')] + [string]$OutputDirectory, [Parameter(HelpMessage='x86_64 for Intel or arm64 for Apple Silicon')] [ValidateSet("x86_64", "arm64")] [string] $HostArchitecture = "x86_64", + [Parameter(HelpMessage='Package identifier')] + [string]$PackageIdentifier, + [Switch] $IsPreview ) @@ -1467,64 +1491,81 @@ function New-MacOsDistributionPackage throw 'New-MacOsDistributionPackage is only supported on macOS!' } - $packageName = Split-Path -Leaf -Path $FpmPackage - # Create a temp directory to store the needed files $tempDir = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName()) New-Item -ItemType Directory -Path $tempDir -Force > $null $resourcesDir = Join-Path -Path $tempDir -ChildPath 'resources' New-Item -ItemType Directory -Path $resourcesDir -Force > $null - #Copy background file to temp directory + + # Copy background file to temp directory $backgroundFile = "$RepoRoot/assets/macDialog.png" - Copy-Item -Path $backgroundFile -Destination $resourcesDir - # Move the current package to the temp directory - $tempPackagePath = Join-Path -Path $tempDir -ChildPath $packageName - Move-Item -Path $FpmPackage -Destination $tempPackagePath -Force - - # Add the OS information to the macOS package file name. - $packageExt = [System.IO.Path]::GetExtension($FpmPackage.Name) - - # get the package name from fpm without the extension, but replace powershell-preview at the beginning of the name with powershell. - $packageNameWithoutExt = [System.IO.Path]::GetFileNameWithoutExtension($FpmPackage.Name) -replace '^powershell\-preview' , 'powershell' - - $newPackageName = "{0}-{1}{2}" -f $packageNameWithoutExt, $script:Options.Runtime, $packageExt - $newPackagePath = Join-Path $FpmPackage.DirectoryName $newPackageName - - # -Force is not deleting the NewName if it exists, so delete it if it does - if ($Force -and (Test-Path -Path $newPackagePath)) - { - Remove-Item -Force $newPackagePath + if (Test-Path $backgroundFile) { + Copy-Item -Path $backgroundFile -Destination $resourcesDir -Force } + + # Copy the component package to temp directory + $componentFileName = Split-Path -Leaf -Path $ComponentPackage + $tempComponentPath = Join-Path -Path $tempDir -ChildPath $componentFileName + Copy-Item -Path $ComponentPackage -Destination $tempComponentPath -Force # Create the distribution xml $distributionXmlPath = Join-Path -Path $tempDir -ChildPath 'powershellDistribution.xml' - $packageId = Get-MacOSPackageId -IsPreview:$IsPreview.IsPresent + # Get package ID if not provided + if (-not $PackageIdentifier) { + $PackageIdentifier = Get-MacOSPackageId -IsPreview:$IsPreview.IsPresent + } + # Minimum OS version + $minOSVersion = "11.0" # macOS Big Sur minimum + # format distribution template with: # 0 - title # 1 - version - # 2 - package path + # 2 - package path (component package filename) # 3 - minimum os version # 4 - Package Identifier # 5 - host architecture (x86_64 for Intel or arm64 for Apple Silicon) - $PackagingStrings.OsxDistributionTemplate -f "PowerShell - $packageVersion", $packageVersion, $packageName, '10.14', $packageId, $HostArchitecture | Out-File -Encoding ascii -FilePath $distributionXmlPath -Force + $PackagingStrings.OsxDistributionTemplate -f $PackageName, $Version, $componentFileName, $minOSVersion, $PackageIdentifier, $HostArchitecture | Out-File -Encoding utf8 -FilePath $distributionXmlPath -Force - Write-Log "Applying distribution.xml to package..." - Push-Location $tempDir - try - { - # productbuild is an xcode command line tool, and those tools are installed when you install brew - Start-NativeExecution -sb {productbuild --distribution $distributionXmlPath --resources $resourcesDir $newPackagePath} -VerboseOutputOnError + # Build final package path + $finalPackagePath = Join-Path $OutputDirectory "$PackageName-$Version-osx-$HostArchitecture.pkg" + + # Remove existing package if it exists + if (Test-Path $finalPackagePath) { + Write-Warning "Removing existing package: $finalPackagePath" + Remove-Item $finalPackagePath -Force } - finally - { - Pop-Location - Remove-Item -Path $tempDir -Recurse -Force + + if ($PSCmdlet.ShouldProcess("Build product package with productbuild")) { + Write-Log "Applying distribution.xml to package..." + Push-Location $tempDir + try + { + # productbuild is an xcode command line tool + Start-NativeExecution -VerboseOutputOnError { + productbuild --distribution $distributionXmlPath ` + --package-path $tempDir ` + --resources $resourcesDir ` + $finalPackagePath + } + + if (Test-Path $finalPackagePath) { + Write-Log "Successfully created macOS package: $finalPackagePath" + } + else { + throw "Package was not created at expected location: $finalPackagePath" + } + } + finally + { + Pop-Location + Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue + } } - return (Get-Item $newPackagePath) + return (Get-Item $finalPackagePath) } Class LinkInfo @@ -1692,6 +1733,157 @@ cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination return $specContent } +function New-MacOSPackage +{ + [CmdletBinding(SupportsShouldProcess=$true)] + param( + [Parameter(Mandatory)] + [string]$Name, + + [Parameter(Mandatory)] + [string]$Version, + + [Parameter(Mandatory)] + [string]$Iteration, + + [Parameter(Mandatory)] + [string]$Staging, + + [Parameter(Mandatory)] + [string]$Destination, + + [Parameter(Mandatory)] + [string]$ManGzipFile, + + [Parameter(Mandatory)] + [string]$ManDestination, + + [Parameter(Mandatory)] + [LinkInfo[]]$LinkInfo, + + [Parameter(Mandatory)] + [string]$AfterInstallScript, + + [Parameter(Mandatory)] + [string]$AppsFolder, + + [Parameter(Mandatory)] + [string]$HostArchitecture, + + [string]$CurrentLocation = (Get-Location) + ) + + Write-Log "Creating macOS package using pkgbuild and productbuild..." + + # Create a temporary directory for package building + $tempRoot = New-TempFolder + $componentPkgPath = Join-Path $tempRoot "component.pkg" + $scriptsDir = Join-Path $tempRoot "scripts" + $resourcesDir = Join-Path $tempRoot "resources" + $distributionFile = Join-Path $tempRoot "distribution.xml" + + try { + # Create scripts directory + New-Item -ItemType Directory -Path $scriptsDir -Force | Out-Null + + # Copy and prepare the postinstall script + $postInstallPath = Join-Path $scriptsDir "postinstall" + Copy-Item -Path $AfterInstallScript -Destination $postInstallPath -Force + Start-NativeExecution { + chmod 755 $postInstallPath + } + + # Create a temporary directory for the package root + $pkgRoot = Join-Path $tempRoot "pkgroot" + New-Item -ItemType Directory -Path $pkgRoot -Force | Out-Null + + # Copy staging files to destination path in package root + $destInPkg = Join-Path $pkgRoot $Destination + New-Item -ItemType Directory -Path $destInPkg -Force | Out-Null + Write-Verbose "Copying staging files from $Staging to $destInPkg" -Verbose + Copy-Item -Path "$Staging/*" -Destination $destInPkg -Recurse -Force + + # Create man page directory structure + $manDir = Join-Path $pkgRoot (Split-Path $ManDestination -Parent) + New-Item -ItemType Directory -Path $manDir -Force | Out-Null + Copy-Item -Path $ManGzipFile -Destination (Join-Path $pkgRoot $ManDestination) -Force + + # Create symlinks in package root + # The LinkInfo contains Source (a temp file that IS a symlink) and Destination (where to install it) + foreach ($link in $LinkInfo) { + $linkDestDir = Join-Path $pkgRoot (Split-Path $link.Destination -Parent) + New-Item -ItemType Directory -Path $linkDestDir -Force | Out-Null + $finalLinkPath = Join-Path $pkgRoot $link.Destination + + Write-Verbose "Creating symlink at $finalLinkPath" -Verbose + + # Remove if exists + if (Test-Path $finalLinkPath) { + Remove-Item $finalLinkPath -Force + } + + # Get the target of the original symlink and recreate it in the package root + if (Test-Path $link.Source) { + $linkTarget = (Get-Item $link.Source).Target + if ($linkTarget) { + Write-Verbose "Creating symlink to target: $linkTarget" -Verbose + New-Item -ItemType SymbolicLink -Path $finalLinkPath -Target $linkTarget -Force | Out-Null + } else { + Write-Warning "Could not determine target for symlink at $($link.Source), copying file instead" + Copy-Item -Path $link.Source -Destination $finalLinkPath -Force + } + } else { + Write-Warning "Source symlink $($link.Source) does not exist" + } + } + + # Copy launcher app folder if provided + if ($AppsFolder) { + $appsInPkg = Join-Path $pkgRoot "Applications" + New-Item -ItemType Directory -Path $appsInPkg -Force | Out-Null + Write-Verbose "Copying launcher app from $AppsFolder to $appsInPkg" -Verbose + Copy-Item -Path "$AppsFolder/*" -Destination $appsInPkg -Recurse -Force + } + + # Build the component package using pkgbuild + $pkgIdentifier = Get-MacOSPackageId -IsPreview:($Name -like '*-preview') + + if ($PSCmdlet.ShouldProcess("Build component package with pkgbuild")) { + Write-Log "Running pkgbuild to create component package..." + + Start-NativeExecution -VerboseOutputOnError { + pkgbuild --root $pkgRoot ` + --identifier $pkgIdentifier ` + --version $Version ` + --scripts $scriptsDir ` + --install-location "/" ` + $componentPkgPath + } + + Write-Verbose "Component package created: $componentPkgPath" -Verbose + } + + # Create the final distribution package using the refactored function + $distributionPackage = New-MacOsDistributionPackage ` + -ComponentPackage (Get-Item $componentPkgPath) ` + -PackageName $Name ` + -Version $Version ` + -OutputDirectory $CurrentLocation ` + -HostArchitecture $HostArchitecture ` + -PackageIdentifier $pkgIdentifier ` + -IsPreview:($Name -like '*-preview') + + return $distributionPackage + } + finally { + # Clean up temporary directory + if (Test-Path $tempRoot) { + Write-Verbose "Cleaning up temporary directory: $tempRoot" -Verbose + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } +} + function Get-FpmArguments { param( @@ -1905,6 +2097,7 @@ function Get-PackageDependencies function Test-Dependencies { # Note: RPM packages no longer require fpm; they use rpmbuild directly + # macOS packages use pkgbuild and productbuild from Xcode Command Line Tools # DEB packages still use fpm $Dependencies = @() @@ -1913,22 +2106,31 @@ function Test-Dependencies $Dependencies += "fpm" } + # Check for macOS packaging tools + if ($Environment.IsMacOS) { + $Dependencies += "pkgbuild" + $Dependencies += "productbuild" + } + foreach ($Dependency in $Dependencies) { if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { - # These tools are not added to the path automatically on OpenSUSE 13.2 - # try adding them to the path and re-tesing first - [string] $gemsPath = $null - [string] $depenencyPath = $null - $gemsPath = Get-ChildItem -Path /usr/lib64/ruby/gems | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName - if ($gemsPath) { - $depenencyPath = Get-ChildItem -Path (Join-Path -Path $gemsPath -ChildPath "gems" -AdditionalChildPath $Dependency) -Recurse | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty DirectoryName - $originalPath = $env:PATH - $env:PATH = $ENV:PATH +":" + $depenencyPath - if ((precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { - continue - } - else { - $env:PATH = $originalPath + # For Debian systems, try adding ruby gems to the path + if ($Environment.IsDebianFamily) { + # These tools are not added to the path automatically on OpenSUSE 13.2 + # try adding them to the path and re-tesing first + [string] $gemsPath = $null + [string] $depenencyPath = $null + $gemsPath = Get-ChildItem -Path /usr/lib64/ruby/gems | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName + if ($gemsPath) { + $depenencyPath = Get-ChildItem -Path (Join-Path -Path $gemsPath -ChildPath "gems" -AdditionalChildPath $Dependency) -Recurse | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty DirectoryName + $originalPath = $env:PATH + $env:PATH = $ENV:PATH +":" + $depenencyPath + if ((precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { + continue + } + else { + $env:PATH = $originalPath + } } } @@ -2081,10 +2283,12 @@ function New-MacOSLauncher # Set permissions for plist and shell script. Start-NativeExecution { chmod 644 $plist + } + Start-NativeExecution { chmod 755 $shellscript } - # Add app folder to fpm paths. + # Return the app folder path for packaging $appsfolder = (Resolve-Path -Path "$macosapp/..").Path return $appsfolder diff --git a/tools/packaging/releaseTests/macOSPackage.tests.ps1 b/tools/packaging/releaseTests/macOSPackage.tests.ps1 new file mode 100644 index 00000000000..c1de1091562 --- /dev/null +++ b/tools/packaging/releaseTests/macOSPackage.tests.ps1 @@ -0,0 +1,162 @@ +Describe "Verify macOS Package" { + BeforeAll { + Write-Verbose "In Describe BeforeAll" -Verbose + Import-Module $PSScriptRoot/../../../build.psm1 + + # Find the macOS package + $packagePath = $env:PACKAGE_FOLDER + if (-not $packagePath) { + $packagePath = Get-Location + } + + Write-Verbose "Looking for package in: $packagePath" -Verbose + $package = Get-ChildItem -Path $packagePath -Filter "*.pkg" -ErrorAction SilentlyContinue | Select-Object -First 1 + + if (-not $package) { + Write-Warning "No .pkg file found in $packagePath" + } else { + Write-Verbose "Found package: $($package.FullName)" -Verbose + } + + # Set up test directories + $script:package = $package + $script:expandDir = $null + $script:payloadDir = $null + $script:extractedFiles = @() + + if ($package) { + # Use TestDrive for temporary directories - pkgutil will create the expand directory + $script:expandDir = Join-Path "TestDrive:" -ChildPath "package-contents-test" + $expandDirResolved = (Resolve-Path "TestDrive:").ProviderPath + $script:expandDir = Join-Path $expandDirResolved -ChildPath "package-contents-test" + + Write-Verbose "Expanding package to: $($script:expandDir)" -Verbose + # pkgutil will create the directory itself, so don't pre-create it + Start-NativeExecution { + pkgutil --expand $package.FullName $script:expandDir + } + + # Extract the payload to verify files + $script:payloadDir = Join-Path "TestDrive:" -ChildPath "package-payload-test" + $payloadDirResolved = (Resolve-Path "TestDrive:").ProviderPath + $script:payloadDir = Join-Path $payloadDirResolved -ChildPath "package-payload-test" + + # Create payload directory since cpio needs it + if (-not (Test-Path $script:payloadDir)) { + $null = New-Item -ItemType Directory -Path $script:payloadDir -Force + } + + $componentPkg = Get-ChildItem -Path $script:expandDir -Filter "*.pkg" -Recurse | Select-Object -First 1 + if ($componentPkg) { + Write-Verbose "Extracting payload from: $($componentPkg.FullName)" -Verbose + Push-Location $script:payloadDir + try { + $payloadFile = Join-Path $componentPkg.FullName "Payload" + Get-Content -Path $payloadFile -Raw -AsByteStream | & cpio -i 2>&1 | Out-Null + } finally { + Pop-Location + } + } + + # Get all extracted files for verification + $script:extractedFiles = Get-ChildItem -Path $script:payloadDir -Recurse -ErrorAction SilentlyContinue + Write-Verbose "Extracted $($script:extractedFiles.Count) files" -Verbose + } + } + + AfterAll { + # TestDrive automatically cleans up, but we can ensure cleanup happens + # No manual cleanup needed as TestDrive handles it + } + + Context "Package existence and structure" { + It "Package file should exist" { + $script:package | Should -Not -BeNullOrEmpty -Because "A .pkg file should be created" + $script:package.Extension | Should -Be ".pkg" + } + + It "Package should expand successfully" { + $script:expandDir | Should -Exist + Get-ChildItem -Path $script:expandDir | Should -Not -BeNullOrEmpty + } + + It "Package should have a component package" { + $componentPkg = Get-ChildItem -Path $script:expandDir -Filter "*.pkg" -Recurse -ErrorAction SilentlyContinue + $componentPkg | Should -Not -BeNullOrEmpty -Because "Package should contain a component.pkg" + } + + It "Payload should extract successfully" { + $script:payloadDir | Should -Exist + $script:extractedFiles | Should -Not -BeNullOrEmpty -Because "Package payload should contain files" + } + } + + Context "Required files in package" { + BeforeAll { + $expectedFilePatterns = @{ + "PowerShell executable" = "usr/local/microsoft/powershell/*/pwsh" + "PowerShell symlink in /usr/local/bin" = "usr/local/bin/pwsh*" + "Man page" = "usr/local/share/man/man1/pwsh*.gz" + "Launcher application plist" = "Applications/PowerShell*.app/Contents/Info.plist" + } + + $testCases = @() + foreach ($key in $expectedFilePatterns.Keys) { + $testCases += @{ + Description = $key + Pattern = $expectedFilePatterns[$key] + } + } + + $script:testCases = $testCases + } + + It "Should contain " -TestCases $script:testCases { + param($Description, $Pattern) + + $found = $script:extractedFiles | Where-Object { $_.FullName -like "*$Pattern*" } + $found | Should -Not -BeNullOrEmpty -Because "$Description should exist in the package at path matching '$Pattern'" + } + } + + Context "PowerShell binary verification" { + It "PowerShell executable should be executable" { + $pwshBinary = $script:extractedFiles | Where-Object { $_.FullName -like "*/pwsh" -and $_.FullName -like "*/microsoft/powershell/*" } + $pwshBinary | Should -Not -BeNullOrEmpty + + # Check if file has executable permissions (on Unix-like systems) + if ($IsLinux -or $IsMacOS) { + $permissions = (Get-Item $pwshBinary[0].FullName).UnixFileMode + # Executable bit should be set + $permissions.ToString() | Should -Match 'x' -Because "pwsh binary should have execute permissions" + } + } + } + + Context "Launcher application" { + It "Launcher app should have proper bundle structure" { + $plistFile = $script:extractedFiles | Where-Object { $_.FullName -like "*PowerShell*.app/Contents/Info.plist" } + $plistFile | Should -Not -BeNullOrEmpty + + # Verify the bundle has required components + $appPath = Split-Path (Split-Path $plistFile[0].FullName -Parent) -Parent + $macOSDir = Join-Path $appPath "Contents/MacOS" + $resourcesDir = Join-Path $appPath "Contents/Resources" + + Test-Path $macOSDir | Should -Be $true -Because "App bundle should have Contents/MacOS directory" + Test-Path $resourcesDir | Should -Be $true -Because "App bundle should have Contents/Resources directory" + } + + It "Launcher script should exist and be executable" { + $launcherScript = $script:extractedFiles | Where-Object { + $_.FullName -like "*PowerShell*.app/Contents/MacOS/PowerShell.sh" + } + $launcherScript | Should -Not -BeNullOrEmpty -Because "Launcher script should exist" + + if ($IsLinux -or $IsMacOS) { + $permissions = (Get-Item $launcherScript[0].FullName).UnixFileMode + $permissions.ToString() | Should -Match 'x' -Because "Launcher script should have execute permissions" + } + } + } +} From 6b2a15e3c12ed1d3c579fd482ac867e22a07277e Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 12:32:55 -0800 Subject: [PATCH 189/275] [release/v7.5] Create GitHub copilot setup workflow (#26807) --- .github/workflows/copilot-setup-steps.yml | 61 +++++++++++++ build.psm1 | 106 ++++++++++++++++++++-- 2 files changed, 159 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/copilot-setup-steps.yml diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml new file mode 100644 index 00000000000..ac57bd87b5a --- /dev/null +++ b/.github/workflows/copilot-setup-steps.yml @@ -0,0 +1,61 @@ +name: "Copilot Setup Steps" + +# Allow testing of the setup steps from your repository's "Actions" tab. +on: + workflow_dispatch: + + pull_request: + branches: + - master + paths: + - ".github/workflows/copilot-setup-steps.yml" + +jobs: + # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot. + # See https://docs.github.com/en/copilot/customizing-copilot/customizing-the-development-environment-for-copilot-coding-agent + copilot-setup-steps: + runs-on: ubuntu-latest + + permissions: + contents: read + + # You can define any steps you want, and they will run before the agent starts. + # If you do not check out your code, Copilot will do this for you. + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 1000 + + - name: Bootstrap + if: success() + run: |- + $title = 'Import Build.psm1' + Write-Host "::group::$title" + Import-Module ./build.psm1 -Verbose -ErrorAction Stop + Write-LogGroupEnd -Title $title + + $title = 'Switch to public feed' + Write-LogGroupStart -Title $title + Switch-PSNugetConfig -Source Public + Write-LogGroupEnd -Title $title + + $title = 'Bootstrap' + Write-LogGroupStart -Title $title + Start-PSBootstrap -Scenario DotNet + Write-LogGroupEnd -Title $title + + $title = 'Install .NET Tools' + Write-LogGroupStart -Title $title + Start-PSBootstrap -Scenario Tools + Write-LogGroupEnd -Title $title + + $title = 'Sync Tags' + Write-LogGroupStart -Title $title + Sync-PSTags -AddRemoteIfMissing + Write-LogGroupEnd -Title $title + + $title = 'Setup .NET environment variables' + Write-LogGroupStart -Title $title + Find-DotNet -SetDotnetRoot + Write-LogGroupEnd -Title $title + shell: pwsh diff --git a/build.psm1 b/build.psm1 index 810709fbf88..9a8b9329e26 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2282,7 +2282,12 @@ function Start-PSBootstrap { [switch]$BuildLinuxArm, [switch]$Force, [Parameter(Mandatory = $true)] - [ValidateSet("Package", "DotNet", "Both")] + # Package: Install dependencies for packaging tools (fpm, rpmbuild, WiX) + # DotNet: Install the .NET SDK + # Both: Package and DotNet scenarios + # Tools: Install .NET global tools (e.g., dotnet-format) + # All: Install all dependencies (packaging, .NET SDK, and tools) + [ValidateSet("Package", "DotNet", "Both", "Tools", "All")] [string]$Scenario = "Package" ) @@ -2402,7 +2407,7 @@ function Start-PSBootstrap { # Install [fpm](https://github.com/jordansissel/fpm) # Note: fpm is now only needed for DEB and macOS packages; RPM packages use rpmbuild directly - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { + if ($Scenario -in 'All', 'Both', 'Package') { # Install fpm on Debian-based systems, macOS, and Mariner (where DEB packages are built) if (($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) -or $environment.IsMacOS) { Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" @@ -2410,7 +2415,7 @@ function Start-PSBootstrap { Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5" } - + # For RPM-based systems, ensure rpmbuild is available if ($environment.IsLinux -and ($environment.IsRedHatFamily -or $environment.IsSUSEFamily -or $environment.IsMariner)) { Write-Verbose -Verbose "Checking for rpmbuild..." @@ -2422,7 +2427,7 @@ function Start-PSBootstrap { } } - if ($Scenario -eq 'DotNet' -or $Scenario -eq 'Both') { + if ($Scenario -in 'All', 'Both', 'DotNet') { Write-Verbose -Verbose "Calling Find-Dotnet from Start-PSBootstrap" @@ -2479,6 +2484,19 @@ function Start-PSBootstrap { } } + if ($Scenario -in 'All', 'Tools') { + Write-Log -message "Installing .NET global tools" + + # Ensure dotnet is available + Find-Dotnet + + # Install dotnet-format + Write-Verbose -Verbose "Installing dotnet-format global tool" + Start-NativeExecution { + dotnet tool install --global dotnet-format + } + } + if ($env:TF_BUILD) { Write-Verbose -Verbose "--- Start - Capturing nuget sources" dotnet nuget list source --format detailed @@ -2646,6 +2664,63 @@ function Start-ResGen } } +function Add-PSEnvironmentPath { + <# + .SYNOPSIS + Adds a path to the process PATH and persists to GitHub Actions workflow if running in GitHub Actions + .PARAMETER Path + Path to add to PATH + .PARAMETER Prepend + If specified, prepends the path instead of appending + #> + param ( + [Parameter(Mandatory)] + [string]$Path, + + [switch]$Prepend + ) + + # Set in current process + if ($Prepend) { + $env:PATH = $Path + [IO.Path]::PathSeparator + $env:PATH + } else { + $env:PATH += [IO.Path]::PathSeparator + $Path + } + + # Persist to GitHub Actions workflow if running in GitHub Actions + if ($env:GITHUB_ACTIONS -eq 'true') { + Write-Verbose -Verbose "Adding $Path to GITHUB_PATH" + Add-Content -Path $env:GITHUB_PATH -Value $Path + } +} + +function Set-PSEnvironmentVariable { + <# + .SYNOPSIS + Sets an environment variable in the process and persists to GitHub Actions workflow if running in GitHub Actions + .PARAMETER Name + The name of the environment variable + .PARAMETER Value + The value of the environment variable + #> + param ( + [Parameter(Mandatory)] + [string]$Name, + + [Parameter(Mandatory)] + [string]$Value + ) + + # Set in current process + Set-Item -Path "env:$Name" -Value $Value + + # Persist to GitHub Actions workflow if running in GitHub Actions + if ($env:GITHUB_ACTIONS -eq 'true') { + Write-Verbose -Verbose "Setting $Name in GITHUB_ENV" + Add-Content -Path $env:GITHUB_ENV -Value "$Name=$Value" + } +} + function Find-Dotnet { param ( [switch] $SetDotnetRoot @@ -2676,25 +2751,40 @@ function Find-Dotnet { if ($dotnetCLIInstalledVersion -ne $chosenDotNetVersion) { Write-Warning "The 'dotnet' in the current path can't find SDK version ${dotnetCLIRequiredVersion}, prepending $dotnetPath to PATH." # Globally installed dotnet doesn't have the required SDK version, prepend the user local dotnet location - $env:PATH = $dotnetPath + [IO.Path]::PathSeparator + $env:PATH + Add-PSEnvironmentPath -Path $dotnetPath -Prepend if ($SetDotnetRoot) { Write-Verbose -Verbose "Setting DOTNET_ROOT to $dotnetPath" - $env:DOTNET_ROOT = $dotnetPath + Set-PSEnvironmentVariable -Name 'DOTNET_ROOT' -Value $dotnetPath } } elseif ($SetDotnetRoot) { Write-Verbose -Verbose "Expected dotnet version found, setting DOTNET_ROOT to $dotnetPath" - $env:DOTNET_ROOT = $dotnetPath + Set-PSEnvironmentVariable -Name 'DOTNET_ROOT' -Value $dotnetPath } } else { Write-Warning "Could not find 'dotnet', appending $dotnetPath to PATH." - $env:PATH += [IO.Path]::PathSeparator + $dotnetPath + Add-PSEnvironmentPath -Path $dotnetPath + + if ($SetDotnetRoot) { + Write-Verbose -Verbose "Setting DOTNET_ROOT to $dotnetPath" + Set-PSEnvironmentVariable -Name 'DOTNET_ROOT' -Value $dotnetPath + } } if (-not (precheck 'dotnet' "Still could not find 'dotnet', restoring PATH.")) { + # Give up, restore original PATH. There is nothing to persist since we didn't make a change. $env:PATH = $originalPath } + elseif ($SetDotnetRoot) { + # If we found dotnet, also add the global tools path to PATH + # Add .NET global tools to PATH when setting up the environment + $dotnetToolsPath = Join-Path $dotnetPath "tools" + if (Test-Path $dotnetToolsPath) { + Write-Verbose -Verbose "Adding .NET tools path to PATH: $dotnetToolsPath" + Add-PSEnvironmentPath -Path $dotnetToolsPath + } + } } <# From 606ba56956e7f76407f4de8a0fc53f8986dcbd31 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 12:52:34 -0800 Subject: [PATCH 190/275] [release/v7.5] Remove usage of fpm for DEB package generation (#26809) --- build.psm1 | 76 +-- .../linux/package-validation.tests.ps1 | 48 +- tools/packaging/packaging.psm1 | 462 ++++++++++-------- 3 files changed, 315 insertions(+), 271 deletions(-) diff --git a/build.psm1 b/build.psm1 index 9a8b9329e26..c42f3d1ecf7 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2234,43 +2234,6 @@ function Get-RedHatPackageManager { } } -function Install-GlobalGem { - param( - [Parameter()] - [string] - $Sudo = "", - - [Parameter(Mandatory)] - [string] - $GemName, - - [Parameter(Mandatory)] - [string] - $GemVersion - ) - try { - # We cannot guess if the user wants to run gem install as root on linux and windows, - # but macOs usually requires sudo - $gemsudo = '' - if($environment.IsMacOS -or $env:TF_BUILD -or $env:GITHUB_ACTIONS) { - $gemsudo = $sudo - } - - Start-NativeExecution ([ScriptBlock]::Create("$gemsudo gem install $GemName -v $GemVersion --no-document")) - - } catch { - Write-Warning "Installation of gem $GemName $GemVersion failed! Must resolve manually." - $logs = Get-ChildItem "/var/lib/gems/*/extensions/x86_64-linux/*/$GemName-*/gem_make.out" | Select-Object -ExpandProperty FullName - foreach ($log in $logs) { - Write-Verbose "Contents of: $log" -Verbose - Get-Content -Raw -Path $log -ErrorAction Ignore | ForEach-Object { Write-Verbose $_ -Verbose } - Write-Verbose "END Contents of: $log" -Verbose - } - - throw - } -} - function Start-PSBootstrap { [CmdletBinding()] param( @@ -2282,7 +2245,7 @@ function Start-PSBootstrap { [switch]$BuildLinuxArm, [switch]$Force, [Parameter(Mandatory = $true)] - # Package: Install dependencies for packaging tools (fpm, rpmbuild, WiX) + # Package: Install dependencies for packaging tools (rpmbuild, dpkg-deb, pkgbuild, WiX) # DotNet: Install the .NET SDK # Both: Package and DotNet scenarios # Tools: Install .NET global tools (e.g., dotnet-format) @@ -2321,7 +2284,9 @@ function Start-PSBootstrap { elseif ($environment.IsUbuntu18) { $Deps += "libicu60"} # Packaging tools - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-dev", "groff", "libffi-dev", "rpm", "g++", "make" } + # Note: ruby-dev, libffi-dev, g++, and make are no longer needed for DEB packaging + # DEB packages now use native dpkg-deb (pre-installed) + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "groff", "rpm" } # Install dependencies # change the fontend from apt-get to noninteractive @@ -2345,7 +2310,9 @@ function Start-PSBootstrap { $Deps += "libicu", "openssl-libs" # Packaging tools - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-devel", "rpm-build", "groff", 'libffi-devel', "gcc-c++" } + # Note: ruby-devel and libffi-devel are no longer needed + # RPM packages use rpmbuild, DEB packages use dpkg-deb + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "rpm-build", "groff" } $PackageManager = Get-RedHatPackageManager @@ -2366,7 +2333,8 @@ function Start-PSBootstrap { $Deps += "wget" # Packaging tools - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-devel", "rpmbuild", "groff", 'libffi-devel', "gcc" } + # Note: ruby-devel and libffi-devel are no longer needed for packaging + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "rpmbuild", "groff" } $PackageManager = "zypper --non-interactive install" $baseCommand = "$sudo $PackageManager" @@ -2405,17 +2373,7 @@ function Start-PSBootstrap { } } - # Install [fpm](https://github.com/jordansissel/fpm) - # Note: fpm is now only needed for DEB and macOS packages; RPM packages use rpmbuild directly if ($Scenario -in 'All', 'Both', 'Package') { - # Install fpm on Debian-based systems, macOS, and Mariner (where DEB packages are built) - if (($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) -or $environment.IsMacOS) { - Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" - Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.16.3" - Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" - Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5" - } - # For RPM-based systems, ensure rpmbuild is available if ($environment.IsLinux -and ($environment.IsRedHatFamily -or $environment.IsSUSEFamily -or $environment.IsMariner)) { Write-Verbose -Verbose "Checking for rpmbuild..." @@ -2424,6 +2382,22 @@ function Start-PSBootstrap { Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y rpm-build")) -IgnoreExitcode } } + + # For Debian-based systems and Mariner, ensure dpkg-deb is available + if ($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) { + Write-Verbose -Verbose "Checking for dpkg-deb..." + if (!(Get-Command dpkg-deb -ErrorAction SilentlyContinue)) { + Write-Warning "dpkg-deb not found. Installing dpkg package..." + if ($environment.IsMariner) { + # For Mariner (Azure Linux), install the extended repo first to access dpkg. + Write-Verbose -Verbose "Installing azurelinux-repos-extended for Mariner..." + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y azurelinux-repos-extended")) -IgnoreExitcode + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y dpkg")) -IgnoreExitcode + } else { + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo apt-get install -y dpkg")) -IgnoreExitcode + } + } + } } } diff --git a/test/packaging/linux/package-validation.tests.ps1 b/test/packaging/linux/package-validation.tests.ps1 index 241863de45d..594a729fa77 100644 --- a/test/packaging/linux/package-validation.tests.ps1 +++ b/test/packaging/linux/package-validation.tests.ps1 @@ -21,10 +21,7 @@ Describe "Linux Package Name Validation" { It "Should have valid RPM package names" { $rpmPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.rpm -ErrorAction SilentlyContinue - if ($rpmPackages.Count -eq 0) { - Set-ItResult -Skipped -Because "No RPM packages found in artifacts directory" - return - } + $rpmPackages.Count | Should -BeGreaterThan 0 -Because "At least one RPM package should exist in the artifacts directory" $invalidPackages = @() # Regex pattern for valid RPM package names. @@ -49,8 +46,42 @@ Describe "Linux Package Name Validation" { if ($invalidPackages.Count -gt 0) { throw ($invalidPackages | Out-String) } + } + } + + Context "DEB Package Names" { + It "Should have valid DEB package names" { + $debPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.deb -ErrorAction SilentlyContinue + + $debPackages.Count | Should -BeGreaterThan 0 -Because "At least one DEB package should exist in the artifacts directory" + + $invalidPackages = @() + # Regex pattern for valid DEB package names. + # Valid examples: + # - powershell-preview_7.6.0-preview.6-1.deb_amd64.deb + # - powershell-lts_7.4.13-1.deb_amd64.deb + # - powershell_7.4.13-1.deb_amd64.deb + # Breakdown: + # ^powershell : Starts with 'powershell' + # (-preview|-lts)? : Optionally '-preview' or '-lts' + # _\d+\.\d+\.\d+ : Underscore followed by version number (e.g., _7.6.0) + # (-[a-z]+\.\d+)? : Optional dash, letters, dot, and digits (e.g., -preview.6) + # -1 : Literal '-1' + # \.deb_ : Literal '.deb_' + # (amd64|arm64) : Architecture + # \.deb$ : File extension + $debPackageNamePattern = '^powershell(-preview|-lts)?_\d+\.\d+\.\d+(-[a-z]+\.\d+)?-1\.deb_(amd64|arm64)\.deb$' + + foreach ($package in $debPackages) { + if ($package.Name -notmatch $debPackageNamePattern) { + $invalidPackages += "$($package.Name) is not a valid DEB package name" + Write-Warning "$($package.Name) is not a valid DEB package name" + } + } - $rpmPackages.Count | Should -BeGreaterThan 0 + if ($invalidPackages.Count -gt 0) { + throw ($invalidPackages | Out-String) + } } } @@ -58,10 +89,7 @@ Describe "Linux Package Name Validation" { It "Should have valid tar.gz package names" { $tarPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.tar.gz -ErrorAction SilentlyContinue - if ($tarPackages.Count -eq 0) { - Set-ItResult -Skipped -Because "No tar.gz packages found in artifacts directory" - return - } + $tarPackages.Count | Should -BeGreaterThan 0 -Because "At least one tar.gz package should exist in the artifacts directory" $invalidPackages = @() foreach ($package in $tarPackages) { @@ -76,8 +104,6 @@ Describe "Linux Package Name Validation" { if ($invalidPackages.Count -gt 0) { throw ($invalidPackages | Out-String) } - - $tarPackages.Count | Should -BeGreaterThan 0 } } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index b6d2b046509..286859e9ed9 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1199,8 +1199,6 @@ function New-UnixPackage { # Generate After Install and After Remove scripts $AfterScriptInfo = New-AfterScripts -Link $Link -Distribution $DebDistro -Destination $Destination - # Note: The fpm symlink workaround is no longer needed with native macOS packaging tools - # Generate gzip of man file $ManGzipInfo = New-ManGzip -IsPreview:$IsPreview -IsLTS:$LTS @@ -1319,6 +1317,33 @@ function New-UnixPackage { throw } } + } elseif ($Type -eq 'deb') { + # Use native DEB package builder + if ($PSCmdlet.ShouldProcess("Create DEB package natively")) { + Write-Log "Creating DEB package natively..." + try { + $result = New-NativeDeb ` + -Name $Name ` + -Version $packageVersion ` + -Iteration $Iteration ` + -Description $Description ` + -Staging $Staging ` + -Destination $Destination ` + -ManGzipFile $ManGzipInfo.GzipFile ` + -ManDestination $ManGzipInfo.ManFile ` + -LinkInfo $Links ` + -Dependencies $Dependencies ` + -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` + -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` + -HostArchitecture $HostArchitecture ` + -CurrentLocation $CurrentLocation + + $Output = @("Created package {:path=>""$($result.PackageName)""}") + } + catch { + Write-Verbose -Message "!!!Handling error in native DEB creation!!!" -Verbose -ErrorAction SilentlyContinue + } + } } elseif ($Type -eq 'osxpkg') { # Use native macOS packaging tools if ($PSCmdlet.ShouldProcess("Create macOS package with pkgbuild/productbuild")) { @@ -1350,40 +1375,8 @@ function New-UnixPackage { } } } else { - # Use fpm for DEB packages - $Arguments = @() - - $Arguments += Get-FpmArguments ` - -Name $Name ` - -Version $packageVersion ` - -Iteration $Iteration ` - -Description $Description ` - -Type $Type ` - -Dependencies $Dependencies ` - -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` - -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` - -Staging $Staging ` - -Destination $Destination ` - -ManGzipFile $ManGzipInfo.GzipFile ` - -ManDestination $ManGzipInfo.ManFile ` - -LinkInfo $Links ` - -AppsFolder $AppsFolder ` - -Distribution $DebDistro ` - -HostArchitecture $HostArchitecture ` - -ErrorAction Stop - - if ($PSCmdlet.ShouldProcess("Create $type package")) { - Write-Log "Creating package with fpm $Arguments..." - try { - $Output = Start-NativeExecution { fpm $Arguments } - } - catch { - Write-Verbose -Message "!!!Handling error in FPM!!!" -Verbose -ErrorAction SilentlyContinue - Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue - Get-Error -InputObject $_ - throw - } - } + # Nothing should reach here + throw "Unknown package type: $Type" } } finally { if ($Environment.IsMacOS) { @@ -1416,8 +1409,7 @@ function New-UnixPackage { $createdPackage = Get-Item (Join-Path $CurrentLocation (($Output[-1] -split ":path=>")[-1] -replace '["{}]')) # For macOS with native tools, the package is already in the correct format - # For macOS with fpm (no longer used), we would need New-MacOsDistributionPackage - # For other platforms, the package name from fpm/rpmbuild is sufficient + # For other platforms, the package name from dpkg-deb/rpmbuild is sufficient if (Test-Path $createdPackage) { @@ -1695,8 +1687,8 @@ cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination foreach ($link in $LinkInfo) { $linkDir = Split-Path -Parent $link.Destination $specContent += "mkdir -p `$RPM_BUILD_ROOT$linkDir`n" - # For RPM, we copy the symlink itself (which fpm does by including it in the source) - # The symlink at $link.Source points to the actual target, so we'll copy it + # For RPM, we copy the symlink itself. + # The symlink at $link.Source points to the actual target, so we'll copy it. # The -P flag preserves symlinks rather than copying their targets, which is critical for this operation. $specContent += "cp -P $($link.Source) `$RPM_BUILD_ROOT$($link.Destination)`n" } @@ -1733,6 +1725,217 @@ cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination return $specContent } +function New-NativeDeb +{ + param( + [Parameter(Mandatory, HelpMessage='Package Name')] + [String]$Name, + + [Parameter(Mandatory, HelpMessage='Package Version')] + [String]$Version, + + [Parameter(Mandatory)] + [String]$Iteration, + + [Parameter(Mandatory, HelpMessage='Package description')] + [String]$Description, + + [Parameter(Mandatory, HelpMessage='Staging folder for installation files')] + [String]$Staging, + + [Parameter(Mandatory, HelpMessage='Install path on target machine')] + [String]$Destination, + + [Parameter(Mandatory, HelpMessage='The built and gzipped man file.')] + [String]$ManGzipFile, + + [Parameter(Mandatory, HelpMessage='The destination of the man file')] + [String]$ManDestination, + + [Parameter(Mandatory, HelpMessage='Symlink to powershell executable')] + [LinkInfo[]]$LinkInfo, + + [Parameter(HelpMessage='Packages required to install this package.')] + [String[]]$Dependencies, + + [Parameter(HelpMessage='Script to run after the package installation.')] + [String]$AfterInstallScript, + + [Parameter(HelpMessage='Script to run after the package removal.')] + [String]$AfterRemoveScript, + + [string]$HostArchitecture, + + [string]$CurrentLocation + ) + + Write-Log "Creating native DEB package..." + + # Create temporary build directory + $debBuildRoot = Join-Path $env:HOME "debbuild-$(Get-Random)" + $debianDir = Join-Path $debBuildRoot "DEBIAN" + $dataDir = Join-Path $debBuildRoot "data" + + try { + New-Item -ItemType Directory -Path $debianDir -Force | Out-Null + New-Item -ItemType Directory -Path $dataDir -Force | Out-Null + + # Calculate installed size (in KB) + $installedSize = 0 + Get-ChildItem -Path $Staging -Recurse -File | ForEach-Object { $installedSize += $_.Length } + $installedSize += (Get-Item $ManGzipFile).Length + $installedSizeKB = [Math]::Ceiling($installedSize / 1024) + + # Create control file with all fields in proper order + # Description must be single line (first line) followed by extended description with leading space + $descriptionLines = $Description -split "`n" + $shortDescription = $descriptionLines[0] + $extendedDescription = if ($descriptionLines.Count -gt 1) { + ($descriptionLines[1..($descriptionLines.Count-1)] | ForEach-Object { " $_" }) -join "`n" + } + + $controlContent = @" +Package: $Name +Version: $Version-$Iteration +Architecture: $HostArchitecture +Maintainer: PowerShell Team +Installed-Size: $installedSizeKB +Priority: optional +Section: shells +Homepage: https://microsoft.com/powershell +Depends: $(if ($Dependencies) { $Dependencies -join ', ' }) +Description: $shortDescription +$(if ($extendedDescription) { $extendedDescription + "`n" }) +"@ + + $controlFile = Join-Path $debianDir "control" + $controlContent | Out-File -FilePath $controlFile -Encoding ascii -NoNewline + + Write-Verbose "Control file created: $controlFile" -Verbose + Write-LogGroup -Title "DEB Control File Content" -Message $controlContent + + # Copy postinst script if provided + if ($AfterInstallScript -and (Test-Path $AfterInstallScript)) { + $postinstFile = Join-Path $debianDir "postinst" + Copy-Item -Path $AfterInstallScript -Destination $postinstFile -Force + Start-NativeExecution { chmod 755 $postinstFile } + Write-Verbose "Postinst script copied to: $postinstFile" -Verbose + } + + # Copy postrm script if provided + if ($AfterRemoveScript -and (Test-Path $AfterRemoveScript)) { + $postrmFile = Join-Path $debianDir "postrm" + Copy-Item -Path $AfterRemoveScript -Destination $postrmFile -Force + Start-NativeExecution { chmod 755 $postrmFile } + Write-Verbose "Postrm script copied to: $postrmFile" -Verbose + } + + # Copy staging files to data directory + $targetPath = Join-Path $dataDir $Destination.TrimStart('/') + New-Item -ItemType Directory -Path $targetPath -Force | Out-Null + Copy-Item -Path "$Staging/*" -Destination $targetPath -Recurse -Force + Write-Verbose "Copied staging files to: $targetPath" -Verbose + + # Copy man page + $manDestPath = Join-Path $dataDir $ManDestination.TrimStart('/') + $manDestDir = Split-Path $manDestPath -Parent + New-Item -ItemType Directory -Path $manDestDir -Force | Out-Null + Copy-Item -Path $ManGzipFile -Destination $manDestPath -Force + Write-Verbose "Copied man page to: $manDestPath" -Verbose + + # Copy symlinks from temporary locations + foreach ($link in $LinkInfo) { + $linkPath = Join-Path $dataDir $link.Destination.TrimStart('/') + $linkDir = Split-Path $linkPath -Parent + New-Item -ItemType Directory -Path $linkDir -Force | Out-Null + + # Copy the temporary symlink file that was created by New-LinkInfo + # The Source contains a temporary symlink that points to the correct target + if (Test-Path $link.Source) { + # Use cp to preserve the symlink + Start-NativeExecution { cp -P $link.Source $linkPath } + Write-Verbose "Copied symlink: $linkPath (from $($link.Source))" -Verbose + } else { + Write-Warning "Symlink source not found: $($link.Source)" + } + } + + # Set proper permissions + Write-Verbose "Setting file permissions..." -Verbose + # 755 = rwxr-xr-x (owner can read/write/execute, group and others can read/execute) + Get-ChildItem $dataDir -Directory -Recurse | ForEach-Object { + Start-NativeExecution { chmod 755 $_.FullName } + } + # 644 = rw-r--r-- (owner can read/write, group and others can read only) + # Exclude symlinks to avoid "cannot operate on dangling symlink" error + Get-ChildItem $dataDir -File -Recurse | + Where-Object { -not $_.Target } | + ForEach-Object { + Start-NativeExecution { chmod 644 $_.FullName } + } + + # Set executable permission for pwsh if it exists + # 755 = rwxr-xr-x (executable permission) + $pwshPath = "$targetPath/pwsh" + if (Test-Path $pwshPath) { + Start-NativeExecution { chmod 755 $pwshPath } + } + + # Calculate md5sums for all files in data directory (excluding symlinks) + $md5sumsFile = Join-Path $debianDir "md5sums" + $md5Content = "" + Get-ChildItem -Path $dataDir -Recurse -File | + Where-Object { -not $_.Target } | + ForEach-Object { + $relativePath = $_.FullName.Substring($dataDir.Length + 1) + $md5Hash = (Get-FileHash -Path $_.FullName -Algorithm MD5).Hash.ToLower() + $md5Content += "$md5Hash $relativePath`n" + } + $md5Content | Out-File -FilePath $md5sumsFile -Encoding ascii -NoNewline + Write-Verbose "MD5 sums file created: $md5sumsFile" -Verbose + + # Build the package using dpkg-deb + $debFileName = "${Name}_${Version}-${Iteration}_${HostArchitecture}.deb" + $debFilePath = Join-Path $CurrentLocation $debFileName + + Write-Verbose "Building DEB package: $debFileName" -Verbose + + # Copy DEBIAN directory and data files to build root + $buildDir = Join-Path $debBuildRoot "build" + New-Item -ItemType Directory -Path $buildDir -Force | Out-Null + + Write-Verbose "debianDir: $debianDir" -Verbose + Write-Verbose "dataDir: $dataDir" -Verbose + Write-Verbose "buildDir: $buildDir" -Verbose + + # Use cp to preserve symlinks + Start-NativeExecution { cp -a $debianDir "$buildDir/DEBIAN" } + Start-NativeExecution { cp -a $dataDir/* $buildDir } + + # Build package with dpkg-deb + Start-NativeExecution -VerboseOutputOnError { + dpkg-deb --build $buildDir $debFilePath + } + + if (Test-Path $debFilePath) { + Write-Log "Successfully created DEB package: $debFileName" + return @{ + PackagePath = $debFilePath + PackageName = $debFileName + } + } else { + throw "DEB package file not found after build: $debFilePath" + } + } + finally { + # Cleanup temporary directory + if (Test-Path $debBuildRoot) { + Write-Verbose "Cleaning up temporary build directory: $debBuildRoot" -Verbose + Remove-Item -Path $debBuildRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } +} + function New-MacOSPackage { [CmdletBinding(SupportsShouldProcess=$true)] @@ -1884,146 +2087,6 @@ function New-MacOSPackage } } -function Get-FpmArguments -{ - param( - [Parameter(Mandatory,HelpMessage='Package Name')] - [String]$Name, - - [Parameter(Mandatory,HelpMessage='Package Version')] - [String]$Version, - - [Parameter(Mandatory)] - [String]$Iteration, - - [Parameter(Mandatory,HelpMessage='Package description')] - [String]$Description, - - # From start-PSPackage without modification, already validated - # Values: deb, rpm, osxpkg - [Parameter(Mandatory,HelpMessage='Installer Type')] - [String]$Type, - - [Parameter(Mandatory,HelpMessage='Staging folder for installation files')] - [String]$Staging, - - [Parameter(Mandatory,HelpMessage='Install path on target machine')] - [String]$Destination, - - [Parameter(Mandatory,HelpMessage='The built and gzipped man file.')] - [String]$ManGzipFile, - - [Parameter(Mandatory,HelpMessage='The destination of the man file')] - [String]$ManDestination, - - [Parameter(Mandatory,HelpMessage='Symlink to powershell executable')] - [LinkInfo[]]$LinkInfo, - - [Parameter(HelpMessage='Packages required to install this package. Not applicable for MacOS.')] - [ValidateScript({ - if (!$Environment.IsMacOS -and $_.Count -eq 0) - { - throw "Must not be null or empty on this environment." - } - return $true - })] - [String[]]$Dependencies, - - [Parameter(HelpMessage='Script to run after the package installation.')] - [AllowNull()] - [ValidateScript({ - if (!$Environment.IsMacOS -and !$_) - { - throw "Must not be null on this environment." - } - return $true - })] - [String]$AfterInstallScript, - - [Parameter(HelpMessage='Script to run after the package removal.')] - [AllowNull()] - [ValidateScript({ - if (!$Environment.IsMacOS -and !$_) - { - throw "Must not be null on this environment." - } - return $true - })] - [String]$AfterRemoveScript, - - [Parameter(HelpMessage='AppsFolder used to add macOS launcher')] - [AllowNull()] - [ValidateScript({ - if ($Environment.IsMacOS -and !$_) - { - throw "Must not be null on this environment." - } - return $true - })] - [String]$AppsFolder, - [String]$Distribution = 'rhel.7', - [string]$HostArchitecture - ) - - $Arguments = @( - "--force", "--verbose", - "--name", $Name, - "--version", $Version, - "--iteration", $Iteration, - "--maintainer", "PowerShell Team ", - "--vendor", "Microsoft Corporation", - "--url", "https://microsoft.com/powershell", - "--description", $Description, - "--architecture", $HostArchitecture, - "--category", "shells", - "-t", $Type, - "-s", "dir" - ) - if ($Distribution -in $script:RedHatDistributions) { - $Arguments += @("--rpm-digest", "sha256") - $Arguments += @("--rpm-dist", $Distribution) - $Arguments += @("--rpm-os", "linux") - $Arguments += @("--license", "MIT") - $Arguments += @("--rpm-rpmbuild-define", "_build_id_links none") - } else { - $Arguments += @("--license", "MIT License") - } - - if ($Environment.IsMacOS) { - $Arguments += @("--osxpkg-identifier-prefix", "com.microsoft") - } - - foreach ($Dependency in $Dependencies) { - $Arguments += @("--depends", $Dependency) - } - - if ($AfterInstallScript) { - $Arguments += @("--after-install", $AfterInstallScript) - } - - if ($AfterRemoveScript) { - $Arguments += @("--after-remove", $AfterRemoveScript) - } - - $Arguments += @( - "$Staging/=$Destination/", - "$ManGzipFile=$ManDestination" - ) - - foreach($link in $LinkInfo) - { - $linkArgument = "$($link.Source)=$($link.Destination)" - $Arguments += $linkArgument - } - - if ($AppsFolder) - { - $Arguments += "$AppsFolder=/" - } - - return $Arguments -} - function Get-PackageDependencies { [CmdletBinding()] @@ -2096,44 +2159,25 @@ function Get-PackageDependencies function Test-Dependencies { - # Note: RPM packages no longer require fpm; they use rpmbuild directly - # macOS packages use pkgbuild and productbuild from Xcode Command Line Tools - # DEB packages still use fpm + # RPM packages use rpmbuild directly. + # DEB packages use dpkg-deb directly. + # macOS packages use pkgbuild and productbuild from Xcode Command Line Tools. $Dependencies = @() - - # Only check for fpm on Debian-based systems - if ($Environment.IsDebianFamily) { - $Dependencies += "fpm" + + # Check for 'rpmbuild' and 'dpkg-deb' on Azure Linux. + if ($Environment.IsMariner) { + $Dependencies += "dpkg-deb" + $Dependencies += "rpmbuild" } - + # Check for macOS packaging tools if ($Environment.IsMacOS) { $Dependencies += "pkgbuild" $Dependencies += "productbuild" } - + foreach ($Dependency in $Dependencies) { if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { - # For Debian systems, try adding ruby gems to the path - if ($Environment.IsDebianFamily) { - # These tools are not added to the path automatically on OpenSUSE 13.2 - # try adding them to the path and re-tesing first - [string] $gemsPath = $null - [string] $depenencyPath = $null - $gemsPath = Get-ChildItem -Path /usr/lib64/ruby/gems | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName - if ($gemsPath) { - $depenencyPath = Get-ChildItem -Path (Join-Path -Path $gemsPath -ChildPath "gems" -AdditionalChildPath $Dependency) -Recurse | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty DirectoryName - $originalPath = $env:PATH - $env:PATH = $ENV:PATH +":" + $depenencyPath - if ((precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { - continue - } - else { - $env:PATH = $originalPath - } - } - } - throw "Dependency precheck failed!" } } From eab7688778e57ab9dd1702ca6c071ebe59171d6e Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 13:49:29 -0800 Subject: [PATCH 191/275] [release/v7.5] Add log grouping to build.psm1 for collapsible GitHub Actions logs (#26810) --- .github/actions/build/ci/action.yml | 4 +- .../actions/test/linux-packaging/action.yml | 4 +- .github/actions/test/nix/action.yml | 6 +- .github/actions/test/windows/action.yml | 6 +- .../log-grouping-guidelines.instructions.md | 181 ++++++++++++++++++ .github/workflows/analyze-reusable.yml | 3 +- .github/workflows/linux-ci.yml | 13 +- .github/workflows/macos-ci.yml | 29 +-- .github/workflows/windows-ci.yml | 15 +- .../workflows/windows-packaging-reusable.yml | 3 +- build.psm1 | 28 ++- tools/ci.psm1 | 8 + 12 files changed, 260 insertions(+), 40 deletions(-) create mode 100644 .github/instructions/log-grouping-guidelines.instructions.md diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml index 997be8b264c..be9c0ecd20b 100644 --- a/.github/actions/build/ci/action.yml +++ b/.github/actions/build/ci/action.yml @@ -5,7 +5,9 @@ runs: steps: - name: Capture Environment if: success() || failure() - run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' + run: |- + Import-Module .\tools\ci.psm1 + Show-Environment shell: pwsh - name: Set Build Name for Non-PR if: github.event_name != 'PullRequest' diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index b7bbdf37185..a04e09b6a5c 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -6,7 +6,9 @@ runs: steps: - name: Capture Environment if: success() || failure() - run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' + run: |- + Import-Module ./tools/ci.psm1 + Show-Environment shell: pwsh - uses: actions/setup-dotnet@v5 diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index b338c398340..ef943bfce78 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -21,10 +21,8 @@ runs: - name: Capture Environment if: success() || failure() run: |- - Import-Module ./build.psm1 - Write-LogGroupStart -Title 'Environment' - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - Write-LogGroupEnd -Title 'Environment' + Import-Module ./tools/ci.psm1 + Show-Environment shell: pwsh - name: Download Build Artifacts diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index 734e30208f0..3b3ce0cafe8 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -21,10 +21,8 @@ runs: - name: Capture Environment if: success() || failure() run: |- - Import-Module ./build.psm1 - Write-LogGroupStart -Title 'Environment' - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - Write-LogGroupEnd -Title 'Environment' + Import-Module ./tools/ci.psm1 + Show-Environment shell: pwsh - name: Download Build Artifacts diff --git a/.github/instructions/log-grouping-guidelines.instructions.md b/.github/instructions/log-grouping-guidelines.instructions.md new file mode 100644 index 00000000000..ff845db4e4b --- /dev/null +++ b/.github/instructions/log-grouping-guidelines.instructions.md @@ -0,0 +1,181 @@ +--- +applyTo: + - "build.psm1" + - "tools/ci.psm1" + - ".github/**/*.yml" + - ".github/**/*.yaml" +--- + +# Log Grouping Guidelines for GitHub Actions + +## Purpose + +Guidelines for using `Write-LogGroupStart` and `Write-LogGroupEnd` to create collapsible log sections in GitHub Actions CI/CD runs. + +## Key Principles + +### 1. Groups Cannot Be Nested + +GitHub Actions does not support nested groups. Only use one level of grouping. + +**❌ Don't:** +```powershell +Write-LogGroupStart -Title "Outer Group" +Write-LogGroupStart -Title "Inner Group" +# ... operations ... +Write-LogGroupEnd -Title "Inner Group" +Write-LogGroupEnd -Title "Outer Group" +``` + +**✅ Do:** +```powershell +Write-LogGroupStart -Title "Operation A" +# ... operations ... +Write-LogGroupEnd -Title "Operation A" + +Write-LogGroupStart -Title "Operation B" +# ... operations ... +Write-LogGroupEnd -Title "Operation B" +``` + +### 2. Groups Should Be Substantial + +Only create groups for operations that generate substantial output (5+ lines). Small groups add clutter without benefit. + +**❌ Don't:** +```powershell +Write-LogGroupStart -Title "Generate Resource Files" +Write-Log -message "Run ResGen" +Start-ResGen +Write-LogGroupEnd -Title "Generate Resource Files" +``` + +**✅ Do:** +```powershell +Write-Log -message "Run ResGen (generating C# bindings for resx files)" +Start-ResGen +``` + +### 3. Groups Should Represent Independent Operations + +Each group should be a logically independent operation that users might want to expand/collapse separately. + +**✅ Good examples:** +- Install Native Dependencies +- Install .NET SDK +- Build PowerShell +- Restore NuGet Packages + +**❌ Bad examples:** +- Individual project restores (too granular) +- Small code generation steps (too small) +- Sub-steps of a larger operation (would require nesting) + +### 4. One Group Per Iteration Is Excessive + +Avoid putting log groups inside loops where each iteration creates a separate group. This would probably cause nesting. + +**❌ Don't:** +```powershell +$projects | ForEach-Object { + Write-LogGroupStart -Title "Restore Project: $_" + dotnet restore $_ + Write-LogGroupEnd -Title "Restore Project: $_" +} +``` + +**✅ Do:** +```powershell +Write-LogGroupStart -Title "Restore All Projects" +$projects | ForEach-Object { + Write-Log -message "Restoring $_" + dotnet restore $_ +} +Write-LogGroupEnd -Title "Restore All Projects" +``` + +## Usage Pattern + +```powershell +Write-LogGroupStart -Title "Descriptive Operation Name" +try { + # ... operation code ... + Write-Log -message "Status updates" +} +finally { + # Ensure group is always closed +} +Write-LogGroupEnd -Title "Descriptive Operation Name" +``` + +## When to Use Log Groups + +Use log groups for: +- Major build phases (bootstrap, restore, build, test, package) +- Installation operations (dependencies, SDKs, tools) +- Operations that produce 5+ lines of output +- Operations where users might want to collapse verbose output + +Don't use log groups for: +- Single-line operations +- Code that's already inside another group +- Loop iterations with minimal output per iteration +- Diagnostic or debug output that should always be visible + +## Examples from build.psm1 + +### Good Usage + +```powershell +function Start-PSBootstrap { + # Multiple independent operations, each with substantial output + Write-LogGroupStart -Title "Install Native Dependencies" + # ... apt-get/yum/brew install commands ... + Write-LogGroupEnd -Title "Install Native Dependencies" + + Write-LogGroupStart -Title "Install .NET SDK" + # ... dotnet installation ... + Write-LogGroupEnd -Title "Install .NET SDK" +} +``` + +### Avoid + +```powershell +# Too small - just 2-3 lines +Write-LogGroupStart -Title "Generate Resource Files (ResGen)" +Write-Log -message "Run ResGen" +Start-ResGen +Write-LogGroupEnd -Title "Generate Resource Files (ResGen)" +``` + +## GitHub Actions Syntax + +These functions emit GitHub Actions workflow commands: +- `Write-LogGroupStart` → `::group::Title` +- `Write-LogGroupEnd` → `::endgroup::` + +In the GitHub Actions UI, this renders as collapsible sections with the specified title. + +## Testing + +Test log grouping locally: +```powershell +$env:GITHUB_ACTIONS = 'true' +Import-Module ./build.psm1 +Write-LogGroupStart -Title "Test" +Write-Log -Message "Content" +Write-LogGroupEnd -Title "Test" +``` + +Output should show: +``` +::group::Test +Content +::endgroup:: +``` + +## References + +- [GitHub Actions: Grouping log lines](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines) +- `build.psm1`: `Write-LogGroupStart` and `Write-LogGroupEnd` function definitions diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 1797e2234a6..10b2f0893a3 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -56,7 +56,8 @@ jobs: # queries: ./path/to/local/query, your-org/your-repo/queries@main - run: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + Import-Module .\tools\ci.psm1 + Show-Environment name: Capture Environment shell: pwsh diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index d6b86bfa75f..7a6c5d76adf 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -51,6 +51,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout @@ -68,7 +69,7 @@ jobs: name: Build PowerShell runs-on: ubuntu-latest needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout uses: actions/checkout@v4.1.0 @@ -82,7 +83,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -99,7 +100,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -116,7 +117,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -133,7 +134,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -149,7 +150,7 @@ jobs: name: xUnit Tests needs: - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} uses: ./.github/workflows/xunit-tests.yml with: runner_os: ubuntu-latest diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index bb7faacfde0..cc2a6c2e8e4 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -51,6 +51,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} steps: - name: checkout uses: actions/checkout@v4.1.0 @@ -63,9 +64,9 @@ jobs: ci_build: name: Build PowerShell - runs-on: macos-latest + runs-on: macos-15-large needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout uses: actions/checkout@v4.1.0 @@ -78,8 +79,8 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: macos-latest + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: macos-15-large steps: - name: checkout uses: actions/checkout@v4.1.0 @@ -95,8 +96,8 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: macos-latest + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: macos-15-large steps: - name: checkout uses: actions/checkout@v4.1.0 @@ -112,8 +113,8 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: macos-latest + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: macos-15-large steps: - name: checkout uses: actions/checkout@v4.1.0 @@ -129,8 +130,8 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: macos-latest + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: macos-15-large steps: - name: checkout uses: actions/checkout@v4.1.0 @@ -145,7 +146,7 @@ jobs: name: xUnit Tests needs: - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} uses: ./.github/workflows/xunit-tests.yml with: runner_os: macos-15-large @@ -155,9 +156,9 @@ jobs: name: macOS packaging and testing needs: - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: - - macos-latest + - macos-15-large steps: - name: checkout uses: actions/checkout@v5 @@ -230,4 +231,4 @@ jobs: if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: - needs_context: ${{ toJson(needs) }} \ No newline at end of file + needs_context: ${{ toJson(needs) }} diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index ac362be7153..118da99f366 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -54,6 +54,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout @@ -68,7 +69,7 @@ jobs: ci_build: name: Build PowerShell needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -82,7 +83,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -99,7 +100,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -116,7 +117,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -133,7 +134,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -149,7 +150,7 @@ jobs: name: xUnit Tests needs: - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} uses: ./.github/workflows/xunit-tests.yml with: runner_os: windows-latest @@ -157,7 +158,7 @@ jobs: analyze: name: CodeQL Analysis needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} uses: ./.github/workflows/analyze-reusable.yml permissions: actions: read diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 5a763544c62..6b42a8899ec 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -43,7 +43,8 @@ jobs: - name: Capture Environment if: success() || failure() run: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + Import-Module .\tools\ci.psm1 + Show-Environment shell: pwsh - name: Capture PowerShell Version Table diff --git a/build.psm1 b/build.psm1 index c42f3d1ecf7..2a30d7a0858 100644 --- a/build.psm1 +++ b/build.psm1 @@ -385,7 +385,7 @@ function Start-PSBuild { } if ($Clean) { - Write-Log -message "Cleaning your working directory. You can also do it with 'git clean -fdX --exclude .vs/PowerShell/v16/Server/sqlite3'" + Write-LogGroupStart -Title "Cleaning your working directory" Push-Location $PSScriptRoot try { # Excluded sqlite3 folder is due to this Roslyn issue: https://github.com/dotnet/roslyn/issues/23060 @@ -393,6 +393,7 @@ function Start-PSBuild { # Excluded nuget.config as this is required for release build. git clean -fdX --exclude .vs/PowerShell/v16/Server/sqlite3 --exclude src/Modules/nuget.config --exclude nuget.config } finally { + Write-LogGroupEnd -Title "Cleaning your working directory" Pop-Location } } @@ -536,7 +537,9 @@ Fix steps: } # handle Restore + Write-LogGroupStart -Title "Restore NuGet Packages" Restore-PSPackage -Options $Options -Force:$Restore -InteractiveAuth:$InteractiveAuth + Write-LogGroupEnd -Title "Restore NuGet Packages" # handle ResGen # Heuristic to run ResGen on the fresh machine @@ -566,6 +569,7 @@ Fix steps: $publishPath = $Options.Output } + Write-LogGroupStart -Title "Build PowerShell" try { # Relative paths do not work well if cwd is not changed to project Push-Location $Options.Top @@ -620,6 +624,7 @@ Fix steps: } finally { Pop-Location } + Write-LogGroupEnd -Title "Build PowerShell" # No extra post-building task will run if '-SMAOnly' is specified, because its purpose is for a quick update of S.M.A.dll after full build. if ($SMAOnly) { @@ -627,6 +632,7 @@ Fix steps: } # publish reference assemblies + Write-LogGroupStart -Title "Publish Reference Assemblies" try { Push-Location "$PSScriptRoot/src/TypeCatalogGen" $refAssemblies = Get-Content -Path $incFileName | Where-Object { $_ -like "*microsoft.netcore.app*" } | ForEach-Object { $_.TrimEnd(';') } @@ -640,6 +646,7 @@ Fix steps: } finally { Pop-Location } + Write-LogGroupEnd -Title "Publish Reference Assemblies" if ($ReleaseTag) { $psVersion = $ReleaseTag @@ -682,10 +689,13 @@ Fix steps: # download modules from powershell gallery. # - PowerShellGet, PackageManagement, Microsoft.PowerShell.Archive if ($PSModuleRestore) { + Write-LogGroupStart -Title "Restore PowerShell Modules" Restore-PSModuleToBuild -PublishPath $publishPath + Write-LogGroupEnd -Title "Restore PowerShell Modules" } # publish powershell.config.json + Write-LogGroupStart -Title "Generate PowerShell Configuration" $config = [ordered]@{} if ($Options.Runtime -like "*win*") { @@ -731,10 +741,13 @@ Fix steps: } else { Write-Warning "No powershell.config.json generated for $publishPath" } + Write-LogGroupEnd -Title "Generate PowerShell Configuration" # Restore the Pester module if ($CI) { + Write-LogGroupStart -Title "Restore Pester Module" Restore-PSPester -Destination (Join-Path $publishPath "Modules") + Write-LogGroupEnd -Title "Restore Pester Module" } Clear-NativeDependencies -PublishFolder $publishPath @@ -2086,6 +2099,7 @@ function Install-Dotnet { [string]$FeedCredential ) + Write-LogGroupStart -Title "Install .NET SDK $Version" Write-Verbose -Verbose "In install-dotnet" # This allows sudo install to be optional; needed when running in containers / as root @@ -2220,6 +2234,7 @@ function Install-Dotnet { } } } + Write-LogGroupEnd -Title "Install .NET SDK $Version" } function Get-RedHatPackageManager { @@ -2264,12 +2279,14 @@ function Start-PSBootstrap { try { if ($environment.IsLinux -or $environment.IsMacOS) { + Write-LogGroupStart -Title "Install Native Dependencies" # This allows sudo install to be optional; needed when running in containers / as root # Note that when it is null, Invoke-Expression (but not &) must be used to interpolate properly $sudo = if (!$NoSudo) { "sudo" } if ($BuildLinuxArm -and $environment.IsLinux -and -not $environment.IsUbuntu -and -not $environment.IsMariner) { Write-Error "Cross compiling for linux-arm is only supported on AzureLinux/Ubuntu environment" + Write-LogGroupEnd -Title "Install Native Dependencies" return } @@ -2399,9 +2416,11 @@ function Start-PSBootstrap { } } } + Write-LogGroupEnd -Title "Install Native Dependencies" } if ($Scenario -in 'All', 'Both', 'DotNet') { + Write-LogGroupStart -Title "Install .NET SDK" Write-Verbose -Verbose "Calling Find-Dotnet from Start-PSBootstrap" @@ -2440,10 +2459,12 @@ function Start-PSBootstrap { else { Write-Log -message "dotnet is already installed. Skipping installation." } + Write-LogGroupEnd -Title "Install .NET SDK" } # Install Windows dependencies if `-Package` or `-BuildWindowsNative` is specified if ($environment.IsWindows) { + Write-LogGroupStart -Title "Install Windows Dependencies" ## The VSCode build task requires 'pwsh.exe' to be found in Path if (-not (Get-Command -Name pwsh.exe -CommandType Application -ErrorAction Ignore)) { @@ -2456,9 +2477,11 @@ function Start-PSBootstrap { $isArm64 = "$env:RUNTIME" -eq 'arm64' Install-Wix -arm64:$isArm64 } + Write-LogGroupEnd -Title "Install Windows Dependencies" } if ($Scenario -in 'All', 'Tools') { + Write-LogGroupStart -Title "Install .NET Global Tools" Write-Log -message "Installing .NET global tools" # Ensure dotnet is available @@ -2469,12 +2492,15 @@ function Start-PSBootstrap { Start-NativeExecution { dotnet tool install --global dotnet-format } + Write-LogGroupEnd -Title "Install .NET Global Tools" } if ($env:TF_BUILD) { + Write-LogGroupStart -Title "Capture NuGet Sources" Write-Verbose -Verbose "--- Start - Capturing nuget sources" dotnet nuget list source --format detailed Write-Verbose -Verbose "--- End - Capturing nuget sources" + Write-LogGroupEnd -Title "Capture NuGet Sources" } } finally { Pop-Location diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 44651c26109..478435e8543 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -688,6 +688,14 @@ function Set-Path } } +# Display environment variables in a log group for GitHub Actions +function Show-Environment +{ + Write-LogGroupStart -Title 'Environment' + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | Write-Verbose -Verbose + Write-LogGroupEnd -Title 'Environment' +} + # Bootstrap script for Linux and macOS function Invoke-BootstrapStage { From 59c263927afc5f63be036809ddbf646e635c54e9 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 14:09:01 -0800 Subject: [PATCH 192/275] [release/v7.5] Add reusable get-changed-files action and refactor existing actions (#26811) --- .../get-changed-files/README.md | 122 ++++++++++++++++++ .../get-changed-files/action.yml | 117 +++++++++++++++++ .../infrastructure/markdownlinks/action.yml | 47 ++----- .../infrastructure/path-filters/action.yml | 107 ++++++++------- 4 files changed, 309 insertions(+), 84 deletions(-) create mode 100644 .github/actions/infrastructure/get-changed-files/README.md create mode 100644 .github/actions/infrastructure/get-changed-files/action.yml diff --git a/.github/actions/infrastructure/get-changed-files/README.md b/.github/actions/infrastructure/get-changed-files/README.md new file mode 100644 index 00000000000..277b28c0674 --- /dev/null +++ b/.github/actions/infrastructure/get-changed-files/README.md @@ -0,0 +1,122 @@ +# Get Changed Files Action + +A reusable composite action that retrieves the list of files changed in a pull request or push event. + +## Features + +- Supports both `pull_request` and `push` events +- Optional filtering by file pattern +- Returns files as JSON array for easy consumption +- Filters out deleted files (only returns added, modified, or renamed files) +- Handles up to 100 changed files per request + +## Usage + +### Basic Usage (Pull Requests Only) + +```yaml +- name: Get changed files + id: changed-files + uses: "./.github/actions/infrastructure/get-changed-files" + +- name: Process files + run: | + echo "Changed files: ${{ steps.changed-files.outputs.files }}" + echo "Count: ${{ steps.changed-files.outputs.count }}" +``` + +### With Filtering + +```yaml +# Get only markdown files +- name: Get changed markdown files + id: changed-md + uses: "./.github/actions/infrastructure/get-changed-files" + with: + filter: '*.md' + +# Get only GitHub workflow/action files +- name: Get changed GitHub files + id: changed-github + uses: "./.github/actions/infrastructure/get-changed-files" + with: + filter: '.github/' +``` + +### Support Both PR and Push Events + +```yaml +- name: Get changed files + id: changed-files + uses: "./.github/actions/infrastructure/get-changed-files" + with: + event-types: 'pull_request,push' +``` + +## Inputs + +| Name | Description | Required | Default | +|------|-------------|----------|---------| +| `filter` | Optional filter pattern (e.g., `*.md` for markdown files, `.github/` for GitHub files) | No | `''` | +| `event-types` | Comma-separated list of event types to support (`pull_request`, `push`) | No | `pull_request` | + +## Outputs + +| Name | Description | +|------|-------------| +| `files` | JSON array of changed file paths | +| `count` | Number of changed files | + +## Filter Patterns + +The action supports simple filter patterns: + +- **Extension matching**: Use `*.ext` to match files with a specific extension + - Example: `*.md` matches all markdown files + - Example: `*.yml` matches all YAML files + +- **Path prefix matching**: Use a path prefix to match files in a directory + - Example: `.github/` matches all files in the `.github` directory + - Example: `tools/` matches all files in the `tools` directory + +## Example: Processing Changed Files + +```yaml +- name: Get changed files + id: changed-files + uses: "./.github/actions/infrastructure/get-changed-files" + +- name: Process each file + shell: pwsh + env: + CHANGED_FILES: ${{ steps.changed-files.outputs.files }} + run: | + $changedFilesJson = $env:CHANGED_FILES + $changedFiles = $changedFilesJson | ConvertFrom-Json + + foreach ($file in $changedFiles) { + Write-Host "Processing: $file" + # Your processing logic here + } +``` + +## Limitations + +- Simple filter patterns only (no complex glob or regex patterns) + +## Pagination + +The action automatically handles pagination to fetch **all** changed files in a PR, regardless of how many files were changed: + +- Fetches files in batches of 100 per page +- Continues fetching until all files are retrieved +- Logs a note when pagination occurs, showing the total file count +- **No file limit** - all changed files will be processed, even in very large PRs + +This ensures that critical workflows (such as merge conflict checking, link validation, etc.) don't miss files due to pagination limits. + +## Related Actions + +- **markdownlinks**: Uses this pattern to get changed markdown files +- **merge-conflict-checker**: Uses this pattern to get changed files for conflict detection +- **path-filters**: Similar functionality but with more complex filtering logic diff --git a/.github/actions/infrastructure/get-changed-files/action.yml b/.github/actions/infrastructure/get-changed-files/action.yml new file mode 100644 index 00000000000..c897d4f388d --- /dev/null +++ b/.github/actions/infrastructure/get-changed-files/action.yml @@ -0,0 +1,117 @@ +name: 'Get Changed Files' +description: 'Gets the list of files changed in a pull request or push event' +inputs: + filter: + description: 'Optional filter pattern (e.g., "*.md" for markdown files, ".github/" for GitHub files)' + required: false + default: '' + event-types: + description: 'Comma-separated list of event types to support (pull_request, push)' + required: false + default: 'pull_request' +outputs: + files: + description: 'JSON array of changed file paths' + value: ${{ steps.get-files.outputs.files }} + count: + description: 'Number of changed files' + value: ${{ steps.get-files.outputs.count }} +runs: + using: 'composite' + steps: + - name: Get changed files + id: get-files + uses: actions/github-script@v7 + with: + script: | + const eventTypes = '${{ inputs.event-types }}'.split(',').map(t => t.trim()); + const filter = '${{ inputs.filter }}'; + let changedFiles = []; + + if (eventTypes.includes('pull_request') && context.eventName === 'pull_request') { + console.log(`Getting files changed in PR #${context.payload.pull_request.number}`); + + // Fetch all files changed in the PR with pagination + let allFiles = []; + let page = 1; + let fetchedCount; + + do { + const { data: files } = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + per_page: 100, + page: page + }); + + allFiles = allFiles.concat(files); + fetchedCount = files.length; + page++; + } while (fetchedCount === 100); + + if (allFiles.length >= 100) { + console.log(`Note: This PR has ${allFiles.length} changed files. All files fetched using pagination.`); + } + + changedFiles = allFiles + .filter(file => file.status === 'added' || file.status === 'modified' || file.status === 'renamed') + .map(file => file.filename); + + } else if (eventTypes.includes('push') && context.eventName === 'push') { + console.log(`Getting files changed in push to ${context.ref}`); + + const { data: comparison } = await github.rest.repos.compareCommits({ + owner: context.repo.owner, + repo: context.repo.repo, + base: context.payload.before, + head: context.payload.after, + }); + + changedFiles = comparison.files + .filter(file => file.status === 'added' || file.status === 'modified' || file.status === 'renamed') + .map(file => file.filename); + + } else { + core.setFailed(`Unsupported event type: ${context.eventName}. Supported types: ${eventTypes.join(', ')}`); + return; + } + + // Apply filter if provided + if (filter) { + const filterLower = filter.toLowerCase(); + const beforeFilter = changedFiles.length; + changedFiles = changedFiles.filter(file => { + const fileLower = file.toLowerCase(); + // Support simple patterns like "*.md" or ".github/" + if (filterLower.startsWith('*.')) { + const ext = filterLower.substring(1); + return fileLower.endsWith(ext); + } else { + return fileLower.startsWith(filterLower); + } + }); + console.log(`Filter '${filter}' applied: ${beforeFilter} → ${changedFiles.length} files`); + } + + // Calculate simple hash for verification + const crypto = require('crypto'); + const filesJson = JSON.stringify(changedFiles.sort()); + const hash = crypto.createHash('sha256').update(filesJson).digest('hex').substring(0, 8); + + // Log changed files in a collapsible group + core.startGroup(`Changed Files (${changedFiles.length} total, hash: ${hash})`); + if (changedFiles.length > 0) { + changedFiles.forEach(file => console.log(` - ${file}`)); + } else { + console.log(' (no files changed)'); + } + core.endGroup(); + + console.log(`Found ${changedFiles.length} changed files`); + core.setOutput('files', JSON.stringify(changedFiles)); + core.setOutput('count', changedFiles.length); + +branding: + icon: 'file-text' + color: 'blue' diff --git a/.github/actions/infrastructure/markdownlinks/action.yml b/.github/actions/infrastructure/markdownlinks/action.yml index 1d6d0864784..de2952252d4 100644 --- a/.github/actions/infrastructure/markdownlinks/action.yml +++ b/.github/actions/infrastructure/markdownlinks/action.yml @@ -31,52 +31,23 @@ runs: steps: - name: Get changed markdown files id: changed-files - uses: actions/github-script@v7 + uses: "./.github/actions/infrastructure/get-changed-files" with: - script: | - let changedMarkdownFiles = []; - - if (context.eventName === 'pull_request') { - const { data: files } = await github.rest.pulls.listFiles({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.payload.pull_request.number, - }); - - changedMarkdownFiles = files - .filter(file => file.filename.endsWith('.md')) - .map(file => file.filename); - } else if (context.eventName === 'push') { - const { data: comparison } = await github.rest.repos.compareCommits({ - owner: context.repo.owner, - repo: context.repo.repo, - base: context.payload.before, - head: context.payload.after, - }); - - changedMarkdownFiles = comparison.files - .filter(file => file.filename.endsWith('.md')) - .map(file => file.filename); - } else { - core.setFailed(`Unsupported event type: ${context.eventName}. This action only supports 'pull_request' and 'push' events.`); - return; - } - - console.log('Changed markdown files:', changedMarkdownFiles); - core.setOutput('files', JSON.stringify(changedMarkdownFiles)); - core.setOutput('count', changedMarkdownFiles.length); - return changedMarkdownFiles; + filter: '*.md' + event-types: 'pull_request,push' - name: Verify markdown links id: verify shell: pwsh + env: + CHANGED_FILES_JSON: ${{ steps.changed-files.outputs.files }} run: | Write-Host "Starting markdown link verification..." -ForegroundColor Cyan - # Get changed markdown files from previous step - $changedFilesJson = '${{ steps.changed-files.outputs.files }}' + # Get changed markdown files from environment variable (secure against injection) + $changedFilesJson = $env:CHANGED_FILES_JSON $changedFiles = $changedFilesJson | ConvertFrom-Json - + if ($changedFiles.Count -eq 0) { Write-Host "No markdown files changed, skipping verification" -ForegroundColor Yellow "total=0" >> $env:GITHUB_OUTPUT @@ -85,7 +56,7 @@ runs: "skipped=0" >> $env:GITHUB_OUTPUT exit 0 } - + Write-Host "Changed markdown files: $($changedFiles.Count)" -ForegroundColor Cyan $changedFiles | ForEach-Object { Write-Host " - $_" -ForegroundColor Gray } diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml index fd48e8091d6..656719262b2 100644 --- a/.github/actions/infrastructure/path-filters/action.yml +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -32,9 +32,16 @@ outputs: runs: using: composite steps: + - name: Get changed files + id: get-files + if: github.event_name == 'pull_request' + uses: "./.github/actions/infrastructure/get-changed-files" + - name: Check if GitHubWorkflowChanges is present id: filter uses: actions/github-script@v7.0.1 + env: + FILES_JSON: ${{ steps.get-files.outputs.files }} with: github-token: ${{ inputs.GITHUB_TOKEN }} script: | @@ -53,52 +60,71 @@ runs: return; } - console.log(`Getting files changed in PR #${context.issue.number}`); - - // Fetch the list of files changed in the PR - let files = []; - let page = 1; - let fetchedFiles; - do { - fetchedFiles = await github.rest.pulls.listFiles({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.issue.number, - per_page: 100, - page: page++ - }); - files = files.concat(fetchedFiles.data); - } while (fetchedFiles.data.length > 0); - - const actionsChanged = files.some(file => file.filename.startsWith('.github/actions')); - const workflowsChanged = files.some(file => file.filename.startsWith('.github/workflows')); + // Get files from environment variable (secure against injection) + const files = JSON.parse(process.env.FILES_JSON || '[]'); + + // Calculate hash for verification (matches get-changed-files action) + const crypto = require('crypto'); + const filesJson = JSON.stringify(files.sort()); + const hash = crypto.createHash('sha256').update(filesJson).digest('hex').substring(0, 8); + console.log(`Received ${files.length} files (hash: ${hash})`); + + // Analyze changes with detailed logging + core.startGroup('Path Filter Analysis'); + + const actionsChanged = files.some(file => file.startsWith('.github/actions')); + console.log(`✓ Actions changed: ${actionsChanged}`); + + const workflowsChanged = files.some(file => file.startsWith('.github/workflows')); + console.log(`✓ Workflows changed: ${workflowsChanged}`); + const githubChanged = actionsChanged || workflowsChanged; + console.log(`→ GitHub changed (actions OR workflows): ${githubChanged}`); + + const toolsCiPsm1Changed = files.some(file => file === 'tools/ci.psm1'); + console.log(`✓ tools/ci.psm1 changed: ${toolsCiPsm1Changed}`); + + const toolsBuildCommonChanged = files.some(file => file.startsWith('tools/buildCommon/')); + console.log(`✓ tools/buildCommon/ changed: ${toolsBuildCommonChanged}`); - const toolsCiPsm1Changed = files.some(file => file.filename.startsWith('tools/ci.psm1')); - const toolsBuildCommonChanged = files.some(file => file.filename.startsWith('tools/buildCommon/')); const toolsChanged = toolsCiPsm1Changed || toolsBuildCommonChanged; + console.log(`→ Tools changed: ${toolsChanged}`); + + const propsChanged = files.some(file => file.endsWith('.props')); + console.log(`✓ Props files changed: ${propsChanged}`); - const propsChanged = files.some(file => file.filename.endsWith('.props')); + const testsChanged = files.some(file => file.startsWith('test/powershell/') || file.startsWith('test/tools/') || file.startsWith('test/xUnit/')); + console.log(`✓ Tests changed: ${testsChanged}`); - const testsChanged = files.some(file => file.filename.startsWith('test/powershell/') || file.filename.startsWith('test/tools/') || file.filename.startsWith('test/xUnit/')); + const mainSourceChanged = files.some(file => file.startsWith('src/')); + console.log(`✓ Main source (src/) changed: ${mainSourceChanged}`); - const mainSourceChanged = files.some(file => file.filename.startsWith('src/')); + const buildModuleChanged = files.some(file => file === 'build.psm1'); + console.log(`✓ build.psm1 changed: ${buildModuleChanged}`); - const buildModuleChanged = files.some(file => file.filename.startsWith('build.psm1')); + const globalConfigChanged = files.some(file => file === '.globalconfig' || file === 'nuget.config' || file === 'global.json'); + console.log(`✓ Global config changed: ${globalConfigChanged}`); - const packagingChanged = files.some(file => - file.filename === '.github/workflows/windows-ci.yml' || - file.filename.startsWith('assets/wix/') || - file.filename === 'PowerShell.Common.props' || - file.filename.match(/^src\/.*\.csproj$/) || - file.filename.startsWith('test/packaging/windows/') || - file.filename.startsWith('tools/packaging/') || - file.filename.startsWith('tools/wix/') + const packagingChanged = files.some(file => + file === '.github/workflows/windows-ci.yml' || + file === '.github/workflows/linux-ci.yml' || + file.startsWith('assets/wix/') || + file === 'PowerShell.Common.props' || + file.match(/^src\/.*\.csproj$/) || + file.startsWith('test/packaging/windows/') || + file.startsWith('test/packaging/linux/') || + file.startsWith('tools/packaging/') || + file.startsWith('tools/wix/') ) || buildModuleChanged || + globalConfigChanged || toolsCiPsm1Changed; + console.log(`→ Packaging changed: ${packagingChanged}`); - const source = mainSourceChanged || toolsChanged || githubChanged || propsChanged || testsChanged; + const source = mainSourceChanged || toolsChanged || githubChanged || propsChanged || testsChanged || globalConfigChanged; + console.log(`→ Source (composite): ${source}`); + + core.endGroup(); core.setOutput('toolsChanged', toolsChanged); core.setOutput('githubChanged', githubChanged); @@ -106,17 +132,6 @@ runs: core.setOutput('testsChanged', testsChanged); core.setOutput('mainSourceChanged', mainSourceChanged); core.setOutput('buildModuleChanged', buildModuleChanged); + core.setOutput('globalConfigChanged', globalConfigChanged); core.setOutput('packagingChanged', packagingChanged); core.setOutput('source', source); - - - name: Capture outputs - run: | - Write-Verbose -Verbose "source: ${{ steps.filter.outputs.source }}" - Write-Verbose -Verbose "github: ${{ steps.filter.outputs.githubChanged }}" - Write-Verbose -Verbose "tools: ${{ steps.filter.outputs.toolsChanged }}" - Write-Verbose -Verbose "props: ${{ steps.filter.outputs.propsChanged }}" - Write-Verbose -Verbose "tests: ${{ steps.filter.outputs.testsChanged }}" - Write-Verbose -Verbose "mainSource: ${{ steps.filter.outputs.mainSourceChanged }}" - Write-Verbose -Verbose "buildModule: ${{ steps.filter.outputs.buildModuleChanged }}" - Write-Verbose -Verbose "packaging: ${{ steps.filter.outputs.packagingChanged }}" - shell: pwsh From 458071221eb5f120b5b226c8da8c0e1136f80028 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 14:44:52 -0800 Subject: [PATCH 193/275] [release/v7.5] Add merge conflict marker detection to linux-ci workflow and refactor existing actions to use reusable get-changed-files action (#26812) --- .../merge-conflict-checker/README.md | 84 ++++++ .../merge-conflict-checker/action.yml | 36 +++ .../actions/test/linux-packaging/action.yml | 6 + ...rshell-automatic-variables.instructions.md | 159 ++++++++++++ ...rshell-module-organization.instructions.md | 201 +++++++++++++++ .github/workflows/linux-ci.yml | 84 +++++- .github/workflows/macos-ci.yml | 8 + .vsts-ci/templates/nanoserver.yml | 61 ----- test/infrastructure/ciModule.Tests.ps1 | 240 ++++++++++++++++++ tools/ci.psm1 | 210 ++++++++++++++- 10 files changed, 1015 insertions(+), 74 deletions(-) create mode 100644 .github/actions/infrastructure/merge-conflict-checker/README.md create mode 100644 .github/actions/infrastructure/merge-conflict-checker/action.yml create mode 100644 .github/instructions/powershell-automatic-variables.instructions.md create mode 100644 .github/instructions/powershell-module-organization.instructions.md delete mode 100644 .vsts-ci/templates/nanoserver.yml create mode 100644 test/infrastructure/ciModule.Tests.ps1 diff --git a/.github/actions/infrastructure/merge-conflict-checker/README.md b/.github/actions/infrastructure/merge-conflict-checker/README.md new file mode 100644 index 00000000000..aeae4a29b93 --- /dev/null +++ b/.github/actions/infrastructure/merge-conflict-checker/README.md @@ -0,0 +1,84 @@ +# Merge Conflict Checker + +This composite GitHub Action checks for Git merge conflict markers in files changed in pull requests. + +## Purpose + +Automatically detects leftover merge conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) in pull request files to prevent them from being merged into the codebase. + +## Usage + +### In a Workflow + +```yaml +- name: Check for merge conflict markers + uses: "./.github/actions/infrastructure/merge-conflict-checker" +``` + +### Complete Example + +```yaml +jobs: + merge_conflict_check: + name: Check for Merge Conflict Markers + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + permissions: + pull-requests: read + contents: read + steps: + - name: checkout + uses: actions/checkout@v5 + + - name: Check for merge conflict markers + uses: "./.github/actions/infrastructure/merge-conflict-checker" +``` + +## How It Works + +1. **File Detection**: Uses GitHub's API to get the list of files changed in the pull request +2. **Marker Scanning**: Reads each changed file and searches for the following markers: + - `<<<<<<<` (conflict start marker) + - `=======` (conflict separator) + - `>>>>>>>` (conflict end marker) +3. **Result Reporting**: + - If markers are found, the action fails and lists all affected files + - If no markers are found, the action succeeds + +## Outputs + +- `files-checked`: Number of files that were checked +- `conflicts-found`: Number of files containing merge conflict markers + +## Behavior + +- **Event Support**: Only works with `pull_request` events +- **File Handling**: + - Checks only files that were added, modified, or renamed + - Skips deleted files + - Skips binary/unreadable files + - Skips directories + +## Example Output + +When conflict markers are detected: + +``` +❌ Merge conflict markers detected in the following files: + - src/example.cs + Markers found: <<<<<<<, =======, >>>>>>> + - README.md + Markers found: <<<<<<<, =======, >>>>>>> + +Please resolve these conflicts before merging. +``` + +When no markers are found: + +``` +✅ No merge conflict markers found +``` + +## Integration + +This action is integrated into the `linux-ci.yml` workflow and runs automatically on all pull requests to ensure code quality before merging. diff --git a/.github/actions/infrastructure/merge-conflict-checker/action.yml b/.github/actions/infrastructure/merge-conflict-checker/action.yml new file mode 100644 index 00000000000..a86cfa5470a --- /dev/null +++ b/.github/actions/infrastructure/merge-conflict-checker/action.yml @@ -0,0 +1,36 @@ +name: 'Check for Merge Conflict Markers' +description: 'Checks for Git merge conflict markers in changed files for pull requests' +author: 'PowerShell Team' + +outputs: + files-checked: + description: 'Number of files checked for merge conflict markers' + value: ${{ steps.check.outputs.files-checked }} + conflicts-found: + description: 'Number of files with merge conflict markers' + value: ${{ steps.check.outputs.conflicts-found }} + +runs: + using: 'composite' + steps: + - name: Get changed files + id: changed-files + uses: "./.github/actions/infrastructure/get-changed-files" + + - name: Check for merge conflict markers + id: check + shell: pwsh + env: + CHANGED_FILES_JSON: ${{ steps.changed-files.outputs.files }} + run: | + # Get changed files from environment variable (secure against injection) + $changedFilesJson = $env:CHANGED_FILES_JSON + $changedFiles = $changedFilesJson | ConvertFrom-Json + + # Import ci.psm1 and run the check + Import-Module "$env:GITHUB_WORKSPACE/tools/ci.psm1" -Force + Test-MergeConflictMarker -File $changedFiles -WorkspacePath $env:GITHUB_WORKSPACE + +branding: + icon: 'alert-triangle' + color: 'red' diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index a04e09b6a5c..ef9ba23e799 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -80,6 +80,12 @@ runs: Invoke-CIFinish shell: pwsh + - name: Install Pester + run: |- + Import-Module ./tools/ci.psm1 + Install-CIPester + shell: pwsh + - name: Validate Package Names run: |- # Run Pester tests to validate package names diff --git a/.github/instructions/powershell-automatic-variables.instructions.md b/.github/instructions/powershell-automatic-variables.instructions.md new file mode 100644 index 00000000000..5015847f41f --- /dev/null +++ b/.github/instructions/powershell-automatic-variables.instructions.md @@ -0,0 +1,159 @@ +--- +applyTo: + - "**/*.ps1" + - "**/*.psm1" +--- + +# PowerShell Automatic Variables - Naming Guidelines + +## Purpose + +This instruction provides guidelines for avoiding conflicts with PowerShell's automatic variables when writing PowerShell scripts and modules. + +## What Are Automatic Variables? + +PowerShell has built-in automatic variables that are created and maintained by PowerShell itself. Assigning values to these variables can cause unexpected behavior and side effects. + +## Common Automatic Variables to Avoid + +### Critical Variables (Never Use) + +- **`$matches`** - Contains the results of regular expression matches. Overwriting this can break regex operations. +- **`$_`** - Represents the current object in the pipeline. Only use within pipeline blocks. +- **`$PSItem`** - Alias for `$_`. Same rules apply. +- **`$args`** - Contains an array of undeclared parameters. Don't use as a regular variable. +- **`$input`** - Contains an enumerator of all input passed to a function. Don't reassign. +- **`$LastExitCode`** - Exit code of the last native command. Don't overwrite unless intentional. +- **`$?`** - Success status of the last command. Don't use as a variable name. +- **`$$`** - Last token in the last line received by the session. Don't use. +- **`$^`** - First token in the last line received by the session. Don't use. + +### Context Variables (Use with Caution) + +- **`$Error`** - Array of error objects. Don't replace, but can modify (e.g., `$Error.Clear()`). +- **`$PSBoundParameters`** - Parameters passed to the current function. Read-only. +- **`$MyInvocation`** - Information about the current command. Read-only. +- **`$PSCmdlet`** - Cmdlet object for advanced functions. Read-only. + +### Other Common Automatic Variables + +- `$true`, `$false`, `$null` - Boolean and null constants +- `$HOME`, `$PSHome`, `$PWD` - Path-related variables +- `$PID` - Process ID of the current PowerShell session +- `$Host` - Host application object +- `$PSVersionTable` - PowerShell version information + +For a complete list, see: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_automatic_variables + +## Best Practices + +### ❌ Bad - Using Automatic Variable Names + +```powershell +# Bad: $matches is an automatic variable used for regex capture groups +$matches = Select-String -Path $file -Pattern $pattern + +# Bad: $args is an automatic variable for undeclared parameters +$args = Get-ChildItem + +# Bad: $input is an automatic variable for pipeline input +$input = Read-Host "Enter value" +``` + +### ✅ Good - Using Descriptive Alternative Names + +```powershell +# Good: Use descriptive names that avoid conflicts +$matchedLines = Select-String -Path $file -Pattern $pattern + +# Good: Use specific names for arguments +$arguments = Get-ChildItem + +# Good: Use specific names for user input +$userInput = Read-Host "Enter value" +``` + +## Naming Alternatives + +When you encounter a situation where you might use an automatic variable name, use these alternatives: + +| Avoid | Use Instead | +|-------|-------------| +| `$matches` | `$matchedLines`, `$matchResults`, `$regexMatches` | +| `$args` | `$arguments`, `$parameters`, `$commandArgs` | +| `$input` | `$userInput`, `$inputValue`, `$inputData` | +| `$_` (outside pipeline) | Use a named parameter or explicit variable | +| `$Error` (reassignment) | Don't reassign; use `$Error.Clear()` if needed | + +## How to Check + +### PSScriptAnalyzer Rule + +PSScriptAnalyzer has a built-in rule that detects assignments to automatic variables: + +```powershell +# This will trigger PSAvoidAssignmentToAutomaticVariable +$matches = Get-Something +``` + +**Rule ID**: PSAvoidAssignmentToAutomaticVariable + +### Manual Review + +When writing PowerShell code, always: +1. Avoid variable names that match PowerShell keywords or automatic variables +2. Use descriptive, specific names that clearly indicate the variable's purpose +3. Run PSScriptAnalyzer on your code before committing +4. Review code for variable naming during PR reviews + +## Examples from the Codebase + +### Example 1: Regex Matching + +```powershell +# ❌ Bad - Overwrites automatic $matches variable +$matches = [regex]::Matches($content, $pattern) + +# ✅ Good - Uses descriptive name +$regexMatches = [regex]::Matches($content, $pattern) +``` + +### Example 2: Select-String Results + +```powershell +# ❌ Bad - Conflicts with automatic $matches +$matches = Select-String -Path $file -Pattern $pattern + +# ✅ Good - Clear and specific +$matchedLines = Select-String -Path $file -Pattern $pattern +``` + +### Example 3: Collecting Arguments + +```powershell +# ❌ Bad - Conflicts with automatic $args +function Process-Items { + $args = $MyItems + # ... process items +} + +# ✅ Good - Descriptive parameter name +function Process-Items { + [CmdletBinding()] + param( + [Parameter(ValueFromRemainingArguments)] + [string[]]$Items + ) + # ... process items +} +``` + +## References + +- [PowerShell Automatic Variables Documentation](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_automatic_variables) +- [PSScriptAnalyzer Rules](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/docs/Rules/README.md) +- [PowerShell Best Practices](https://learn.microsoft.com/powershell/scripting/developer/cmdlet/strongly-encouraged-development-guidelines) + +## Summary + +**Key Takeaway**: Always use descriptive, specific variable names that clearly indicate their purpose and avoid conflicts with PowerShell's automatic variables. When in doubt, choose a longer, more descriptive name over a short one that might conflict. diff --git a/.github/instructions/powershell-module-organization.instructions.md b/.github/instructions/powershell-module-organization.instructions.md new file mode 100644 index 00000000000..461d19fb5df --- /dev/null +++ b/.github/instructions/powershell-module-organization.instructions.md @@ -0,0 +1,201 @@ +--- +applyTo: + - "tools/ci.psm1" + - "build.psm1" + - "tools/packaging/**/*.psm1" + - ".github/**/*.yml" + - ".github/**/*.yaml" +--- + +# Guidelines for PowerShell Code Organization + +## When to Move Code from YAML to PowerShell Modules + +PowerShell code in GitHub Actions YAML files should be kept minimal. Move code to a module when: + +### Size Threshold +- **More than ~30 lines** of PowerShell in a YAML file step +- **Any use of .NET types** like `[regex]`, `[System.IO.Path]`, etc. +- **Complex logic** requiring multiple nested loops or conditionals +- **Reusable functionality** that might be needed elsewhere + +### Indicators to Move Code +1. Using .NET type accelerators (`[regex]`, `[PSCustomObject]`, etc.) +2. Complex string manipulation or parsing +3. File system operations beyond basic reads/writes +4. Logic that would benefit from unit testing +5. Code that's difficult to read/maintain in YAML format + +## Which Module to Use + +### ci.psm1 (`tools/ci.psm1`) +**Purpose**: CI/CD-specific operations and workflows + +**Use for**: +- Build orchestration (invoking builds, tests, packaging) +- CI environment setup and configuration +- Test execution and result processing +- Artifact handling and publishing +- CI-specific validations and checks +- Environment variable management for CI + +**Examples**: +- `Invoke-CIBuild` - Orchestrates build process +- `Invoke-CITest` - Runs Pester tests +- `Test-MergeConflictMarker` - Validates files for conflicts +- `Set-BuildVariable` - Manages CI variables + +**When NOT to use**: +- Core build operations (use build.psm1) +- Package creation logic (use packaging.psm1) +- Platform-specific build steps + +### build.psm1 (`build.psm1`) +**Purpose**: Core build operations and utilities + +**Use for**: +- Compiling source code +- Resource generation +- Build configuration management +- Core build utilities (New-PSOptions, Get-PSOutput, etc.) +- Bootstrap operations +- Cross-platform build helpers + +**Examples**: +- `Start-PSBuild` - Main build function +- `Start-PSBootstrap` - Bootstrap dependencies +- `New-PSOptions` - Create build configuration +- `Start-ResGen` - Generate resources + +**When NOT to use**: +- CI workflow orchestration (use ci.psm1) +- Package creation (use packaging.psm1) +- Test execution + +### packaging.psm1 (`tools/packaging/packaging.psm1`) +**Purpose**: Package creation and distribution + +**Use for**: +- Creating distribution packages (MSI, RPM, DEB, etc.) +- Package-specific metadata generation +- Package signing operations +- Platform-specific packaging logic + +**Examples**: +- `Start-PSPackage` - Create packages +- `New-MSIPackage` - Create Windows MSI +- `New-DotnetSdkContainerFxdPackage` - Create container packages + +**When NOT to use**: +- Building binaries (use build.psm1) +- Running tests (use ci.psm1) +- General utilities + +## Best Practices + +### Keep YAML Minimal +```yaml +# ❌ Bad - too much logic in YAML +- name: Check files + shell: pwsh + run: | + $files = Get-ChildItem -Recurse + foreach ($file in $files) { + $content = Get-Content $file -Raw + if ($content -match $pattern) { + # ... complex processing ... + } + } + +# ✅ Good - call function from module +- name: Check files + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Test-SomeCondition -Path ${{ github.workspace }} +``` + +### Document Functions +Always include comment-based help for functions: +```powershell +function Test-MyFunction +{ + <# + .SYNOPSIS + Brief description + .DESCRIPTION + Detailed description + .PARAMETER ParameterName + Parameter description + .EXAMPLE + Test-MyFunction -ParameterName Value + #> + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string] $ParameterName + ) + # Implementation +} +``` + +### Error Handling +Use proper error handling in modules: +```powershell +try { + # Operation +} +catch { + Write-Error "Detailed error message: $_" + throw +} +``` + +### Verbose Output +Use `Write-Verbose` for debugging information: +```powershell +Write-Verbose "Processing file: $filePath" +``` + +## Module Dependencies + +- **ci.psm1** imports both `build.psm1` and `packaging.psm1` +- **build.psm1** is standalone (minimal dependencies) +- **packaging.psm1** imports `build.psm1` + +When adding new functions, consider these import relationships to avoid circular dependencies. + +## Testing Modules + +Functions in modules should be testable: +```powershell +# Test locally +Import-Module ./tools/ci.psm1 -Force +Test-MyFunction -Parameter Value + +# Can be unit tested with Pester +Describe "Test-MyFunction" { + It "Should return expected result" { + # Test implementation + } +} +``` + +## Migration Checklist + +When moving code from YAML to a module: + +1. ✅ Determine which module is appropriate (ci, build, or packaging) +2. ✅ Create function with proper parameter validation +3. ✅ Add comment-based help documentation +4. ✅ Use `[CmdletBinding()]` for advanced function features +5. ✅ Include error handling +6. ✅ Add verbose output for debugging +7. ✅ Test the function independently +8. ✅ Update YAML to call the new function +9. ✅ Verify the workflow still works end-to-end + +## References + +- PowerShell Advanced Functions: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_functions_advanced +- Comment-Based Help: https://learn.microsoft.com/powershell/scripting/developer/help/writing-help-for-windows-powershell-scripts-and-functions diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 7a6c5d76adf..b92b58fea5f 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -65,6 +65,20 @@ jobs: with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + merge_conflict_check: + name: Check for Merge Conflict Markers + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' && (startsWith(github.repository_owner, 'azure') || github.repository_owner == 'PowerShell') + permissions: + pull-requests: read + contents: read + steps: + - name: checkout + uses: actions/checkout@v5 + + - name: Check for merge conflict markers + uses: "./.github/actions/infrastructure/merge-conflict-checker" + ci_build: name: Build PowerShell runs-on: ubuntu-latest @@ -156,17 +170,60 @@ jobs: runner_os: ubuntu-latest test_results_artifact_name: testResults-xunit - analyze: - name: CodeQL Analysis - needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} - uses: ./.github/workflows/analyze-reusable.yml - permissions: - actions: read - contents: read - security-events: write - with: - runner_os: ubuntu-latest + infrastructure_tests: + name: Infrastructure Tests + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v5 + with: + fetch-depth: 1 + + - name: Install Pester + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Install-CIPester + + - name: Run Infrastructure Tests + shell: pwsh + run: | + $testResultsFolder = Join-Path $PWD "testResults" + New-Item -ItemType Directory -Path $testResultsFolder -Force | Out-Null + + $config = New-PesterConfiguration + $config.Run.Path = './test/infrastructure/' + $config.Run.PassThru = $true + $config.TestResult.Enabled = $true + $config.TestResult.OutputFormat = 'NUnitXml' + $config.TestResult.OutputPath = "$testResultsFolder/InfrastructureTests.xml" + $config.Output.Verbosity = 'Detailed' + + $result = Invoke-Pester -Configuration $config + + if ($result.FailedCount -gt 0 -or $result.Result -eq 'Failed') { + throw "Infrastructure tests failed" + } + + - name: Publish Test Results + uses: "./.github/actions/test/process-pester-results" + if: always() + with: + name: "InfrastructureTests" + testResultsFolder: "${{ github.workspace }}/testResults" + + ## Temporarily disable the CodeQL analysis on Linux as it doesn't work for .NET SDK 10-rc.2. + # analyze: + # name: CodeQL Analysis + # needs: changes + # if: ${{ needs.changes.outputs.source == 'true' }} + # uses: ./.github/workflows/analyze-reusable.yml + # permissions: + # actions: read + # contents: read + # security-events: write + # with: + # runner_os: ubuntu-latest ready_to_merge: name: Linux ready to merge @@ -178,6 +235,9 @@ jobs: - linux_test_unelevated_others - analyze - linux_packaging + - merge_conflict_check + - infrastructure_tests + # - analyze if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: @@ -195,4 +255,4 @@ jobs: with: fetch-depth: 0 - name: Linux Packaging - uses: "./.github/actions/test/linux-packaging" \ No newline at end of file + uses: "./.github/actions/test/linux-packaging" diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index cc2a6c2e8e4..14c15bd288d 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -186,6 +186,14 @@ jobs: $macOSRuntime = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'osx-arm64' } else { 'osx-x64' } Start-PSPackage -Type osxpkg -ReleaseTag $releaseTag -MacOSRuntime $macOSRuntime -SkipReleaseChecks shell: pwsh + + - name: Install Pester + if: success() + run: |- + Import-Module ./tools/ci.psm1 + Install-CIPester + shell: pwsh + - name: Test package contents if: success() run: |- diff --git a/.vsts-ci/templates/nanoserver.yml b/.vsts-ci/templates/nanoserver.yml deleted file mode 100644 index ae9f639b3b2..00000000000 --- a/.vsts-ci/templates/nanoserver.yml +++ /dev/null @@ -1,61 +0,0 @@ -parameters: - vmImage: 'windows-latest' - jobName: 'Nanoserver_Tests' - continueOnError: false - -jobs: - -- job: ${{ parameters.jobName }} - variables: - scriptName: ${{ parameters.scriptName }} - - pool: - vmImage: ${{ parameters.vmImage }} - - displayName: ${{ parameters.jobName }} - - steps: - - script: | - set - displayName: Capture Environment - condition: succeededOrFailed() - - - task: DownloadBuildArtifacts@0 - displayName: 'Download Build Artifacts' - inputs: - downloadType: specific - itemPattern: | - build/**/* - downloadPath: '$(System.ArtifactsDirectory)' - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Artifacts Directory' - continueOnError: true - - - pwsh: | - Install-module Pester -Scope CurrentUser -Force -MaximumVersion 4.99 - displayName: 'Install Pester' - continueOnError: true - - - pwsh: | - Import-Module .\tools\ci.psm1 - Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' - $options = (Get-PSOptions) - $path = split-path -path $options.Output - Write-Verbose "Path: '$path'" -Verbose - $rootPath = split-Path -path $path - Expand-Archive -Path '$(System.ArtifactsDirectory)\build\build.zip' -DestinationPath $rootPath -Force - Invoke-Pester -Path ./test/nanoserver -OutputFormat NUnitXml -OutputFile ./test-nanoserver.xml - displayName: Test - condition: succeeded() - - - task: PublishTestResults@2 - condition: succeededOrFailed() - displayName: Publish Nanoserver Test Results **\test*.xml - inputs: - testRunner: NUnit - testResultsFiles: '**\test*.xml' - testRunTitle: nanoserver - mergeTestResults: true - failTaskOnFailedTests: true diff --git a/test/infrastructure/ciModule.Tests.ps1 b/test/infrastructure/ciModule.Tests.ps1 new file mode 100644 index 00000000000..f88d5787fc9 --- /dev/null +++ b/test/infrastructure/ciModule.Tests.ps1 @@ -0,0 +1,240 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# NOTE: This test file tests the Test-MergeConflictMarker function which detects Git merge conflict markers. +# IMPORTANT: Do NOT use here-strings or literal conflict markers (e.g., "<<<<<<<", "=======", ">>>>>>>") +# in this file, as they will trigger conflict marker detection in CI pipelines. +# Instead, use string multiplication (e.g., '<' * 7) to dynamically generate these markers at runtime. + +Describe "Test-MergeConflictMarker" { + BeforeAll { + # Import the module + Import-Module "$PSScriptRoot/../../tools/ci.psm1" -Force + + # Create a temporary test workspace + $script:testWorkspace = Join-Path $TestDrive "workspace" + New-Item -ItemType Directory -Path $script:testWorkspace -Force | Out-Null + + # Create temporary output files + $script:testOutputPath = Join-Path $TestDrive "outputs.txt" + $script:testSummaryPath = Join-Path $TestDrive "summary.md" + } + + AfterEach { + # Clean up test files after each test + if (Test-Path $script:testWorkspace) { + Get-ChildItem $script:testWorkspace -File -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue + } + Remove-Item $script:testOutputPath -Force -ErrorAction SilentlyContinue + Remove-Item $script:testSummaryPath -Force -ErrorAction SilentlyContinue + } + + Context "When no files are provided" { + It "Should handle empty file array" { + # The function parameter has Mandatory validation which rejects empty arrays by design + # This test verifies that behavior + $emptyArray = @() + { Test-MergeConflictMarker -File $emptyArray -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw -ExpectedMessage "*empty array*" + } + } + + Context "When files have no conflicts" { + It "Should pass for clean files" { + $testFile = Join-Path $script:testWorkspace "clean.txt" + "This is a clean file" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @("clean.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=1" + $outputs | Should -Contain "conflicts-found=0" + + $summary = Get-Content $script:testSummaryPath -Raw + $summary | Should -Match "No Conflicts Found" + } + } + + Context "When files have conflict markers" { + It "Should detect <<<<<<< marker" { + $testFile = Join-Path $script:testWorkspace "conflict1.txt" + "Some content`n" + ('<' * 7) + " HEAD`nConflicting content" | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict1.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=1" + $outputs | Should -Contain "conflicts-found=1" + } + + It "Should detect ======= marker" { + $testFile = Join-Path $script:testWorkspace "conflict2.txt" + "Some content`n" + ('=' * 7) + "`nMore content" | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict2.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + } + + It "Should detect >>>>>>> marker" { + $testFile = Join-Path $script:testWorkspace "conflict3.txt" + "Some content`n" + ('>' * 7) + " branch-name`nMore content" | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict3.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + } + + It "Should detect multiple markers in one file" { + $testFile = Join-Path $script:testWorkspace "conflict4.txt" + $content = "Some content`n" + ('<' * 7) + " HEAD`nContent A`n" + ('=' * 7) + "`nContent B`n" + ('>' * 7) + " branch`nMore content" + $content | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict4.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + + $summary = Get-Content $script:testSummaryPath -Raw + $summary | Should -Match "Conflicts Detected" + $summary | Should -Match "conflict4.txt" + } + + It "Should detect conflicts in multiple files" { + $testFile1 = Join-Path $script:testWorkspace "conflict5.txt" + ('<' * 7) + " HEAD" | Out-File $testFile1 -Encoding utf8 + + $testFile2 = Join-Path $script:testWorkspace "conflict6.txt" + ('=' * 7) | Out-File $testFile2 -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict5.txt", "conflict6.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=2" + $outputs | Should -Contain "conflicts-found=2" + } + } + + Context "When markers are not at line start" { + It "Should not detect markers in middle of line" { + $testFile = Join-Path $script:testWorkspace "notconflict.txt" + "This line has <<<<<<< in the middle" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @("notconflict.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "conflicts-found=0" + } + + It "Should not detect markers with wrong number of characters" { + $testFile = Join-Path $script:testWorkspace "wrongcount.txt" + ('<' * 6) + " Only 6`n" + ('<' * 8) + " 8 characters" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @("wrongcount.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "conflicts-found=0" + } + } + + Context "When handling special file scenarios" { + It "Should skip non-existent files" { + Test-MergeConflictMarker -File @("nonexistent.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=0" + } + + It "Should handle absolute paths" { + $testFile = Join-Path $script:testWorkspace "absolute.txt" + "Clean content" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @($testFile) -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "conflicts-found=0" + } + + It "Should handle mixed relative and absolute paths" { + $testFile1 = Join-Path $script:testWorkspace "relative.txt" + "Clean" | Out-File $testFile1 -Encoding utf8 + + $testFile2 = Join-Path $script:testWorkspace "absolute.txt" + "Clean" | Out-File $testFile2 -Encoding utf8 + + Test-MergeConflictMarker -File @("relative.txt", $testFile2) -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=2" + $outputs | Should -Contain "conflicts-found=0" + } + } + + Context "When summary and output generation" { + It "Should generate proper GitHub Actions outputs format" { + $testFile = Join-Path $script:testWorkspace "test.txt" + "Clean file" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @("test.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Where-Object {$_ -match "^files-checked=\d+$"} | Should -Not -BeNullOrEmpty + $outputs | Where-Object {$_ -match "^conflicts-found=\d+$"} | Should -Not -BeNullOrEmpty + } + + It "Should generate markdown summary with conflict details" { + $testFile = Join-Path $script:testWorkspace "marked.txt" + $content = "Line 1`n" + ('<' * 7) + " HEAD`nLine 3`n" + ('=' * 7) + "`nLine 5" + $content | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("marked.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + + $summary = Get-Content $script:testSummaryPath -Raw + $summary | Should -Match "# Merge Conflict Marker Check Results" + $summary | Should -Match "marked.txt" + $summary | Should -Match "\| Line \| Marker \|" + } + } +} + +Describe "Install-CIPester" { + BeforeAll { + # Import the module + Import-Module "$PSScriptRoot/../../tools/ci.psm1" -Force + } + + Context "When checking function exists" { + It "Should export Install-CIPester function" { + $function = Get-Command Install-CIPester -ErrorAction SilentlyContinue + $function | Should -Not -BeNullOrEmpty + $function.ModuleName | Should -Be 'ci' + } + + It "Should have expected parameters" { + $function = Get-Command Install-CIPester + $function.Parameters.Keys | Should -Contain 'MinimumVersion' + $function.Parameters.Keys | Should -Contain 'MaximumVersion' + $function.Parameters.Keys | Should -Contain 'Force' + } + + It "Should accept version parameters" { + $function = Get-Command Install-CIPester + $function.Parameters['MinimumVersion'].ParameterType.Name | Should -Be 'String' + $function.Parameters['MaximumVersion'].ParameterType.Name | Should -Be 'String' + $function.Parameters['Force'].ParameterType.Name | Should -Be 'SwitchParameter' + } + } + + Context "When validating real execution" { + # These tests only run in CI where we can safely install/test Pester + + It "Should successfully run without errors when Pester exists" { + if (!$env:CI) { + Set-ItResult -Skipped -Because "Test requires CI environment to safely install Pester" + } + + { Install-CIPester -ErrorAction Stop } | Should -Not -Throw + } + + It "Should accept custom version parameters" { + if (!$env:CI) { + Set-ItResult -Skipped -Because "Test requires CI environment to safely install Pester" + } + + { Install-CIPester -MinimumVersion '4.0.0' -MaximumVersion '5.99.99' -ErrorAction Stop } | Should -Not -Throw + } + } +} + diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 478435e8543..bcc816cc918 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -228,6 +228,45 @@ function Invoke-CIxUnit } } +# Install Pester module if not already installed with a compatible version +function Install-CIPester +{ + [CmdletBinding()] + param( + [string]$MinimumVersion = '5.0.0', + [string]$MaximumVersion = '5.99.99', + [switch]$Force + ) + + Write-Verbose "Checking for Pester module (required: $MinimumVersion - $MaximumVersion)" -Verbose + + # Check if a compatible version of Pester is already installed + $installedPester = Get-Module -Name Pester -ListAvailable | + Where-Object { $_.Version -ge $MinimumVersion -and $_.Version -le $MaximumVersion } | + Sort-Object -Property Version -Descending | + Select-Object -First 1 + + if ($installedPester -and -not $Force) { + Write-Host "Pester version $($installedPester.Version) is already installed and meets requirements" -ForegroundColor Green + return + } + + if ($Force) { + Write-Host "Installing Pester module (forced)" -ForegroundColor Yellow + } else { + Write-Host "Installing Pester module" -ForegroundColor Yellow + } + + try { + Install-Module -Name Pester -Force -SkipPublisherCheck -MaximumVersion $MaximumVersion -ErrorAction Stop + Write-Host "Successfully installed Pester module" -ForegroundColor Green + } + catch { + Write-Error "Failed to install Pester module: $_" + throw + } +} + # Implement CI 'Test_script' function Invoke-CITest { @@ -621,7 +660,7 @@ function Invoke-CIFinish # Install the latest Pester and import it $maximumPesterVersion = '4.99' - Install-Module Pester -Force -SkipPublisherCheck -MaximumVersion $maximumPesterVersion + Install-CIPester -MinimumVersion '4.0.0' -MaximumVersion $maximumPesterVersion -Force Import-Module Pester -Force -MaximumVersion $maximumPesterVersion $testResultPath = Join-Path -Path $env:TEMP -ChildPath "win-package-$channel-$runtime.xml" @@ -977,3 +1016,172 @@ function Invoke-InitializeContainerStage { Write-Host "##vso[build.addbuildtag]$($selectedImage.JobName)" } } + +Function Test-MergeConflictMarker +{ + <# + .SYNOPSIS + Checks files for Git merge conflict markers and outputs results for GitHub Actions. + .DESCRIPTION + Scans the specified files for Git merge conflict markers (<<<<<<<, =======, >>>>>>>) + and generates console output, GitHub Actions outputs, and job summary. + Designed for use in GitHub Actions workflows. + .PARAMETER File + Array of file paths (relative or absolute) to check for merge conflict markers. + .PARAMETER WorkspacePath + Base workspace path for resolving relative paths. Defaults to current directory. + .PARAMETER OutputPath + Path to write GitHub Actions outputs. Defaults to $env:GITHUB_OUTPUT. + .PARAMETER SummaryPath + Path to write GitHub Actions job summary. Defaults to $env:GITHUB_STEP_SUMMARY. + .EXAMPLE + Test-MergeConflictMarker -File @('file1.txt', 'file2.cs') -WorkspacePath $env:GITHUB_WORKSPACE + #> + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string[]] $File, + + [Parameter()] + [string] $WorkspacePath = $PWD, + + [Parameter()] + [string] $OutputPath = $env:GITHUB_OUTPUT, + + [Parameter()] + [string] $SummaryPath = $env:GITHUB_STEP_SUMMARY + ) + + Write-Host "Starting merge conflict marker check..." -ForegroundColor Cyan + + Write-Host "Checking $($File.Count) changed files for merge conflict markers" -ForegroundColor Cyan + + # Convert relative paths to absolute paths for processing + $absolutePaths = $File | ForEach-Object { + if ([System.IO.Path]::IsPathRooted($_)) { + $_ + } else { + Join-Path $WorkspacePath $_ + } + } + + $filesWithConflicts = @() + $filesChecked = 0 + + foreach ($filePath in $absolutePaths) { + # Check if file exists (might be deleted) + if (-not (Test-Path $filePath)) { + Write-Verbose " Skipping deleted file: $filePath" + continue + } + + # Skip binary files and directories + if ((Get-Item $filePath) -is [System.IO.DirectoryInfo]) { + continue + } + + $filesChecked++ + + # Get relative path for display + $relativePath = if ($WorkspacePath -and $filePath.StartsWith($WorkspacePath)) { + $filePath.Substring($WorkspacePath.Length).TrimStart([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar) + } else { + $filePath + } + + Write-Host " Checking: $relativePath" -ForegroundColor Gray + + # Search for conflict markers using Select-String + try { + # Git conflict markers are 7 characters followed by a space or end of line + # Regex pattern breakdown: + # ^ - Matches the start of a line + # (<{7}|={7}|>{7}) - Matches exactly 7 consecutive '<', '=', or '>' characters (Git conflict markers) + # (\s|$) - Ensures the marker is followed by whitespace or end of line + $pattern = '^(<{7}|={7}|>{7})(\s|$)' + $matchedLines = Select-String -Path $filePath -Pattern $pattern -AllMatches -ErrorAction Stop + + if ($matchedLines) { + # Collect marker details with line numbers (Select-String provides LineNumber automatically) + $markerDetails = @() + + foreach ($match in $matchedLines) { + $markerDetails += [PSCustomObject]@{ + Marker = $match.Matches[0].Groups[1].Value + Line = $match.LineNumber + } + } + + $filesWithConflicts += [PSCustomObject]@{ + File = $relativePath + MarkerDetails = $markerDetails + } + + Write-Host " ❌ CONFLICT MARKERS FOUND in $relativePath" -ForegroundColor Red + foreach ($detail in $markerDetails) { + Write-Host " Line $($detail.Line): $($detail.Marker)" -ForegroundColor Red + } + } + } + catch { + # Skip files that can't be read (likely binary) + Write-Verbose " Skipping unreadable file: $relativePath" + } + } + + # Output results to GitHub Actions + if ($OutputPath) { + "files-checked=$filesChecked" | Out-File -FilePath $OutputPath -Append -Encoding utf8 + "conflicts-found=$($filesWithConflicts.Count)" | Out-File -FilePath $OutputPath -Append -Encoding utf8 + } + + Write-Host "`nSummary:" -ForegroundColor Cyan + Write-Host " Files checked: $filesChecked" -ForegroundColor Cyan + Write-Host " Files with conflicts: $($filesWithConflicts.Count)" -ForegroundColor Cyan + + # Create GitHub Actions job summary + if ($SummaryPath) { + $summaryContent = @" +# Merge Conflict Marker Check Results + +## Summary +- **Files Checked:** $filesChecked +- **Files with Conflicts:** $($filesWithConflicts.Count) + +"@ + + if ($filesWithConflicts.Count -gt 0) { + Write-Host "`n❌ Merge conflict markers detected in the following files:" -ForegroundColor Red + + $summaryContent += "`n## ❌ Conflicts Detected`n`n" + $summaryContent += "The following files contain merge conflict markers:`n`n" + + foreach ($fileInfo in $filesWithConflicts) { + Write-Host " - $($fileInfo.File)" -ForegroundColor Red + + $summaryContent += "### 📄 ``$($fileInfo.File)```n`n" + $summaryContent += "| Line | Marker |`n" + $summaryContent += "|------|--------|`n" + + foreach ($detail in $fileInfo.MarkerDetails) { + Write-Host " Line $($detail.Line): $($detail.Marker)" -ForegroundColor Red + $summaryContent += "| $($detail.Line) | ``$($detail.Marker)`` |`n" + } + $summaryContent += "`n" + } + + $summaryContent += "`n**Action Required:** Please resolve these conflicts before merging.`n" + Write-Host "`nPlease resolve these conflicts before merging." -ForegroundColor Red + } else { + Write-Host "`n✅ No merge conflict markers found" -ForegroundColor Green + $summaryContent += "`n## ✅ No Conflicts Found`n`nAll checked files are free of merge conflict markers.`n" + } + + $summaryContent | Out-File -FilePath $SummaryPath -Encoding utf8 + } + + # Exit with error if conflicts found + if ($filesWithConflicts.Count -gt 0) { + throw "Merge conflict markers detected in $($filesWithConflicts.Count) file(s)" + } +} From 189d64bf8cb05edce994a84f01cb5e9d51c71a55 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 14:53:09 -0800 Subject: [PATCH 194/275] [release/v7.5] Improve ADO package build and validation across platforms (#26814) --- .github/workflows/macos-ci.yml | 2 +- .pipelines/templates/mac-package-build.yml | 26 ++++-- build.psm1 | 11 ++- .../macos/package-validation.tests.ps1 | 81 ++++++++++++------- tools/packaging/packaging.psm1 | 70 ++++++++-------- 5 files changed, 116 insertions(+), 74 deletions(-) rename tools/packaging/releaseTests/macOSPackage.tests.ps1 => test/packaging/macos/package-validation.tests.ps1 (85%) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 14c15bd288d..89f3b7811d6 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -204,7 +204,7 @@ jobs: } Import-Module Pester $pesterConfig = New-PesterConfiguration - $pesterConfig.Run.Path = './tools/packaging/releaseTests/macOSPackage.tests.ps1' + $pesterConfig.Run.Path = './test/packaging/macos/package-validation.tests.ps1' $pesterConfig.Run.PassThru = $true $pesterConfig.Output.Verbosity = 'Detailed' $pesterConfig.TestResult.Enabled = $true diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 40a6faef06c..6f746438da9 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -116,13 +116,25 @@ jobs: Start-PSPackage -Type osxpkg -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS $pkgNameFilter = "powershell-*$macosRuntime.pkg" - $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$pkgPath" + Write-Verbose -Verbose "Looking for pkg packages with filter: $pkgNameFilter in '$(Pipeline.Workspace)' to upload..." + $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgNameFilter -Recurse -File + + foreach($p in $pkgPath) { + $file = $p.FullName + Write-Verbose -verbose "Uploading $file to macos-pkgs" + Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$file" + } Start-PSPackage -Type tar -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS $tarPkgNameFilter = "powershell-*$macosRuntime.tar.gz" - $tarPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $tarPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$tarPkgPath" + Write-Verbose -Verbose "Looking for tar packages with filter: $tarPkgNameFilter in '$(Pipeline.Workspace)' to upload..." + $tarPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $tarPkgNameFilter -Recurse -File + + foreach($t in $tarPkgPath) { + $file = $t.FullName + Write-Verbose -verbose "Uploading $file to macos-pkgs" + Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$file" + } displayName: 'Package ${{ parameters.buildArchitecture}}' env: @@ -195,14 +207,14 @@ jobs: - pwsh: | $signedPkg = Get-ChildItem -Path $(Pipeline.Workspace) -Filter "*osx*.zip" -File - + $signedPkg | ForEach-Object { Write-Verbose -Verbose "Signed package zip: $_" - + if (-not (Test-Path $_)) { throw "Package not found: $_" } - + if (-not (Test-Path $(ob_outputDirectory))) { $null = New-Item -Path $(ob_outputDirectory) -ItemType Directory } diff --git a/build.psm1 b/build.psm1 index 2a30d7a0858..1e1899ca0c5 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2399,7 +2399,7 @@ function Start-PSBootstrap { Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y rpm-build")) -IgnoreExitcode } } - + # For Debian-based systems and Mariner, ensure dpkg-deb is available if ($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) { Write-Verbose -Verbose "Checking for dpkg-deb..." @@ -2407,9 +2407,14 @@ function Start-PSBootstrap { Write-Warning "dpkg-deb not found. Installing dpkg package..." if ($environment.IsMariner) { # For Mariner (Azure Linux), install the extended repo first to access dpkg. + Write-Verbose -verbose "BEGIN: /etc/os-release content:" + Get-Content /etc/os-release | Write-Verbose -verbose + Write-Verbose -verbose "END: /etc/os-release content" + Write-Verbose -Verbose "Installing azurelinux-repos-extended for Mariner..." - Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y azurelinux-repos-extended")) -IgnoreExitcode - Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y dpkg")) -IgnoreExitcode + + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager azurelinux-repos-extended")) -IgnoreExitcode -Verbose + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager dpkg")) -IgnoreExitcode -Verbose } else { Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo apt-get install -y dpkg")) -IgnoreExitcode } diff --git a/tools/packaging/releaseTests/macOSPackage.tests.ps1 b/test/packaging/macos/package-validation.tests.ps1 similarity index 85% rename from tools/packaging/releaseTests/macOSPackage.tests.ps1 rename to test/packaging/macos/package-validation.tests.ps1 index c1de1091562..02b09fbb078 100644 --- a/tools/packaging/releaseTests/macOSPackage.tests.ps1 +++ b/test/packaging/macos/package-validation.tests.ps1 @@ -1,51 +1,54 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + Describe "Verify macOS Package" { BeforeAll { Write-Verbose "In Describe BeforeAll" -Verbose Import-Module $PSScriptRoot/../../../build.psm1 - + # Find the macOS package $packagePath = $env:PACKAGE_FOLDER if (-not $packagePath) { $packagePath = Get-Location } - + Write-Verbose "Looking for package in: $packagePath" -Verbose $package = Get-ChildItem -Path $packagePath -Filter "*.pkg" -ErrorAction SilentlyContinue | Select-Object -First 1 - + if (-not $package) { Write-Warning "No .pkg file found in $packagePath" } else { Write-Verbose "Found package: $($package.FullName)" -Verbose } - + # Set up test directories $script:package = $package $script:expandDir = $null $script:payloadDir = $null $script:extractedFiles = @() - + if ($package) { # Use TestDrive for temporary directories - pkgutil will create the expand directory $script:expandDir = Join-Path "TestDrive:" -ChildPath "package-contents-test" $expandDirResolved = (Resolve-Path "TestDrive:").ProviderPath $script:expandDir = Join-Path $expandDirResolved -ChildPath "package-contents-test" - + Write-Verbose "Expanding package to: $($script:expandDir)" -Verbose # pkgutil will create the directory itself, so don't pre-create it Start-NativeExecution { pkgutil --expand $package.FullName $script:expandDir } - + # Extract the payload to verify files $script:payloadDir = Join-Path "TestDrive:" -ChildPath "package-payload-test" $payloadDirResolved = (Resolve-Path "TestDrive:").ProviderPath $script:payloadDir = Join-Path $payloadDirResolved -ChildPath "package-payload-test" - + # Create payload directory since cpio needs it if (-not (Test-Path $script:payloadDir)) { $null = New-Item -ItemType Directory -Path $script:payloadDir -Force } - + $componentPkg = Get-ChildItem -Path $script:expandDir -Filter "*.pkg" -Recurse | Select-Object -First 1 if ($componentPkg) { Write-Verbose "Extracting payload from: $($componentPkg.FullName)" -Verbose @@ -57,40 +60,60 @@ Describe "Verify macOS Package" { Pop-Location } } - + # Get all extracted files for verification $script:extractedFiles = Get-ChildItem -Path $script:payloadDir -Recurse -ErrorAction SilentlyContinue Write-Verbose "Extracted $($script:extractedFiles.Count) files" -Verbose } } - + AfterAll { # TestDrive automatically cleans up, but we can ensure cleanup happens # No manual cleanup needed as TestDrive handles it } - + Context "Package existence and structure" { It "Package file should exist" { $script:package | Should -Not -BeNullOrEmpty -Because "A .pkg file should be created" $script:package.Extension | Should -Be ".pkg" } - + + It "Package name should follow correct naming convention" { + $script:package | Should -Not -BeNullOrEmpty + + # Regex pattern for valid macOS PKG package names. + # Valid examples: + # - powershell-7.4.13-osx-x64.pkg (Intel x64 - note: x64 with hyphens for compatibility) + # - powershell-7.4.13-osx-arm64.pkg (Apple Silicon) + # - powershell-preview-7.6.0-preview.6-osx-x64.pkg + # - powershell-lts-7.4.13-osx-arm64.pkg + $pkgPackageNamePattern = '^powershell(-preview|-lts)?-\d+\.\d+\.\d+(-[a-z]+\.\d+)?-osx-(x64|arm64)\.pkg$' + + $script:package.Name | Should -Match $pkgPackageNamePattern -Because "Package name should follow the standard naming convention" + } + + It "Package name should NOT use x86_64 with underscores" { + $script:package | Should -Not -BeNullOrEmpty + + $script:package.Name | Should -Not -Match 'x86_64' -Because "Package should use 'x64' not 'x86_64' (with underscores) for compatibility" + } + It "Package should expand successfully" { $script:expandDir | Should -Exist Get-ChildItem -Path $script:expandDir | Should -Not -BeNullOrEmpty } - + It "Package should have a component package" { $componentPkg = Get-ChildItem -Path $script:expandDir -Filter "*.pkg" -Recurse -ErrorAction SilentlyContinue $componentPkg | Should -Not -BeNullOrEmpty -Because "Package should contain a component.pkg" } - + It "Payload should extract successfully" { $script:payloadDir | Should -Exist $script:extractedFiles | Should -Not -BeNullOrEmpty -Because "Package payload should contain files" } } - + Context "Required files in package" { BeforeAll { $expectedFilePatterns = @{ @@ -99,7 +122,7 @@ Describe "Verify macOS Package" { "Man page" = "usr/local/share/man/man1/pwsh*.gz" "Launcher application plist" = "Applications/PowerShell*.app/Contents/Info.plist" } - + $testCases = @() foreach ($key in $expectedFilePatterns.Keys) { $testCases += @{ @@ -107,23 +130,23 @@ Describe "Verify macOS Package" { Pattern = $expectedFilePatterns[$key] } } - + $script:testCases = $testCases } - + It "Should contain " -TestCases $script:testCases { param($Description, $Pattern) - + $found = $script:extractedFiles | Where-Object { $_.FullName -like "*$Pattern*" } $found | Should -Not -BeNullOrEmpty -Because "$Description should exist in the package at path matching '$Pattern'" } } - + Context "PowerShell binary verification" { It "PowerShell executable should be executable" { $pwshBinary = $script:extractedFiles | Where-Object { $_.FullName -like "*/pwsh" -and $_.FullName -like "*/microsoft/powershell/*" } $pwshBinary | Should -Not -BeNullOrEmpty - + # Check if file has executable permissions (on Unix-like systems) if ($IsLinux -or $IsMacOS) { $permissions = (Get-Item $pwshBinary[0].FullName).UnixFileMode @@ -132,27 +155,27 @@ Describe "Verify macOS Package" { } } } - + Context "Launcher application" { It "Launcher app should have proper bundle structure" { $plistFile = $script:extractedFiles | Where-Object { $_.FullName -like "*PowerShell*.app/Contents/Info.plist" } $plistFile | Should -Not -BeNullOrEmpty - + # Verify the bundle has required components $appPath = Split-Path (Split-Path $plistFile[0].FullName -Parent) -Parent $macOSDir = Join-Path $appPath "Contents/MacOS" $resourcesDir = Join-Path $appPath "Contents/Resources" - + Test-Path $macOSDir | Should -Be $true -Because "App bundle should have Contents/MacOS directory" Test-Path $resourcesDir | Should -Be $true -Because "App bundle should have Contents/Resources directory" } - + It "Launcher script should exist and be executable" { - $launcherScript = $script:extractedFiles | Where-Object { - $_.FullName -like "*PowerShell*.app/Contents/MacOS/PowerShell.sh" + $launcherScript = $script:extractedFiles | Where-Object { + $_.FullName -like "*PowerShell*.app/Contents/MacOS/PowerShell.sh" } $launcherScript | Should -Not -BeNullOrEmpty -Because "Launcher script should exist" - + if ($IsLinux -or $IsMacOS) { $permissions = (Get-Item $launcherScript[0].FullName).UnixFileMode $permissions.ToString() | Should -Match 'x' -Because "Launcher script should have execute permissions" diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 286859e9ed9..4f397ad10b4 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1239,15 +1239,15 @@ function New-UnixPackage { # Use rpmbuild directly for RPM packages if ($PSCmdlet.ShouldProcess("Create RPM package with rpmbuild")) { Write-Log "Creating RPM package with rpmbuild..." - + # Create rpmbuild directory structure $rpmBuildRoot = Join-Path $env:HOME "rpmbuild" $specsDir = Join-Path $rpmBuildRoot "SPECS" $rpmsDir = Join-Path $rpmBuildRoot "RPMS" - + New-Item -ItemType Directory -Path $specsDir -Force | Out-Null New-Item -ItemType Directory -Path $rpmsDir -Force | Out-Null - + # Generate RPM spec file $specContent = New-RpmSpec ` -Name $Name ` @@ -1264,11 +1264,11 @@ function New-UnixPackage { -LinkInfo $Links ` -Distribution $DebDistro ` -HostArchitecture $HostArchitecture - + $specFile = Join-Path $specsDir "$Name.spec" $specContent | Out-File -FilePath $specFile -Encoding ascii Write-Verbose "Generated spec file: $specFile" -Verbose - + # Log the spec file content if ($env:GITHUB_ACTIONS -eq 'true') { Write-Host "::group::RPM Spec File Content" @@ -1277,7 +1277,7 @@ function New-UnixPackage { } else { Write-Verbose "RPM Spec File Content:`n$specContent" -Verbose } - + # Build RPM package try { # Use bash to properly handle rpmbuild arguments @@ -1290,16 +1290,16 @@ function New-UnixPackage { Write-Verbose "Running: $buildCmd" -Verbose $Output = bash -c $buildCmd 2>&1 $exitCode = $LASTEXITCODE - + if ($exitCode -ne 0) { throw "rpmbuild failed with exit code $exitCode" } - + # Find the generated RPM - $rpmFile = Get-ChildItem -Path (Join-Path $rpmsDir $HostArchitecture) -Filter "*.rpm" -ErrorAction Stop | - Sort-Object -Property LastWriteTime -Descending | + $rpmFile = Get-ChildItem -Path (Join-Path $rpmsDir $HostArchitecture) -Filter "*.rpm" -ErrorAction Stop | + Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 - + if ($rpmFile) { # Copy RPM to current location Copy-Item -Path $rpmFile.FullName -Destination $CurrentLocation -Force @@ -1337,7 +1337,7 @@ function New-UnixPackage { -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` -HostArchitecture $HostArchitecture ` -CurrentLocation $CurrentLocation - + $Output = @("Created package {:path=>""$($result.PackageName)""}") } catch { @@ -1348,7 +1348,7 @@ function New-UnixPackage { # Use native macOS packaging tools if ($PSCmdlet.ShouldProcess("Create macOS package with pkgbuild/productbuild")) { Write-Log "Creating macOS package with native tools..." - + $macPkgArgs = @{ Name = $Name Version = $packageVersion @@ -1363,7 +1363,7 @@ function New-UnixPackage { HostArchitecture = $HostArchitecture CurrentLocation = $CurrentLocation } - + try { $packageFile = New-MacOSPackage @macPkgArgs $Output = @("Created package {:path=>""$($packageFile.Name)""}") @@ -1386,7 +1386,7 @@ function New-UnixPackage { Clear-MacOSLauncher } } - + # Clean up rpmbuild directory if it was created if ($Type -eq 'rpm') { $rpmBuildRoot = Join-Path $env:HOME "rpmbuild" @@ -1395,7 +1395,7 @@ function New-UnixPackage { Remove-Item -Path $rpmBuildRoot -Recurse -Force -ErrorAction SilentlyContinue } } - + if ($AfterScriptInfo.AfterInstallScript) { Remove-Item -ErrorAction 'silentlycontinue' $AfterScriptInfo.AfterInstallScript -Force } @@ -1489,13 +1489,13 @@ function New-MacOsDistributionPackage $resourcesDir = Join-Path -Path $tempDir -ChildPath 'resources' New-Item -ItemType Directory -Path $resourcesDir -Force > $null - + # Copy background file to temp directory $backgroundFile = "$RepoRoot/assets/macDialog.png" if (Test-Path $backgroundFile) { Copy-Item -Path $backgroundFile -Destination $resourcesDir -Force } - + # Copy the component package to temp directory $componentFileName = Split-Path -Leaf -Path $ComponentPackage $tempComponentPath = Join-Path -Path $tempDir -ChildPath $componentFileName @@ -1511,7 +1511,7 @@ function New-MacOsDistributionPackage # Minimum OS version $minOSVersion = "11.0" # macOS Big Sur minimum - + # format distribution template with: # 0 - title # 1 - version @@ -1522,8 +1522,10 @@ function New-MacOsDistributionPackage $PackagingStrings.OsxDistributionTemplate -f $PackageName, $Version, $componentFileName, $minOSVersion, $PackageIdentifier, $HostArchitecture | Out-File -Encoding utf8 -FilePath $distributionXmlPath -Force # Build final package path - $finalPackagePath = Join-Path $OutputDirectory "$PackageName-$Version-osx-$HostArchitecture.pkg" - + # Rename x86_64 to x64 for compatibility + $packageArchName = if ($HostArchitecture -eq "x86_64") { "x64" } else { $HostArchitecture } + $finalPackagePath = Join-Path $OutputDirectory "$PackageName-$Version-osx-$packageArchName.pkg" + # Remove existing package if it exists if (Test-Path $finalPackagePath) { Write-Warning "Removing existing package: $finalPackagePath" @@ -1542,7 +1544,7 @@ function New-MacOsDistributionPackage --resources $resourcesDir ` $finalPackagePath } - + if (Test-Path $finalPackagePath) { Write-Log "Successfully created macOS package: $finalPackagePath" } @@ -1612,7 +1614,7 @@ function New-RpmSpec # RPM doesn't allow hyphens in version, so convert them to underscores # e.g., "7.6.0-preview.6" becomes Version: 7.6.0_preview.6 $rpmVersion = $Version -replace '-', '_' - + # Build Release field with distribution suffix (e.g., "1.cm" or "1.rh") # Don't use RPM macros - build the full release string in PowerShell $rpmRelease = "$Iteration.$Distribution" @@ -1638,7 +1640,7 @@ AutoReq: no } else { # For cross-architecture builds, don't specify BuildArch in spec # The --target option will handle the architecture - + # Disable automatic binary stripping for cross-arch builds # The native /bin/strip on x86_64 cannot process ARM64 binaries and would fail with: # "Unable to recognise the format of the input file" @@ -1646,7 +1648,7 @@ AutoReq: no # __strip: This macro controls the command used for stripping binaries during the build process. # /bin/true: A command that does nothing and always exits successfully, effectively bypassing the stripping process. $specContent += "%define __strip /bin/true`n" - + # Disable debug package generation to prevent strip-related errors # Debug packages require binary stripping which fails for cross-arch builds # See: https://rpm-packaging-guide.github.io/#debugging @@ -1903,11 +1905,11 @@ $(if ($extendedDescription) { $extendedDescription + "`n" }) # Copy DEBIAN directory and data files to build root $buildDir = Join-Path $debBuildRoot "build" New-Item -ItemType Directory -Path $buildDir -Force | Out-Null - + Write-Verbose "debianDir: $debianDir" -Verbose Write-Verbose "dataDir: $dataDir" -Verbose Write-Verbose "buildDir: $buildDir" -Verbose - + # Use cp to preserve symlinks Start-NativeExecution { cp -a $debianDir "$buildDir/DEBIAN" } Start-NativeExecution { cp -a $dataDir/* $buildDir } @@ -2017,14 +2019,14 @@ function New-MacOSPackage $linkDestDir = Join-Path $pkgRoot (Split-Path $link.Destination -Parent) New-Item -ItemType Directory -Path $linkDestDir -Force | Out-Null $finalLinkPath = Join-Path $pkgRoot $link.Destination - + Write-Verbose "Creating symlink at $finalLinkPath" -Verbose - + # Remove if exists if (Test-Path $finalLinkPath) { Remove-Item $finalLinkPath -Force } - + # Get the target of the original symlink and recreate it in the package root if (Test-Path $link.Source) { $linkTarget = (Get-Item $link.Source).Target @@ -2050,10 +2052,10 @@ function New-MacOSPackage # Build the component package using pkgbuild $pkgIdentifier = Get-MacOSPackageId -IsPreview:($Name -like '*-preview') - + if ($PSCmdlet.ShouldProcess("Build component package with pkgbuild")) { Write-Log "Running pkgbuild to create component package..." - + Start-NativeExecution -VerboseOutputOnError { pkgbuild --root $pkgRoot ` --identifier $pkgIdentifier ` @@ -2062,7 +2064,7 @@ function New-MacOSPackage --install-location "/" ` $componentPkgPath } - + Write-Verbose "Component package created: $componentPkgPath" -Verbose } @@ -2075,7 +2077,7 @@ function New-MacOSPackage -HostArchitecture $HostArchitecture ` -PackageIdentifier $pkgIdentifier ` -IsPreview:($Name -like '*-preview') - + return $distributionPackage } finally { From 5d9d882d9253d6a971cee8e34e1a755b0e4408e4 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 15:03:14 -0800 Subject: [PATCH 195/275] [release/v7.5] Optimize/split windows package signing (#26815) --- .../chatmodes/cherry-pick-commits.chatmode.md | 78 ++++++ .../instructions/build-configuration-guide.md | 11 +- ...ode-review-branch-strategy.instructions.md | 230 ++++++++++++++++++ ...anch-restore-phase-pattern.instructions.md | 83 +++++++ ...anch-signing-configuration.instructions.md | 195 +++++++++++++++ .pipelines/MSIXBundle-vPack-Official.yml | 1 - ...werShell-Coordinated_Packages-Official.yml | 1 - .pipelines/PowerShell-Packages-Official.yml | 62 +++-- .pipelines/PowerShell-vPack-Official.yml | 1 - .pipelines/templates/SetVersionVariables.yml | 59 ++--- .pipelines/templates/checkAzureContainer.yml | 3 +- .pipelines/templates/cloneToOfficialPath.yml | 18 +- .pipelines/templates/compliance/apiscan.yml | 3 +- .pipelines/templates/install-dotnet.yml | 7 +- .pipelines/templates/linux-package-build.yml | 3 +- .pipelines/templates/mac-package-build.yml | 3 +- .pipelines/templates/nupkg.yml | 3 +- .pipelines/templates/package-create-msix.yml | 6 +- .../windows/package.yml} | 152 +++--------- .../templates/packaging/windows/sign.yml | 216 ++++++++++++++++ .../templates/release-MakeBlobPublic.yml | 6 +- .../templates/release-checkout-pwsh-repo.yml | 13 - .../templates/release-download-packages.yml | 122 ---------- .pipelines/templates/release-install-pwsh.yml | 34 --- .pipelines/templates/set-reporoot.yml | 35 +++ .pipelines/templates/shouldSign.yml | 7 +- .pipelines/templates/uploadToAzure.yml | 3 +- 27 files changed, 978 insertions(+), 377 deletions(-) create mode 100644 .github/chatmodes/cherry-pick-commits.chatmode.md create mode 100644 .github/instructions/code-review-branch-strategy.instructions.md create mode 100644 .github/instructions/onebranch-restore-phase-pattern.instructions.md create mode 100644 .github/instructions/onebranch-signing-configuration.instructions.md rename .pipelines/templates/{windows-package-build.yml => packaging/windows/package.yml} (56%) create mode 100644 .pipelines/templates/packaging/windows/sign.yml delete mode 100644 .pipelines/templates/release-checkout-pwsh-repo.yml delete mode 100644 .pipelines/templates/release-download-packages.yml delete mode 100644 .pipelines/templates/release-install-pwsh.yml create mode 100644 .pipelines/templates/set-reporoot.yml diff --git a/.github/chatmodes/cherry-pick-commits.chatmode.md b/.github/chatmodes/cherry-pick-commits.chatmode.md new file mode 100644 index 00000000000..826ab11d56c --- /dev/null +++ b/.github/chatmodes/cherry-pick-commits.chatmode.md @@ -0,0 +1,78 @@ +# Cherry-Pick Commits Between Branches + +Cherry-pick recent commits from a source branch to a target branch without switching branches. + +## Instructions for Copilot + +1. **Confirm branches with the user** + - Ask the user to confirm the source and target branches + - If different branches are needed, update the configuration + +2. **Identify unique commits** + - Run: `git log .. --oneline --reverse` + - **IMPORTANT**: The commit count may be misleading if branches diverged from different base commits + - Compare the LAST few commits from each branch to identify actual missing commits: + - `git log --oneline -10` + - `git log --oneline -10` + - Look for commits with the same message but different SHAs (rebased commits) + - Show the user ONLY the truly missing commits (usually just the most recent ones) + +3. **Confirm with user before proceeding** + - If the commit count seems unusually high (e.g., 400+), STOP and verify semantically + - Ask: "I found X commits to cherry-pick. Shall I proceed?" + - If there are many commits, warn that this may take time + +4. **Execute the cherry-pick** + - Ensure the target branch is checked out first + - Run: `git cherry-pick ` for single commits + - Or: `git cherry-pick ` for multiple commits + - Apply commits in chronological order (oldest first) + +5. **Handle any issues** + - If conflicts occur, pause and ask user for guidance + - If empty commits occur, automatically skip with `git cherry-pick --skip` + +6. **Verify and report results** + - Run: `git log - --oneline` + - Show the user the newly applied commits + - Confirm the branch is now ahead by X commits + +## Key Git Commands + +```bash +# Find unique commits (may show full divergence if branches were rebased) +git log .. --oneline --reverse + +# Compare recent commits on each branch (more reliable for rebased branches) +git log --oneline -10 +git log --oneline -10 + +# Cherry-pick specific commits (when target is checked out) +git cherry-pick +git cherry-pick + +# Skip empty commits +git cherry-pick --skip + +# Verify result +git log - --oneline +``` + +## Common Scenarios + +- **Empty commits**: Automatically skip with `git cherry-pick --skip` +- **Conflicts**: Stop, show files with conflicts, ask user to resolve +- **Many commits**: Warn user and confirm before proceeding +- **Already applied**: These will result in empty commits that should be skipped +- **Diverged branches**: If branches diverged (rebased), `git log` may show the entire history difference + - The actual missing commits are usually only the most recent ones + - Compare commit messages from recent history on both branches + - Cherry-pick only commits that are semantically missing + +## Workflow Style + +Use an interactive, step-by-step approach: +- Show output from each command +- Ask for confirmation before major actions +- Provide clear status updates +- Handle errors gracefully with user guidance diff --git a/.github/instructions/build-configuration-guide.md b/.github/instructions/build-configuration-guide.md index c31f8139c62..d0384f4f307 100644 --- a/.github/instructions/build-configuration-guide.md +++ b/.github/instructions/build-configuration-guide.md @@ -1,3 +1,12 @@ +--- +applyTo: + - "build.psm1" + - "tools/ci.psm1" + - ".github/**/*.yml" + - ".github/**/*.yaml" + - ".pipelines/**/*.yml" +--- + # Build Configuration Guide ## Choosing the Right Configuration @@ -113,7 +122,7 @@ The `Switch-PSNugetConfig` function in `build.psm1` manages NuGet package source - **Public**: Uses public feeds (nuget.org and public Azure DevOps feeds) - Required for: CI/CD environments, public builds, packaging - Does not require authentication - + - **Private**: Uses internal PowerShell team feeds - Required for: Internal development with preview packages - Requires authentication credentials diff --git a/.github/instructions/code-review-branch-strategy.instructions.md b/.github/instructions/code-review-branch-strategy.instructions.md new file mode 100644 index 00000000000..191a677b912 --- /dev/null +++ b/.github/instructions/code-review-branch-strategy.instructions.md @@ -0,0 +1,230 @@ +--- +applyTo: "**/*" +--- + +# Code Review Branch Strategy Guide + +This guide helps GitHub Copilot provide appropriate feedback when reviewing code changes, particularly distinguishing between issues that should be fixed in the current branch versus the default branch. + +## Purpose + +When reviewing pull requests, especially those targeting release branches, it's important to identify whether an issue should be fixed in: +- **The current PR/branch** - Release-specific fixes or backports +- **The default branch first** - General bugs that exist in the main codebase + +## Branch Types and Fix Strategy + +### Release Branches (e.g., `release/v7.5`, `release/v7.4`) + +**Purpose:** Contain release-specific changes and critical backports + +**Should contain:** +- Release-specific configuration changes +- Critical bug fixes that are backported from the default branch +- Release packaging/versioning adjustments + +**Should NOT contain:** +- New general bug fixes that haven't been fixed in the default branch +- Refactoring or improvements that apply to the main codebase +- Workarounds for issues that exist in the default branch + +### Default/Main Branch (e.g., `master`, `main`) + +**Purpose:** Primary development branch for all ongoing work + +**Should contain:** +- All general bug fixes +- New features and improvements +- Refactoring and code quality improvements +- Fixes that will later be backported to release branches + +## Identifying Issues That Belong in the Default Branch + +When reviewing a PR targeting a release branch, look for these indicators that suggest the fix should be in the default branch first: + +### 1. The Root Cause Exists in Default Branch + +If the underlying issue exists in the default branch's code, it should be fixed there first. + +**Example:** +```yaml +# PR changes this in release/v7.5: +- $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json ++ $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw | ConvertFrom-Json +``` + +**Analysis:** If `$repoRoot` is undefined because the template doesn't include its dependencies in BOTH the release branch AND the default branch, the fix should address the root cause in the default branch first. + +### 2. The Fix is a Workaround Rather Than a Proper Solution + +If the change introduces a workaround (hardcoded paths, special cases) rather than fixing the underlying design issue, it likely belongs in the default branch as a proper fix. + +**Example:** +- Using hardcoded paths instead of fixing variable initialization +- Adding special cases instead of fixing the logic +- Duplicating code instead of fixing shared dependencies + +### 3. The Issue Affects General Functionality + +If the issue affects general functionality not specific to a release, it should be fixed in the default branch. + +**Example:** +- Template dependencies that affect all pipelines +- Shared utility functions +- Common configuration issues + +## Providing Code Review Feedback + +### For Issues in the Current Branch + +When an issue is specific to the current branch or is a legitimate fix for the branch being targeted, **use the default code review feedback format** without any special branch-strategy commentary. + +### For Issues That Belong in the Default Branch + +1. **Provide the code review feedback** +2. **Explain why it should be fixed in the default branch** +3. **Provide an issue template** in markdown format + +**Example:** + +```markdown +The `channelSelection.yml` template relies on `$repoRoot` being set by `SetVersionVariables.yml`, but doesn't declare this dependency. This issue exists in both the release branch and the default branch. + +**This should be fixed in the default branch first**, then backported if needed. The proper fix is to ensure template dependencies are correctly declared, rather than using hardcoded paths as a workaround. + +--- + +**Suggested Issue for Default Branch:** + +### Issue Title +`channelSelection.yml` template missing dependency on `SetVersionVariables.yml` + +### Description +The `channelSelection.yml` template uses the `$repoRoot` variable but doesn't ensure it's set beforehand by including `SetVersionVariables.yml`. + +**Current State:** +- `channelSelection.yml` expects `$repoRoot` to be available +- Not all pipelines that use `channelSelection.yml` include `SetVersionVariables.yml` first +- This creates an implicit dependency that's not enforced + +**Expected State:** +Either: +1. `channelSelection.yml` should include `SetVersionVariables.yml` as a dependency, OR +2. `channelSelection.yml` should be refactored to not depend on `$repoRoot`, OR +3. Pipelines using `channelSelection.yml` should explicitly include `SetVersionVariables.yml` first + +**Files Affected:** +- `.pipelines/templates/channelSelection.yml` +- `.pipelines/templates/package-create-msix.yml` +- `.pipelines/templates/release-SetTagAndChangelog.yml` + +**Priority:** Medium +**Labels:** `Issue-Bug`, `Area-Build`, `Area-Pipeline` +``` + +## Issue Template Format + +When creating an issue template for the default branch, use this structure: + +```markdown +### Issue Title +[Clear, concise description of the problem] + +### Description +[Detailed explanation of the issue] + +**Current State:** +- [What's happening now] +- [Why it's problematic] + +**Expected State:** +- [What should happen] +- [Proposed solution(s)] + +**Files Affected:** +- [List of files] + +**Priority:** [Low/Medium/High/Critical] +**Labels:** [Suggested labels like `Issue-Bug`, `Area-*`] + +**Additional Context:** +[Any additional information, links to related issues, etc.] +``` + +## Common Scenarios + +### Scenario 1: Template Dependency Issues + +**Indicators:** +- Missing template includes +- Undefined variables from other templates +- Assumptions about pipeline execution order + +**Action:** Suggest fixing template dependencies in the default branch. + +### Scenario 2: Hardcoded Values + +**Indicators:** +- Hardcoded paths replacing variables +- Environment-specific values in shared code +- Magic strings or numbers + +**Action:** Suggest proper variable/parameter usage in the default branch. + +### Scenario 3: Logic Errors + +**Indicators:** +- Incorrect conditional logic +- Missing error handling +- Race conditions + +**Action:** Suggest fixing the logic in the default branch unless it's release-specific. + +### Scenario 4: Legitimate Release Branch Fixes + +**Indicators:** +- Version-specific configuration +- Release packaging changes +- Backport of already-fixed default branch issue + +**Action:** Provide normal code review feedback for the current PR. + +## Best Practices + +1. **Always check if the issue exists in the default branch** before suggesting a release-branch-only fix +2. **Prefer fixing root causes over workarounds** +3. **Provide clear rationale** for why a fix belongs in the default branch +4. **Include actionable issue templates** so users can easily create issues +5. **Be helpful, not blocking** - provide the feedback even if you can't enforce where it's fixed + +## Examples of Good vs. Bad Approaches + +### ❌ Bad: Workaround in Release Branch Only + +```yaml +# In release/v7.5 only +- pwsh: | + $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw +``` + +**Why bad:** Hardcodes path to work around missing `$repoRoot`, doesn't fix the default branch. + +### ✅ Good: Fix in Default Branch, Then Backport + +```yaml +# In default branch first +- template: SetVersionVariables.yml@self # Ensures $repoRoot is set +- template: channelSelection.yml@self # Now can use $repoRoot +``` + +**Why good:** Fixes the root cause by ensuring dependencies are declared, then backport to release if needed. + +## When in Doubt + +If you're unsure whether an issue should be fixed in the current branch or the default branch, ask yourself: + +1. Does this issue exist in the default branch? +2. Is this a workaround or a proper fix? +3. Will other branches/releases benefit from this fix? + +If the answer to any of these is "yes," suggest fixing it in the default branch first. diff --git a/.github/instructions/onebranch-restore-phase-pattern.instructions.md b/.github/instructions/onebranch-restore-phase-pattern.instructions.md new file mode 100644 index 00000000000..0945bb47c0b --- /dev/null +++ b/.github/instructions/onebranch-restore-phase-pattern.instructions.md @@ -0,0 +1,83 @@ +--- +applyTo: ".pipelines/**/*.{yml,yaml}" +--- + +# OneBranch Restore Phase Pattern + +## Overview +When steps need to run in the OneBranch restore phase (before the main build phase), the `ob_restore_phase` environment variable must be set in the `env:` block of **each individual step**. + +## Pattern + +### ✅ Correct (Working Pattern) +```yaml +parameters: +- name: "ob_restore_phase" + type: boolean + default: true # or false if you don't want restore phase + +steps: +- powershell: | + # script content + displayName: 'Step Name' + env: + ob_restore_phase: ${{ parameters.ob_restore_phase }} +``` + +The key is to: +1. Define `ob_restore_phase` as a **boolean** parameter +2. Set `ob_restore_phase: ${{ parameters.ob_restore_phase }}` directly in each step's `env:` block +3. Pass `true` to run in restore phase, `false` to run in normal build phase + +### ❌ Incorrect (Does Not Work) +```yaml +steps: +- powershell: | + # script content + displayName: 'Step Name' + ${{ if eq(parameters.useRestorePhase, 'yes') }}: + env: + ob_restore_phase: true +``` + +Using conditionals at the same indentation level as `env:` causes only the first step to execute in restore phase. + +## Parameters + +Templates using this pattern should accept an `ob_restore_phase` boolean parameter: + +```yaml +parameters: +- name: "ob_restore_phase" + type: boolean + default: true # Set to true to run in restore phase by default +``` + +## Reference Examples + +Working examples of this pattern can be found in: +- `.pipelines/templates/insert-nuget-config-azfeed.yml` - Demonstrates the correct pattern +- `.pipelines/templates/SetVersionVariables.yml` - Updated to use this pattern + +## Why This Matters + +The restore phase in OneBranch pipelines runs before signing and other build operations. Steps that need to: +- Set environment variables for the entire build +- Configure authentication +- Prepare the repository structure + +Must run in the restore phase to be available when subsequent stages execute. + +## Common Use Cases + +- Setting `REPOROOT` variable +- Configuring NuGet feeds with authentication +- Setting version variables +- Repository preparation and validation + +## Troubleshooting + +If only the first step in your template is running in restore phase: +1. Check that `env:` block exists for **each step** +2. Verify the conditional `${{ if ... }}:` is **inside** the `env:` block +3. Confirm indentation is correct (conditional is indented under `env:`) diff --git a/.github/instructions/onebranch-signing-configuration.instructions.md b/.github/instructions/onebranch-signing-configuration.instructions.md new file mode 100644 index 00000000000..747fcaffdd6 --- /dev/null +++ b/.github/instructions/onebranch-signing-configuration.instructions.md @@ -0,0 +1,195 @@ +--- +applyTo: + - ".pipelines/**/*.yml" + - ".pipelines/**/*.yaml" +--- + +# OneBranch Signing Configuration + +This guide explains how to configure OneBranch signing variables in Azure Pipeline jobs, particularly when signing is not required. + +## Purpose + +OneBranch pipelines include signing infrastructure by default. For build-only jobs where signing happens in a separate stage, you should disable signing setup to improve performance and avoid unnecessary overhead. + +## Disable Signing for Build-Only Jobs + +When a job does not perform signing (e.g., it only builds artifacts that will be signed in a later stage), disable both signing setup and code sign validation: + +```yaml +variables: + - name: ob_signing_setup_enabled + value: false # Disable signing setup - this is a build-only stage + - name: ob_sdl_codeSignValidation_enabled + value: false # Skip signing validation in build-only stage +``` + +### Why Disable These Variables? + +**`ob_signing_setup_enabled: false`** +- Prevents OneBranch from setting up the signing infrastructure +- Reduces job startup time +- Avoids unnecessary credential validation +- Only disable when the job will NOT sign any artifacts + +**`ob_sdl_codeSignValidation_enabled: false`** +- Skips validation that checks if files are properly signed +- Appropriate for build stages where artifacts are unsigned +- Must be enabled in signing/release stages to validate signatures + +## Common Patterns + +### Build-Only Job (No Signing) + +```yaml +jobs: +- job: build_artifacts + variables: + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_codeSignValidation_enabled + value: false + steps: + - checkout: self + - pwsh: | + # Build unsigned artifacts + Start-PSBuild +``` + +### Signing Job + +```yaml +jobs: +- job: sign_artifacts + variables: + - name: ob_signing_setup_enabled + value: true + - name: ob_sdl_codeSignValidation_enabled + value: true + steps: + - checkout: self + env: + ob_restore_phase: true # Steps before first signing operation + - pwsh: | + # Prepare artifacts for signing + env: + ob_restore_phase: true # Steps before first signing operation + - task: onebranch.pipeline.signing@1 + displayName: 'Sign artifacts' + # Signing step runs in build phase (no ob_restore_phase) + - pwsh: | + # Post-signing validation + # Post-signing steps run in build phase (no ob_restore_phase) +``` + +## Restore Phase Usage with Signing + +**The restore phase (`ob_restore_phase: true`) should only be used in jobs that perform signing operations.** It separates preparation steps from the actual signing and build steps. + +### When to Use Restore Phase + +Use `ob_restore_phase: true` **only** in jobs where `ob_signing_setup_enabled: true`: + +```yaml +jobs: +- job: sign_artifacts + variables: + - name: ob_signing_setup_enabled + value: true # Signing enabled + steps: + # Steps BEFORE first signing operation: use restore phase + - checkout: self + env: + ob_restore_phase: true + - template: prepare-for-signing.yml + parameters: + ob_restore_phase: true + + # SIGNING STEP: runs in build phase (no ob_restore_phase) + - task: onebranch.pipeline.signing@1 + displayName: 'Sign artifacts' + + # Steps AFTER signing: run in build phase (no ob_restore_phase) + - pwsh: | + # Validation or packaging +``` + +### When NOT to Use Restore Phase + +**Do not use restore phase in build-only jobs** where `ob_signing_setup_enabled: false`: + +```yaml +jobs: +- job: build_artifacts + variables: + - name: ob_signing_setup_enabled + value: false # No signing + - name: ob_sdl_codeSignValidation_enabled + value: false + steps: + - checkout: self + # NO ob_restore_phase - not needed without signing + - pwsh: | + Start-PSBuild +``` + +**Why?** The restore phase is part of OneBranch's signing infrastructure. Using it without signing enabled adds unnecessary overhead without benefit. + +## Related Variables + +Other OneBranch signing-related variables: + +- `ob_sdl_binskim_enabled`: Controls BinSkim security analysis (can be false in build-only, true in signing stages) + +## Best Practices + +1. **Separate build and signing stages**: Build artifacts in one job, sign in another +2. **Disable signing in build stages**: Improves performance and clarifies intent +3. **Only use restore phase with signing**: The restore phase should only be used in jobs where signing is enabled (`ob_signing_setup_enabled: true`) +4. **Restore phase before first signing step**: All steps before the first signing operation should use `ob_restore_phase: true` +5. **Always validate after signing**: Enable validation in signing stages to catch issues +6. **Document the reason**: Add comments explaining why signing is disabled or why restore phase is used + +## Example: Split Build and Sign Pipeline + +```yaml +stages: + - stage: Build + jobs: + - job: build_windows + variables: + - name: ob_signing_setup_enabled + value: false # Build-only, no signing + - name: ob_sdl_codeSignValidation_enabled + value: false # Artifacts are unsigned + steps: + - template: templates/build-unsigned.yml + + - stage: Sign + dependsOn: Build + jobs: + - job: sign_windows + variables: + - name: ob_signing_setup_enabled + value: true # Enable signing infrastructure + - name: ob_sdl_codeSignValidation_enabled + value: true # Validate signatures + steps: + - template: templates/sign-artifacts.yml +``` + +## Troubleshooting + +**Job fails with signing-related errors but signing is disabled:** +- Verify `ob_signing_setup_enabled: false` is set in variables +- Check that no template is overriding the setting +- Ensure `ob_sdl_codeSignValidation_enabled: false` is also set + +**Signed artifacts fail validation:** +- Confirm `ob_sdl_codeSignValidation_enabled: true` in signing job +- Verify signing actually occurred +- Check certificate configuration + +## Reference + +- PowerShell signing templates: `.pipelines/templates/packaging/windows/sign.yml` diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 8e175c5a6bb..997b7c458be 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -99,7 +99,6 @@ extends: - template: .pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - UseJson: no - pwsh: | Write-Verbose -Verbose 'PowerShell Version: $(version)' diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index b309791d77d..51acfc08053 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -166,7 +166,6 @@ extends: parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes - UseJson: no - stage: macos displayName: macOS - build and sign diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 9c2dee1c571..8e06be1cc64 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -127,11 +127,13 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - stage: prep + displayName: 'Prep BuildInfo+Az' jobs: - template: /.pipelines/templates/checkAzureContainer.yml@self - stage: mac_package - dependsOn: [prep] + displayName: 'macOS Pkg+Sign' + dependsOn: [] jobs: - template: /.pipelines/templates/mac-package-build.yml@self parameters: @@ -141,35 +143,65 @@ extends: parameters: buildArchitecture: arm64 - - stage: windows_package - dependsOn: [prep] + - stage: windows_package_build + displayName: 'Win Pkg (unsigned)' + dependsOn: [] jobs: - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: x64 - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: arm64 - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: x86 - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: fxdependent - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: fxdependentWinDesktop - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: minsize + + - stage: windows_package_sign + displayName: 'Win Pkg Sign' + dependsOn: [windows_package_build] + jobs: + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: x64 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: arm64 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: x86 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: fxdependent + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: fxdependentWinDesktop + + - template: /.pipelines/templates/packaging/windows/sign.yml@self parameters: runtime: minsize - stage: linux_package - dependsOn: [prep] + displayName: 'Linux Pkg+Sign' + dependsOn: [] jobs: - template: /.pipelines/templates/linux-package-build.yml@self parameters: @@ -251,17 +283,19 @@ extends: jobName: minSize - stage: nupkg - dependsOn: [prep] + displayName: 'NuGet Pkg+Sign' + dependsOn: [] jobs: - template: /.pipelines/templates/nupkg.yml@self - stage: msixbundle - displayName: 'Create MSIX Bundle' - dependsOn: [windows_package] + displayName: 'MSIX Bundle+Sign' + dependsOn: [windows_package_build] # Only depends on unsigned packages jobs: - template: /.pipelines/templates/package-create-msix.yml@self - stage: upload - dependsOn: [mac_package, windows_package, linux_package, nupkg, msixbundle] + displayName: 'Upload' + dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON jobs: - template: /.pipelines/templates/uploadToAzure.yml@self diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 7ba92f4eda9..096dfb574a4 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -159,7 +159,6 @@ extends: parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes - UseJson: no - pwsh: | $version = '$(Version)' diff --git a/.pipelines/templates/SetVersionVariables.yml b/.pipelines/templates/SetVersionVariables.yml index 9f692373f6c..30ed1704022 100644 --- a/.pipelines/templates/SetVersionVariables.yml +++ b/.pipelines/templates/SetVersionVariables.yml @@ -1,49 +1,18 @@ parameters: - ReleaseTagVar: v6.2.0 - ReleaseTagVarName: ReleaseTagVar - CreateJson: 'no' - UseJson: 'yes' +- name: ReleaseTagVar + default: v6.2.0 +- name: ReleaseTagVarName + default: ReleaseTagVar +- name: CreateJson + default: 'no' +- name: ob_restore_phase + type: boolean + default: true steps: -- ${{ if eq(parameters['UseJson'],'yes') }}: - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: 'drop_prep_SetVars' - itemPattern: '*.json' - downloadPath: '$(System.ArtifactsDirectory)' - displayName: Download Build Info Json - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - -- powershell: | - $path = "./build.psm1" - if($env:REPOROOT){ - Write-Verbose "reporoot already set to ${env:REPOROOT}" -Verbose - exit 0 - } - if(Test-Path -Path $path) - { - Write-Verbose "reporoot detected at: ." -Verbose - $repoRoot = '.' - } - else{ - $path = "./PowerShell/build.psm1" - if(Test-Path -Path $path) - { - Write-Verbose "reporoot detect at: ./PowerShell" -Verbose - $repoRoot = './PowerShell' - } - } - if($repoRoot) { - $vstsCommandString = "vso[task.setvariable variable=repoRoot]$repoRoot" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - } else { - Write-Verbose -Verbose "repo not found" - } - displayName: 'Set repo Root' - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue +- template: set-reporoot.yml@self + parameters: + ob_restore_phase: ${{ parameters.ob_restore_phase }} - powershell: | $createJson = ("${{ parameters.CreateJson }}" -ne "no") @@ -69,11 +38,11 @@ steps: Write-Host "##$vstsCommandString" displayName: 'Set ${{ parameters.ReleaseTagVarName }} and other version Variables' env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + ob_restore_phase: ${{ parameters.ob_restore_phase }} - powershell: | Get-ChildItem -Path Env: | Out-String -Width 150 displayName: Capture environment condition: succeededOrFailed() env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/checkAzureContainer.yml b/.pipelines/templates/checkAzureContainer.yml index a6a86214d07..3e383d2c572 100644 --- a/.pipelines/templates/checkAzureContainer.yml +++ b/.pipelines/templates/checkAzureContainer.yml @@ -3,6 +3,8 @@ jobs: variables: - group: Azure Blob variable group - group: AzureBlobServiceConnection + - name: ob_artifactBaseName + value: BuildInfoJson - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT/BuildJson' - name: ob_sdl_sbom_enabled @@ -29,7 +31,6 @@ jobs: parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes - UseJson: no - template: /.pipelines/templates/cloneToOfficialPath.yml@self diff --git a/.pipelines/templates/cloneToOfficialPath.yml b/.pipelines/templates/cloneToOfficialPath.yml index 844d8b8028d..b060c713683 100644 --- a/.pipelines/templates/cloneToOfficialPath.yml +++ b/.pipelines/templates/cloneToOfficialPath.yml @@ -1,5 +1,9 @@ parameters: - nativePathRoot: '' +- name: nativePathRoot + default: '' +- name: ob_restore_phase + type: boolean + default: true steps: - powershell: | @@ -12,8 +16,16 @@ steps: else { Write-Verbose -Verbose -Message "No cleanup required." } - git clone --quiet $env:REPOROOT $nativePath + # REPOROOT must be set by the pipeline - this is where the repository was checked out + $sourceDir = $env:REPOROOT + if (-not $sourceDir) { throw "REPOROOT environment variable is not set. This step depends on REPOROOT being configured in the pipeline." } + + $buildModulePath = Join-Path $sourceDir "build.psm1" + if (-not (Test-Path $buildModulePath)) { throw "build.psm1 not found at: $buildModulePath. REPOROOT must point to the PowerShell repository root." } + + Write-Verbose -Verbose -Message "Cloning from: $sourceDir to $nativePath" + git clone --quiet $sourceDir $nativePath displayName: Clone PowerShell Repo to /PowerShell errorActionPreference: silentlycontinue env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml index 17f07a597b5..a07000c7067 100644 --- a/.pipelines/templates/compliance/apiscan.yml +++ b/.pipelines/templates/compliance/apiscan.yml @@ -51,8 +51,7 @@ jobs: - template: ../SetVersionVariables.yml parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: ../insert-nuget-config-azfeed.yml parameters: diff --git a/.pipelines/templates/install-dotnet.yml b/.pipelines/templates/install-dotnet.yml index c2a2cfebeca..464e13d1047 100644 --- a/.pipelines/templates/install-dotnet.yml +++ b/.pipelines/templates/install-dotnet.yml @@ -1,3 +1,8 @@ +parameters: +- name: ob_restore_phase + type: boolean + default: true + steps: - pwsh: | if (-not (Test-Path '$(RepoRoot)')) { @@ -15,5 +20,5 @@ steps: displayName: 'Install dotnet SDK' workingDirectory: $(RepoRoot) env: - ob_restore_phase: true + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index 02839c7d650..8354c60feae 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -54,8 +54,7 @@ jobs: - template: SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: shouldSign.yml diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 6f746438da9..1bd19e09d98 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -52,8 +52,7 @@ jobs: - template: SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: shouldSign.yml diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index 175c847944a..2aed6749baa 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -41,8 +41,7 @@ jobs: - template: SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: shouldSign.yml diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index dedbdf543f9..1df89e2de07 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -22,7 +22,7 @@ jobs: - task: DownloadPipelineArtifact@2 inputs: buildType: 'current' - artifact: drop_windows_package_package_win_arm64 + artifact: drop_windows_package_arm64 itemPattern: | **/*.msix targetPath: '$(Build.ArtifactStagingDirectory)/downloads' @@ -31,7 +31,7 @@ jobs: - task: DownloadPipelineArtifact@2 inputs: buildType: 'current' - artifact: drop_windows_package_package_win_x64 + artifact: drop_windows_package_x64 itemPattern: | **/*.msix targetPath: '$(Build.ArtifactStagingDirectory)/downloads' @@ -40,7 +40,7 @@ jobs: - task: DownloadPipelineArtifact@2 inputs: buildType: 'current' - artifact: drop_windows_package_package_win_x86 + artifact: drop_windows_package_x86 itemPattern: | **/*.msix targetPath: '$(Build.ArtifactStagingDirectory)/downloads' diff --git a/.pipelines/templates/windows-package-build.yml b/.pipelines/templates/packaging/windows/package.yml similarity index 56% rename from .pipelines/templates/windows-package-build.yml rename to .pipelines/templates/packaging/windows/package.yml index 50309c5099b..9a8be4b18fe 100644 --- a/.pipelines/templates/windows-package-build.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -2,8 +2,8 @@ parameters: runtime: x64 jobs: -- job: package_win_${{ parameters.runtime }} - displayName: Package Windows ${{ parameters.runtime }} +- job: build_win_${{ parameters.runtime }} + displayName: Build Windows Packages ${{ parameters.runtime }} condition: succeeded() pool: type: windows @@ -11,6 +11,12 @@ jobs: variables: - name: runCodesignValidationInjection value: false + - name: ob_sdl_codeSignValidation_enabled + value: false # Skip signing validation in build-only stage + - name: ob_signing_setup_enabled + value: false # Disable signing setup - this is a build-only stage, signing happens in separate stage + - name: ob_artifactBaseName + value: drop_windows_package_${{ parameters.runtime }} - name: nugetMultiFeedWarnLevel value: none - name: NugetSecurityAnalysisWarningLevel @@ -22,7 +28,7 @@ jobs: - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)\ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled - value: true + value: false # Disable for build-only, enable in signing stage - name: ob_sdl_tsa_configFile value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - name: ob_sdl_credscan_suppressionsFile @@ -34,40 +40,35 @@ jobs: steps: - checkout: self clean: true - env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - pwsh: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture environment - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - - template: SetVersionVariables.yml@self + - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no + ob_restore_phase: false - - template: shouldSign.yml + - template: /.pipelines/templates/shouldSign.yml@self + parameters: + ob_restore_phase: false - - template: cloneToOfficialPath.yml + - template: /.pipelines/templates/cloneToOfficialPath.yml@self parameters: nativePathRoot: '$(Agent.TempDirectory)' + ob_restore_phase: false - download: CoOrdinatedBuildPipeline artifact: drop_windows_build_windows_${{ parameters.runtime }}_release displayName: Download signed artifacts condition: ${{ ne(parameters.runtime, 'minSize') }} - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - download: CoOrdinatedBuildPipeline artifact: drop_windows_build_windows_x64_${{ parameters.runtime }} displayName: Download minsize signed artifacts condition: ${{ eq(parameters.runtime, 'minSize') }} - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - pwsh: | Write-Verbose -Verbose "signed artifacts" @@ -75,18 +76,10 @@ jobs: displayName: 'Capture Downloaded Artifacts' # Diagnostics is not critical it passes every time it runs continueOnError: true - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - template: /.pipelines/templates/install-dotnet.yml@self - - - pwsh: | - $msixUrl = '$(makeappUrl)' - Invoke-RestMethod -Uri $msixUrl -OutFile '$(Pipeline.Workspace)\makeappx.zip' - Expand-Archive '$(Pipeline.Workspace)\makeappx.zip' -destination '\' -Force - displayName: Install packaging tools - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + parameters: + ob_restore_phase: false - pwsh: | $runtime = '$(Runtime)' @@ -168,94 +161,19 @@ jobs: Start-PSPackage -Type $packageTypes -SkipReleaseChecks -WindowsRuntime $WindowsRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS - displayName: 'Package ${{ parameters.buildArchitecture}}' + displayName: 'Build Packages (Unsigned)' env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - - - task: onebranch.pipeline.signing@1 - displayName: Sign MSI packages - inputs: - command: 'sign' - signing_profile: external_distribution - files_to_sign: '**\*.msi' - search_root: '$(Pipeline.Workspace)' - - - pwsh: | - $runtime = '$(Runtime)' - Write-Verbose -Verbose "runtime = '$(Runtime)'" - - $repoRoot = "$env:REPOROOT" - Import-Module "$repoRoot\build.psm1" - Import-Module "$repoRoot\tools\packaging" - - $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') - - if ($runtime -in $noExeRuntimes) { - Write-Verbose -Verbose "No EXE generated for $runtime" - return - } - - $version = '$(Version)' - - $msiLocation = Get-ChildItem -Path $(Pipeline.Workspace) -Recurse -Filter "powershell-*$runtime.msi" | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msiLocation: $msiLocation" - - Set-Location $repoRoot - - $exePath = New-ExePackage -ProductVersion $version -ProductTargetArchitecture $runtime -MsiLocationPath $msiLocation - Write-Verbose -Verbose "setting vso[task.setvariable variable=exePath]$exePath" - Write-Host "##vso[task.setvariable variable=exePath]$exePath" - Write-Verbose -Verbose "exePath: $exePath" - - $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe - Expand-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime - displayName: 'Make exe and expand package' - - - task: onebranch.pipeline.signing@1 - displayName: Sign exe engine - inputs: - command: 'sign' - signing_profile: $(msft_3rd_party_cert_id) - files_to_sign: '$(System.ArtifactsDirectory)\unsignedEngine\*.exe' - search_root: '$(Pipeline.Workspace)' - - - pwsh: | - $runtime = '$(Runtime)' - Write-Verbose -Verbose "runtime = '$(Runtime)'" - $repoRoot = "$env:REPOROOT" - Import-Module "$repoRoot\build.psm1" - Import-Module "$repoRoot\tools\packaging" - - $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') - - if ($runtime -in $noExeRuntimes) { - Write-Verbose -Verbose "No EXE generated for $runtime" - return - } - - $exePath = '$(exePath)' - $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe - $enginePath | Get-AuthenticodeSignature | out-string | Write-Verbose -verbose - Compress-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime - displayName: Compress signed exe package - - - task: onebranch.pipeline.signing@1 - displayName: Sign exe packages - inputs: - command: 'sign' - signing_profile: external_distribution - files_to_sign: '**\*.exe' - search_root: '$(Pipeline.Workspace)' + # Copy unsigned packages to output directory - pwsh: | $runtime = '$(Runtime)' Write-Verbose -Verbose "runtime = '$(Runtime)'" $packageTypes = switch ($runtime) { - 'x64' { @('msi', 'zip', 'msix', 'exe') } - 'x86' { @('msi', 'zip', 'msix', 'exe') } - 'arm64' { @('msi', 'zip', 'msix', 'exe') } + 'x64' { @('msi', 'zip', 'msix') } + 'x86' { @('msi', 'zip', 'msix') } + 'arm64' { @('msi', 'zip', 'msix') } 'fxdependent' { 'fxdependent' } 'fxdependentWinDesktop' { 'fxdependent-win-desktop' } 'minsize' { 'min-size' } @@ -268,35 +186,25 @@ jobs: if ($packageTypes -contains 'msi') { $msiPkgNameFilter = "powershell-*.msi" $msiPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msiPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msiPkgPath: $msiPkgPath" - Copy-Item -Path $msiPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose - } - - if ($packageTypes -contains 'exe') { - $msiPkgNameFilter = "powershell-*.exe" - $msiPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msiPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msiPkgPath: $msiPkgPath" + Write-Verbose -Verbose "unsigned msiPkgPath: $msiPkgPath" Copy-Item -Path $msiPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose } if ($packageTypes -contains 'zip' -or $packageTypes -contains 'fxdependent' -or $packageTypes -contains 'min-size' -or $packageTypes -contains 'fxdependent-win-desktop') { $zipPkgNameFilter = "powershell-*.zip" $zipPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $zipPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "zipPkgPath: $zipPkgPath" + Write-Verbose -Verbose "unsigned zipPkgPath: $zipPkgPath" Copy-Item -Path $zipPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose } if ($packageTypes -contains 'msix') { $msixPkgNameFilter = "powershell-*.msix" $msixPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msixPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msixPkgPath: $msixPkgPath" + Write-Verbose -Verbose "unsigned msixPkgPath: $msixPkgPath" Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose } - displayName: Copy to output directory + displayName: Copy unsigned packages to output directory - pwsh: | Get-ChildItem -Path $(ob_outputDirectory) -Recurse - displayName: 'List artifacts' - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - + displayName: 'List unsigned artifacts' diff --git a/.pipelines/templates/packaging/windows/sign.yml b/.pipelines/templates/packaging/windows/sign.yml new file mode 100644 index 00000000000..4a095ba7694 --- /dev/null +++ b/.pipelines/templates/packaging/windows/sign.yml @@ -0,0 +1,216 @@ +parameters: + runtime: x64 + +jobs: +- job: sign_win_${{ parameters.runtime }} + displayName: Sign Windows Packages ${{ parameters.runtime }} + condition: succeeded() + pool: + type: windows + + variables: + - name: runCodesignValidationInjection + value: false + - name: ob_artifactBaseName + value: drop_windows_package_package_win_${{ parameters.runtime }} + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)\ONEBRANCH_ARTIFACT' + - name: ob_sdl_binskim_enabled + value: true + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: Runtime + value: ${{ parameters.runtime }} + - group: msixTools + + steps: + - checkout: self + clean: true + env: + ob_restore_phase: true + + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no + + - template: /.pipelines/templates/shouldSign.yml@self + + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + parameters: + nativePathRoot: '$(Agent.TempDirectory)' + + # Download unsigned packages from the build stage + - download: current + artifact: drop_windows_package_${{ parameters.runtime }} + displayName: Download unsigned packages + env: + ob_restore_phase: true + + - pwsh: | + Write-Verbose -Verbose "Downloaded unsigned artifacts:" + Get-ChildItem "$(Pipeline.Workspace)\drop_windows_package_${{ parameters.runtime }}" -Recurse + displayName: 'Capture Downloaded Unsigned Artifacts' + continueOnError: true + env: + ob_restore_phase: true + + - template: /.pipelines/templates/install-dotnet.yml@self + + # Import build.psm1 and bootstrap packaging dependencies (WiX Toolset) + - pwsh: | + $repoRoot = "$env:REPOROOT" + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + Write-Verbose -Verbose "Modules imported successfully" + + # Install WiX Toolset for EXE package creation + $isArm64 = '$(Runtime)' -eq 'arm64' + $env:RUNTIME = '$(Runtime)' + Start-PSBootstrap -Scenario Package + displayName: 'Import modules and install WiX Toolset' + env: + ob_restore_phase: true + + # Sign MSI packages + - task: onebranch.pipeline.signing@1 + displayName: Sign MSI packages + inputs: + command: 'sign' + signing_profile: external_distribution + files_to_sign: '**\*.msi' + search_root: '$(Pipeline.Workspace)' + + # Create EXE package from signed MSI (for x64, x86, arm64 only) + - pwsh: | + $runtime = '$(Runtime)' + Write-Verbose -Verbose "runtime = '$(Runtime)'" + + $repoRoot = "$env:REPOROOT" + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + + $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') + + if ($runtime -in $noExeRuntimes) { + Write-Verbose -Verbose "No EXE generated for $runtime" + return + } + + $version = '$(Version)' + + $msiLocation = Get-ChildItem -Path $(Pipeline.Workspace) -Recurse -Filter "powershell-*$runtime.msi" | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "msiLocation: $msiLocation" + + Set-Location $repoRoot + + $exePath = New-ExePackage -ProductVersion $version -ProductTargetArchitecture $runtime -MsiLocationPath $msiLocation + Write-Verbose -Verbose "setting vso[task.setvariable variable=exePath]$exePath" + Write-Host "##vso[task.setvariable variable=exePath]$exePath" + Write-Verbose -Verbose "exePath: $exePath" + + $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe + Expand-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime + displayName: 'Make exe and expand package' + + # Sign EXE engine + - task: onebranch.pipeline.signing@1 + displayName: Sign exe engine + inputs: + command: 'sign' + signing_profile: $(msft_3rd_party_cert_id) + files_to_sign: '$(System.ArtifactsDirectory)\unsignedEngine\*.exe' + search_root: '$(Pipeline.Workspace)' + + # Compress signed EXE engine back into package + - pwsh: | + $runtime = '$(Runtime)' + Write-Verbose -Verbose "runtime = '$(Runtime)'" + $repoRoot = "$env:REPOROOT" + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + + $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') + + if ($runtime -in $noExeRuntimes) { + Write-Verbose -Verbose "No EXE generated for $runtime" + return + } + + $exePath = '$(exePath)' + $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe + $enginePath | Get-AuthenticodeSignature | out-string | Write-Verbose -verbose + Compress-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime + displayName: Compress signed exe package + + # Sign final EXE packages + - task: onebranch.pipeline.signing@1 + displayName: Sign exe packages + inputs: + command: 'sign' + signing_profile: external_distribution + files_to_sign: '**\*.exe' + search_root: '$(Pipeline.Workspace)' + + # Copy all signed packages to output directory + - pwsh: | + $runtime = '$(Runtime)' + Write-Verbose -Verbose "runtime = '$(Runtime)'" + + $packageTypes = switch ($runtime) { + 'x64' { @('msi', 'zip', 'msix', 'exe') } + 'x86' { @('msi', 'zip', 'msix', 'exe') } + 'arm64' { @('msi', 'zip', 'msix', 'exe') } + 'fxdependent' { 'fxdependent' } + 'fxdependentWinDesktop' { 'fxdependent-win-desktop' } + 'minsize' { 'min-size' } + } + + if (-not (Test-Path $(ob_outputDirectory))) { + New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force + } + + if ($packageTypes -contains 'msi') { + $msiPkgNameFilter = "powershell-*.msi" + $msiPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msiPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "signed msiPkgPath: $msiPkgPath" + Copy-Item -Path $msiPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + + if ($packageTypes -contains 'exe') { + $exePkgNameFilter = "powershell-*.exe" + $exePkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $exePkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "signed exePkgPath: $exePkgPath" + Copy-Item -Path $exePkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + + if ($packageTypes -contains 'zip' -or $packageTypes -contains 'fxdependent' -or $packageTypes -contains 'min-size' -or $packageTypes -contains 'fxdependent-win-desktop') { + $zipPkgNameFilter = "powershell-*.zip" + $zipPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $zipPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "signed zipPkgPath: $zipPkgPath" + Copy-Item -Path $zipPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + + if ($packageTypes -contains 'msix') { + $msixPkgNameFilter = "powershell-*.msix" + $msixPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msixPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "signed msixPkgPath: $msixPkgPath" + Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + displayName: Copy signed packages to output directory + + - pwsh: | + Get-ChildItem -Path $(ob_outputDirectory) -Recurse + displayName: 'List signed artifacts' + env: + ob_restore_phase: true diff --git a/.pipelines/templates/release-MakeBlobPublic.yml b/.pipelines/templates/release-MakeBlobPublic.yml index bfa07c9b27f..f705c79e79d 100644 --- a/.pipelines/templates/release-MakeBlobPublic.yml +++ b/.pipelines/templates/release-MakeBlobPublic.yml @@ -45,8 +45,7 @@ jobs: - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - pwsh: | Get-ChildItem Env: @@ -132,8 +131,7 @@ jobs: - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - pwsh: | Get-ChildItem Env: diff --git a/.pipelines/templates/release-checkout-pwsh-repo.yml b/.pipelines/templates/release-checkout-pwsh-repo.yml deleted file mode 100644 index 9a7486887a6..00000000000 --- a/.pipelines/templates/release-checkout-pwsh-repo.yml +++ /dev/null @@ -1,13 +0,0 @@ -steps: - - pwsh: | - Write-Verbose -Verbose "Deploy Box Product Pathway Does Not Support the `"checkout`" task" - if ($ENV:BUILD_REASON -eq 'PullRequest') { - throw 'We dont support PRs' - } - - Write-Verbose -Verbose $ENV:BUILD_SOURCEBRANCH - $branchName = $ENV:BUILD_SOURCEBRANCH -replace '^refs/heads/' - Write-Verbose -Verbose "Branch Name: $branchName" - git clone --depth 1 --branch $branchName https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/PowerShell '$(Pipeline.Workspace)/PowerShell' - cd $(Pipeline.Workspace)/PowerShell - displayName: Checkout Powershell Repository diff --git a/.pipelines/templates/release-download-packages.yml b/.pipelines/templates/release-download-packages.yml deleted file mode 100644 index 27a3098d1e1..00000000000 --- a/.pipelines/templates/release-download-packages.yml +++ /dev/null @@ -1,122 +0,0 @@ -jobs: -- job: upload_packages - displayName: Upload packages - condition: succeeded() - pool: - type: windows - variables: - - template: ./variable/release-shared.yml@self - parameters: - REPOROOT: $(Build.SourcesDirectory) - SBOM: true - - steps: - - pwsh: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - displayName: Capture environment variables - - - download: PSPackagesOfficial - artifact: drop_linux_package_deb - displayName: Download linux deb packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_fxdependent - displayName: Download linux fx packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_mariner_arm64 - displayName: Download linux mariner packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_mariner_x64 - displayName: Download linux mariner x64 packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_minSize - displayName: Download linux min packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_rpm - displayName: Download linux rpm packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar - displayName: Download linux tar packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar_alpine - displayName: Download linux tar alpine packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar_alpine_fxd - displayName: Download linux tar alpine fxd packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar_arm - displayName: Download linux tar arm packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar_arm64 - displayName: Download linux tar arm 64 packages - - - download: PSPackagesOfficial - artifact: drop_nupkg_build_nupkg - displayName: Download nupkg packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_arm64 - displayName: Download windows arm64 packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_fxdependent - displayName: Download windows fxdependent packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_fxdependentWinDesktop - displayName: Download windows fxdependentWinDesktop packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_minsize - displayName: Download windows minsize packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_x64 - displayName: Download windows x64 packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_x86 - displayName: Download windows x86 packages - - - download: PSPackagesOfficial - artifact: macos-pkgs - displayName: Download macos tar packages - - - download: PSPackagesOfficial - artifact: drop_mac_package_sign_package_macos_arm64 - displayName: Download macos arm packages - - - download: PSPackagesOfficial - artifact: drop_mac_package_sign_package_macos_x64 - displayName: Download macos x64 packages - - - pwsh: | - Get-ChildItem '$(Pipeline.Workspace)/PSPackagesOfficial' -Recurse | Select-Object -ExpandProperty FullName - displayName: 'Capture downloads' - - - pwsh: | - $PackagesPath = '$(Pipeline.Workspace)/PSPackagesOfficial' - Write-Verbose -Verbose "Copying Github Release files in $PackagesPath to use in Release Pipeline" - - Write-Verbose -Verbose "Creating output directory for GitHub Release files: $(ob_outputDirectory)/GitHubPackages" - New-Item -Path $(ob_outputDirectory)/GitHubPackages -ItemType Directory -Force - Get-ChildItem -Path "$PackagesPath/*" -Recurse | - Where-Object { $_.Extension -notin '.msix', '.nupkg' } | - Where-Object { $_.Extension -in '.gz', '.pkg', '.msi', '.zip', '.deb', '.rpm', '.zip' } | - Copy-Item -Destination $(ob_outputDirectory)/GitHubPackages -Recurse -Verbose - - Write-Verbose -Verbose "Creating output directory for NuGet packages: $(ob_outputDirectory)/NuGetPackages" - New-Item -Path $(ob_outputDirectory)/NuGetPackages -ItemType Directory -Force - Get-ChildItem -Path "$PackagesPath/*" -Recurse | - Where-Object { $_.Extension -eq '.nupkg' } | - Copy-Item -Destination $(ob_outputDirectory)/NuGetPackages -Recurse -Verbose - displayName: Copy downloads to Artifacts diff --git a/.pipelines/templates/release-install-pwsh.yml b/.pipelines/templates/release-install-pwsh.yml deleted file mode 100644 index 9d7080a7e78..00000000000 --- a/.pipelines/templates/release-install-pwsh.yml +++ /dev/null @@ -1,34 +0,0 @@ -steps: - - task: PowerShell@2 - inputs: - targetType: inline - script: | - $localInstallerPath = Get-ChildItem -Path "$(Pipeline.Workspace)/GitHubPackages" -Filter '*win-x64.msi' | Select-Object -First 1 -ExpandProperty FullName - if (Test-Path -Path $localInstallerPath) { - Write-Verbose -Verbose "Installer found at $localInstallerPath" - } else { - throw "Installer not found" - } - Write-Verbose -Verbose "Installing PowerShell via msiexec" - Start-Process -FilePath msiexec -ArgumentList "/package $localInstallerPath /quiet REGISTER_MANIFEST=1" -Wait -NoNewWindow - $pwshPath = Get-ChildItem -Directory -Path 'C:\Program Files\PowerShell\7*' | Select-Object -First 1 -ExpandProperty FullName - if (Test-Path -Path $pwshPath) { - Write-Verbose -Verbose "PowerShell installed at $pwshPath" - Write-Verbose -Verbose "Adding pwsh to env:PATH" - Write-Host "##vso[task.prependpath]$pwshPath" - } else { - throw "PowerShell not installed" - } - displayName: Install pwsh 7 - - - task: PowerShell@2 - inputs: - targetType: inline - pwsh: true - script: | - Write-Verbose -Verbose "Pwsh 7 Installed" - Write-Verbose -Verbose "env:Path: " - $env:PATH -split ';' | ForEach-Object { - Write-Verbose -Verbose $_ - } - displayName: Check pwsh 7 installation diff --git a/.pipelines/templates/set-reporoot.yml b/.pipelines/templates/set-reporoot.yml new file mode 100644 index 00000000000..af7983afaa1 --- /dev/null +++ b/.pipelines/templates/set-reporoot.yml @@ -0,0 +1,35 @@ +parameters: +- name: ob_restore_phase + type: boolean + default: true + +steps: +- pwsh: | + $path = "./build.psm1" + if($env:REPOROOT){ + Write-Verbose "reporoot already set to ${env:REPOROOT}" -Verbose + exit 0 + } + if(Test-Path -Path $path) + { + Write-Verbose "reporoot detected at: ." -Verbose + $repoRoot = '.' + } + else{ + $path = "./PowerShell/build.psm1" + if(Test-Path -Path $path) + { + Write-Verbose "reporoot detected at: ./PowerShell" -Verbose + $repoRoot = './PowerShell' + } + } + if($repoRoot) { + $vstsCommandString = "vso[task.setvariable variable=repoRoot]$repoRoot" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + } else { + Write-Verbose -Verbose "repo not found" + } + displayName: 'Set repo Root' + env: + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/shouldSign.yml b/.pipelines/templates/shouldSign.yml index 4bac9e1a3ae..551297f3aaa 100644 --- a/.pipelines/templates/shouldSign.yml +++ b/.pipelines/templates/shouldSign.yml @@ -1,3 +1,8 @@ +parameters: +- name: ob_restore_phase + type: boolean + default: true + steps: - powershell: | $shouldSign = $true @@ -22,4 +27,4 @@ steps: Write-Host "##$vstsCommandString" displayName: 'Set SHOULD_SIGN Variable' env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index 5f43ab4cd7f..576830ba8f4 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -36,8 +36,7 @@ jobs: - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: /.pipelines/templates/release-SetReleaseTagandContainerName.yml@self From 579b53ea8345f659600eccc57dad2e9019b0cbaf Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 15:03:55 -0800 Subject: [PATCH 196/275] [release/v7.5] Move package validation to package pipeline (#26816) --- .pipelines/PowerShell-Packages-Official.yml | 6 ++++++ .pipelines/PowerShell-Release-Official.yml | 13 ++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 8e06be1cc64..afd82af4462 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -299,3 +299,9 @@ extends: dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON jobs: - template: /.pipelines/templates/uploadToAzure.yml@self + + - stage: validatePackages + displayName: 'Validate Packages' + dependsOn: [upload] + jobs: + - template: /.pipelines/templates/release-validate-packagenames.yml@self diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 36bee13a0c7..cefb49abbee 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -216,12 +216,6 @@ extends: arm64: 'yes' enableCredScan: false - - stage: validatePackages - displayName: 'Validate Packages' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-validate-packagenames.yml@self - - stage: ManualValidation dependsOn: [] displayName: Manual Validation @@ -272,7 +266,6 @@ extends: dependsOn: - ManualValidation - ReleaseAutomation - - validatePackages - fxdpackages - gbltool - validateSdk @@ -365,10 +358,12 @@ extends: This is typically done by the community 1-2 days after the release. - stage: PublishMsix - dependsOn: PushGitTagAndMakeDraftPublic + dependsOn: + - setReleaseTagAndChangelog + - PushGitTagAndMakeDraftPublic displayName: Publish MSIX to store variables: - ob_release_environment: Production + ob_release_environment: ${{ variables.releaseEnvironment }} jobs: - template: /.pipelines/templates/release-MSIX-Publish.yml@self parameters: From 914288e476dedd963153a9a4cb9c3dba9791e2eb Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 15:16:12 -0800 Subject: [PATCH 197/275] [release/v7.5] Add rebuild branch support with conditional MSIX signing (#26817) --- .../ServiceGroupRoot/Shell/Run/Run.ps1 | 6 ++- ...werShell-Coordinated_Packages-Official.yml | 13 +++++- .pipelines/PowerShell-Packages-Official.yml | 2 + .pipelines/templates/channelSelection.yml | 26 +++++++++-- .pipelines/templates/linux-package-build.yml | 18 +++++++- .pipelines/templates/mac-package-build.yml | 18 +++++++- .pipelines/templates/package-create-msix.yml | 46 ++++++++++++++----- .../templates/packaging/windows/package.yml | 18 +++++++- .pipelines/templates/rebuild-branch-check.yml | 17 +++++++ 9 files changed, 144 insertions(+), 20 deletions(-) create mode 100644 .pipelines/templates/rebuild-branch-check.yml diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 index 25a5686b33e..23f91c1bff2 100644 --- a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 +++ b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 @@ -354,6 +354,9 @@ try { $skipPublish = $metadataContent.SkipPublish $lts = $metadataContent.LTS + # Check if this is a rebuild version (e.g., 7.4.13-rebuild.5) + $isRebuild = $releaseVersion -match '-rebuild\.' + if ($releaseVersion.Contains('-')) { $channel = 'preview' $packageNames = @('powershell-preview') @@ -363,7 +366,8 @@ try { $packageNames = @('powershell') } - if ($lts) { + # Only add LTS package if not a rebuild branch + if ($lts -and -not $isRebuild) { $packageNames += @('powershell-lts') } diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 51acfc08053..7e9c44edac8 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -284,9 +284,20 @@ extends: - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) + - template: /.pipelines/templates/rebuild-branch-check.yml@self - powershell: | $metadata = Get-Content '$(Build.SourcesDirectory)/PowerShell/tools/metadata.json' -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't mark as LTS release for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, not marking as LTS release" -Verbose + } + @{ ReleaseVersion = "$(Version)"; LTSRelease = $LTS } | ConvertTo-Json | Out-File "$(Build.StagingDirectory)\release.json" Get-Content "$(Build.StagingDirectory)\release.json" diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index afd82af4462..18ef7b2d14c 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -293,6 +293,8 @@ extends: dependsOn: [windows_package_build] # Only depends on unsigned packages jobs: - template: /.pipelines/templates/package-create-msix.yml@self + parameters: + OfficialBuild: ${{ parameters.OfficialBuild }} - stage: upload displayName: 'Upload' diff --git a/.pipelines/templates/channelSelection.yml b/.pipelines/templates/channelSelection.yml index 3d1f445c559..9dd0f3fb216 100644 --- a/.pipelines/templates/channelSelection.yml +++ b/.pipelines/templates/channelSelection.yml @@ -2,13 +2,31 @@ steps: - pwsh: | # Determine LTS, Preview, or Stable $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw | ConvertFrom-Json + $releaseTag = '$(OutputReleaseTag.releaseTag)' + + # Rebuild branches should be treated as preview builds + # NOTE: The following regex is duplicated from rebuild-branch-check.yml. + # This duplication is necessary because channelSelection.yml does not call rebuild-branch-check.yml, + # and is used in contexts where that check may not have run. + # If you update this regex, also update it in rebuild-branch-check.yml to keep them in sync. + $isRebuildBranch = '$(Build.SourceBranch)' -match 'refs/heads/rebuild/.*-rebuild\.' + $LTS = $metadata.LTSRelease.Latest $Stable = $metadata.StableRelease.Latest - $isPreview = '$(OutputReleaseTag.releaseTag)' -match '-' + $isPreview = $releaseTag -match '-' - $IsLTS = [bool]$LTS - $IsStable = [bool]$Stable - $IsPreview = [bool]$isPreview + # If this is a rebuild branch, force preview mode and ignore LTS metadata + if ($isRebuildBranch) { + $IsLTS = $false + $IsStable = $false + $IsPreview = $true + Write-Verbose -Message "Rebuild branch detected, forcing Preview channel" -Verbose + } + else { + $IsLTS = [bool]$LTS + $IsStable = [bool]$Stable + $IsPreview = [bool]$isPreview + } $channelVars = @{ IsLTS = $IsLTS diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index 8354c60feae..dad43a05885 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -62,6 +62,8 @@ jobs: parameters: nativePathRoot: '$(Agent.TempDirectory)' + - template: rebuild-branch-check.yml@self + - download: CoOrdinatedBuildPipeline artifact: ${{ parameters.unsignedDrop }} displayName: 'Download unsigned artifacts' @@ -139,7 +141,21 @@ jobs: } $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package + + Write-Verbose -Verbose "metadata:" + $metadata | Out-String | Write-Verbose -Verbose + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't build LTS packages for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, skipping LTS package build" -Verbose + } + + Write-Verbose -Verbose "LTS: $LTS" if ($LTS) { Write-Verbose -Message "LTS Release: $LTS" diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 1bd19e09d98..ce53c70b066 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -60,6 +60,8 @@ jobs: parameters: nativePathRoot: '$(Agent.TempDirectory)' + - template: rebuild-branch-check.yml@self + - download: CoOrdinatedBuildPipeline artifact: macosBinResults-${{ parameters.buildArchitecture }} @@ -103,7 +105,21 @@ jobs: Get-PSOptions | Write-Verbose -Verbose $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package + + Write-Verbose -Verbose "metadata:" + $metadata | Out-String | Write-Verbose -Verbose + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't build LTS packages for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, skipping LTS package build" -Verbose + } + + Write-Verbose -Verbose "LTS: $LTS" if ($LTS) { Write-Verbose -Message "LTS Release: $LTS" diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 1df89e2de07..cd17be2176e 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -1,3 +1,8 @@ +parameters: + - name: OfficialBuild + type: boolean + default: false + jobs: - job: CreateMSIXBundle displayName: Create .msixbundle file @@ -45,7 +50,7 @@ jobs: **/*.msix targetPath: '$(Build.ArtifactStagingDirectory)/downloads' displayName: Download windows x86 packages - + # Finds the makeappx tool on the machine with image: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - pwsh: | $cmd = Get-Command makeappx.exe -ErrorAction Ignore @@ -95,12 +100,13 @@ jobs: - task: onebranch.pipeline.signing@1 displayName: Sign MsixBundle + condition: eq('${{ parameters.OfficialBuild }}', 'true') inputs: command: 'sign' signing_profile: $(MSIXProfile) files_to_sign: '**/*.msixbundle' search_root: '$(BundleDir)' - + - pwsh: | $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File Write-Verbose -Verbose "Signed bundle: $signedBundle" @@ -124,12 +130,12 @@ jobs: Get-ChildItem -Path $(System.DefaultWorkingDirectory) -Recurse | Select-Object -ExpandProperty FullName Test-Path -Path '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP-Private.xml' | Write-Verbose -Verbose displayName: Output Pipeline.Workspace and System.DefaultWorkingDirectory - + - template: channelSelection.yml@self - pwsh: | $IsLTS = '$(ChannelSelection.IsLTS)' -eq 'true' - $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' + $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' $IsPreview = '$(ChannelSelection.IsPreview)' -eq 'true' Write-Verbose -Verbose "Channel Selection - LTS: $IsLTS, Stable: $IsStable, Preview: $IsPreview" @@ -156,11 +162,11 @@ jobs: $currentChannel = if ($IsLTS) { 'LTS' } elseif ($IsStable) { 'Stable' } elseif ($IsPreview) { 'Preview' } - else { + else { Write-Error "No valid channel detected" exit 1 } - + $config = $channelConfigs[$currentChannel] Write-Verbose -Verbose "Selected channel: $currentChannel" Write-Verbose -Verbose "App Store Name: $($config.AppStoreName)" @@ -209,12 +215,30 @@ jobs: Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" # These variables are used in the next tasks to determine which ServiceEndpoint to use - Write-Host "##vso[task.setvariable variable=LTS]$($IsLTS.ToString().ToLower())" - Write-Host "##vso[task.setvariable variable=STABLE]$($IsStable.ToString().ToLower())" - Write-Host "##vso[task.setvariable variable=PREVIEW]$($IsPreview.ToString().ToLower())" + $ltsValue = $IsLTS.ToString().ToLower() + $stableValue = $IsStable.ToString().ToLower() + $previewValue = $IsPreview.ToString().ToLower() + + Write-Verbose -Verbose "About to set variables:" + Write-Verbose -Verbose " LTS=$ltsValue" + Write-Verbose -Verbose " STABLE=$stableValue" + Write-Verbose -Verbose " PREVIEW=$previewValue" + + Write-Host "##vso[task.setvariable variable=LTS]$ltsValue" + Write-Host "##vso[task.setvariable variable=STABLE]$stableValue" + Write-Host "##vso[task.setvariable variable=PREVIEW]$previewValue" + + Write-Verbose -Verbose "Variables set successfully" name: UpdateConfigs displayName: Update PDPs and SBConfig.json + - pwsh: | + Write-Verbose -Verbose "Checking variables after UpdateConfigs:" + Write-Verbose -Verbose "LTS=$(LTS)" + Write-Verbose -Verbose "STABLE=$(STABLE)" + Write-Verbose -Verbose "PREVIEW=$(PREVIEW)" + displayName: Debug - Check Variables + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package (Preview)' condition: eq('$(PREVIEW)', 'true') @@ -243,14 +267,14 @@ jobs: $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" $jsonFile = "$submissionPackageDir/PowerShellStorePackage.json" $zipFile = "$submissionPackageDir/PowerShellStorePackage.zip" - + if ((Test-Path $jsonFile) -and (Test-Path $zipFile)) { Write-Verbose -Verbose "Uploading StoreBroker Package files:" Write-Verbose -Verbose "JSON File: $jsonFile" Write-Verbose -Verbose "ZIP File: $zipFile" Copy-Item -Path $submissionPackageDir -Destination "$(ob_outputDirectory)" -Verbose -Recurse - } + } else { Write-Error "Required files not found in $submissionPackageDir" diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 9a8be4b18fe..83cdf730b53 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -60,6 +60,8 @@ jobs: nativePathRoot: '$(Agent.TempDirectory)' ob_restore_phase: false + - template: rebuild-branch-check.yml@self + - download: CoOrdinatedBuildPipeline artifact: drop_windows_build_windows_${{ parameters.runtime }}_release displayName: Download signed artifacts @@ -127,7 +129,21 @@ jobs: Get-PSOptions | Write-Verbose -Verbose $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package + + Write-Verbose -Verbose "metadata:" + $metadata | Out-String | Write-Verbose -Verbose + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't build LTS packages for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, skipping LTS package build" -Verbose + } + + Write-Verbose -Verbose "LTS: $LTS" if ($LTS) { Write-Verbose -Message "LTS Release: $LTS" diff --git a/.pipelines/templates/rebuild-branch-check.yml b/.pipelines/templates/rebuild-branch-check.yml new file mode 100644 index 00000000000..a4b546a0dc6 --- /dev/null +++ b/.pipelines/templates/rebuild-branch-check.yml @@ -0,0 +1,17 @@ +# This template checks if the current branch is a rebuild branch +# and sets an output variable IsRebuildBranch that can be used by other templates +steps: +- pwsh: | + # Check if this is a rebuild branch (e.g., rebuild/v7.4.13-rebuild.5) + $isRebuildBranch = '$(Build.SourceBranch)' -match 'refs/heads/rebuild/.*-rebuild\.' + + $value = if ($isRebuildBranch) { 'true' } else { 'false' } + Write-Verbose -Message "IsRebuildBranch: $value" -Verbose + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected: $(Build.SourceBranch)" -Verbose + } + + Write-Host "##vso[task.setvariable variable=IsRebuildBranch;isOutput=true]$value" + name: RebuildBranchCheck + displayName: Check if Rebuild Branch From 2c5fdfb30ef7694da916ea8d9fc2eb016c8fa4ca Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 15:24:41 -0800 Subject: [PATCH 198/275] [release/v7.5] Fix merge conflict checker for empty file lists and filter *.cs files (#26813) --- .../merge-conflict-checker/README.md | 2 + .../merge-conflict-checker/action.yml | 3 +- test/infrastructure/ciModule.Tests.ps1 | 14 ++-- tools/ci.psm1 | 72 ++++++++++++++++--- 4 files changed, 77 insertions(+), 14 deletions(-) diff --git a/.github/actions/infrastructure/merge-conflict-checker/README.md b/.github/actions/infrastructure/merge-conflict-checker/README.md index aeae4a29b93..b53d6f99964 100644 --- a/.github/actions/infrastructure/merge-conflict-checker/README.md +++ b/.github/actions/infrastructure/merge-conflict-checker/README.md @@ -56,8 +56,10 @@ jobs: - **File Handling**: - Checks only files that were added, modified, or renamed - Skips deleted files + - **Filters out `*.cs` files** (C# files are excluded from merge conflict checking) - Skips binary/unreadable files - Skips directories +- **Empty File List**: Gracefully handles cases where no files need checking (e.g., PRs that only delete files) ## Example Output diff --git a/.github/actions/infrastructure/merge-conflict-checker/action.yml b/.github/actions/infrastructure/merge-conflict-checker/action.yml index a86cfa5470a..41c7d2ad941 100644 --- a/.github/actions/infrastructure/merge-conflict-checker/action.yml +++ b/.github/actions/infrastructure/merge-conflict-checker/action.yml @@ -25,7 +25,8 @@ runs: run: | # Get changed files from environment variable (secure against injection) $changedFilesJson = $env:CHANGED_FILES_JSON - $changedFiles = $changedFilesJson | ConvertFrom-Json + # Ensure we always have an array (ConvertFrom-Json returns null for empty JSON arrays) + $changedFiles = @($changedFilesJson | ConvertFrom-Json) # Import ci.psm1 and run the check Import-Module "$env:GITHUB_WORKSPACE/tools/ci.psm1" -Force diff --git a/test/infrastructure/ciModule.Tests.ps1 b/test/infrastructure/ciModule.Tests.ps1 index f88d5787fc9..b7320ff49b7 100644 --- a/test/infrastructure/ciModule.Tests.ps1 +++ b/test/infrastructure/ciModule.Tests.ps1 @@ -30,11 +30,17 @@ Describe "Test-MergeConflictMarker" { } Context "When no files are provided" { - It "Should handle empty file array" { - # The function parameter has Mandatory validation which rejects empty arrays by design - # This test verifies that behavior + It "Should handle empty file array gracefully" { + # The function now accepts empty arrays to handle cases like delete-only PRs $emptyArray = @() - { Test-MergeConflictMarker -File $emptyArray -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw -ExpectedMessage "*empty array*" + Test-MergeConflictMarker -File $emptyArray -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=0" + $outputs | Should -Contain "conflicts-found=0" + + $summary = Get-Content $script:testSummaryPath -Raw + $summary | Should -Match "No Files to Check" } } diff --git a/tools/ci.psm1 b/tools/ci.psm1 index bcc816cc918..07839996d27 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -932,12 +932,12 @@ function New-LinuxPackage } else { "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" } - + # Ensure artifacts directory exists if (-not (Test-Path $artifactsDir)) { New-Item -ItemType Directory -Path $artifactsDir -Force | Out-Null } - + Write-Log -message "Artifacts directory: $artifactsDir" Copy-Item $packageObj.FullName -Destination $artifactsDir -Force } @@ -950,7 +950,7 @@ function New-LinuxPackage } else { "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" } - + # Create and package Raspbian .tgz # Build must be clean for Raspbian Start-PSBuild -PSModuleRestore -Clean -Runtime linux-arm -Configuration 'Release' @@ -1039,8 +1039,9 @@ Function Test-MergeConflictMarker #> [CmdletBinding()] param( - [Parameter(Mandatory)] - [string[]] $File, + [Parameter()] + [AllowEmptyCollection()] + [string[]] $File = @(), [Parameter()] [string] $WorkspacePath = $PWD, @@ -1054,10 +1055,63 @@ Function Test-MergeConflictMarker Write-Host "Starting merge conflict marker check..." -ForegroundColor Cyan - Write-Host "Checking $($File.Count) changed files for merge conflict markers" -ForegroundColor Cyan + # Helper function to write outputs when no files to check + function Write-NoFilesOutput { + param( + [string]$Message, + [string]$OutputPath, + [string]$SummaryPath + ) + + # Output results to GitHub Actions + if ($OutputPath) { + "files-checked=0" | Out-File -FilePath $OutputPath -Append -Encoding utf8 + "conflicts-found=0" | Out-File -FilePath $OutputPath -Append -Encoding utf8 + } + + # Create GitHub Actions job summary + if ($SummaryPath) { + $summaryContent = @" +# Merge Conflict Marker Check Results + +## Summary +- **Files Checked:** 0 +- **Files with Conflicts:** 0 + +## ℹ️ No Files to Check + +$Message + +"@ + $summaryContent | Out-File -FilePath $SummaryPath -Encoding utf8 + } + } + + # Handle empty file list (e.g., when PR only deletes files) + if ($File.Count -eq 0) { + Write-Host "No files to check (empty file list)" -ForegroundColor Yellow + Write-NoFilesOutput -Message "No files were provided for checking (this can happen when a PR only deletes files)." -OutputPath $OutputPath -SummaryPath $SummaryPath + return + } + + # Filter out *.cs files from merge conflict checking + $filesToCheck = @($File | Where-Object { $_ -notlike "*.cs" }) + $filteredCount = $File.Count - $filesToCheck.Count + + if ($filteredCount -gt 0) { + Write-Host "Filtered out $filteredCount *.cs file(s) from merge conflict checking" -ForegroundColor Yellow + } + + if ($filesToCheck.Count -eq 0) { + Write-Host "No files to check after filtering (all files were *.cs)" -ForegroundColor Yellow + Write-NoFilesOutput -Message "All $filteredCount file(s) were filtered out (*.cs files are excluded from merge conflict checking)." -OutputPath $OutputPath -SummaryPath $SummaryPath + return + } + + Write-Host "Checking $($filesToCheck.Count) changed files for merge conflict markers" -ForegroundColor Cyan # Convert relative paths to absolute paths for processing - $absolutePaths = $File | ForEach-Object { + $absolutePaths = $filesToCheck | ForEach-Object { if ([System.IO.Path]::IsPathRooted($_)) { $_ } else { @@ -1081,14 +1135,14 @@ Function Test-MergeConflictMarker } $filesChecked++ - + # Get relative path for display $relativePath = if ($WorkspacePath -and $filePath.StartsWith($WorkspacePath)) { $filePath.Substring($WorkspacePath.Length).TrimStart([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar) } else { $filePath } - + Write-Host " Checking: $relativePath" -ForegroundColor Gray # Search for conflict markers using Select-String From 953cd3a1073fc1c608326e192060f52dca24cbf5 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 16:23:29 -0800 Subject: [PATCH 199/275] [release/v7.5] Fix template path for rebuild branch check in package.yml (#26818) --- .github/workflows/linux-ci.yml | 1 - .github/workflows/macos-ci.yml | 20 ++++++++++--------- .../templates/packaging/windows/package.yml | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index b92b58fea5f..773f565c601 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -233,7 +233,6 @@ jobs: - linux_test_elevated_others - linux_test_unelevated_ci - linux_test_unelevated_others - - analyze - linux_packaging - merge_conflict_check - infrastructure_tests diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 89f3b7811d6..e359623bbeb 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -10,6 +10,8 @@ on: - github-mirror paths: - "**" + - "*" + - ".globalconfig" - "!.github/ISSUE_TEMPLATE/**" - "!.dependabot/config.yml" - "!.pipelines/**" @@ -23,12 +25,12 @@ on: # Path filters for PRs need to go into the changes job concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} cancel-in-progress: ${{ contains(github.ref, 'merge')}} env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: 1 FORCE_FEATURE: 'False' FORCE_PACKAGE: 'False' HOMEBREW_NO_ANALYTICS: 1 @@ -54,7 +56,7 @@ jobs: buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v5 - name: Change Detection id: filter @@ -69,7 +71,7 @@ jobs: if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Build @@ -83,7 +85,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: macOS Unelevated CI @@ -100,7 +102,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: macOS Elevated CI @@ -117,7 +119,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: macOS Unelevated Others @@ -134,7 +136,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: macOS Elevated Others @@ -167,7 +169,7 @@ jobs: - uses: actions/setup-dotnet@v4 with: global-json-file: ./global.json - + - name: Bootstrap packaging if: success() run: |- import-module ./build.psm1 diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 83cdf730b53..03673d61c7b 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -60,7 +60,7 @@ jobs: nativePathRoot: '$(Agent.TempDirectory)' ob_restore_phase: false - - template: rebuild-branch-check.yml@self + - template: /.pipelines/templates/rebuild-branch-check.yml@self - download: CoOrdinatedBuildPipeline artifact: drop_windows_build_windows_${{ parameters.runtime }}_release From d0a41f8127229a89bad3cda9f8f0e1decd287755 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 16:24:09 -0800 Subject: [PATCH 200/275] [release/v7.5] Fix condition syntax for StoreBroker package tasks in MSIX pipeline (#26819) --- ...onebranch-condition-syntax.instructions.md | 223 ++++++++++++++++++ .pipelines/templates/package-create-msix.yml | 4 +- 2 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 .github/instructions/onebranch-condition-syntax.instructions.md diff --git a/.github/instructions/onebranch-condition-syntax.instructions.md b/.github/instructions/onebranch-condition-syntax.instructions.md new file mode 100644 index 00000000000..19bf331d9c3 --- /dev/null +++ b/.github/instructions/onebranch-condition-syntax.instructions.md @@ -0,0 +1,223 @@ +--- +applyTo: ".pipelines/**/*.{yml,yaml}" +--- + +# OneBranch Pipeline Condition Syntax + +## Overview +Azure Pipelines (OneBranch) uses specific syntax for referencing variables and parameters in condition expressions. Using the wrong syntax will cause conditions to fail silently or behave unexpectedly. + +## Variable Reference Patterns + +### In Condition Expressions + +**✅ Correct Pattern:** +```yaml +condition: eq(variables['VariableName'], 'value') +condition: or(eq(variables['VAR1'], 'true'), eq(variables['VAR2'], 'true')) +condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) +``` + +**❌ Incorrect Patterns:** +```yaml +# Don't use $(VAR) string expansion in conditions +condition: eq('$(VariableName)', 'value') + +# Don't use direct variable references +condition: eq($VariableName, 'value') +``` + +### In Script Content (pwsh, bash, etc.) + +**✅ Correct Pattern:** +```yaml +- pwsh: | + $value = '$(VariableName)' + Write-Host "Value: $(VariableName)" +``` + +### In Input Fields + +**✅ Correct Pattern:** +```yaml +inputs: + serviceEndpoint: '$(ServiceEndpoint)' + sbConfigPath: '$(SBConfigPath)' +``` + +## Parameter References + +### Template Parameters (Compile-Time) + +**✅ Correct Pattern:** +```yaml +parameters: + - name: OfficialBuild + type: boolean + default: false + +steps: + - task: SomeTask@1 + condition: eq('${{ parameters.OfficialBuild }}', 'true') +``` + +Note: Parameters use `${{ parameters.Name }}` because they're evaluated at template compile-time. + +### Runtime Variables (Execution-Time) + +**✅ Correct Pattern:** +```yaml +steps: + - pwsh: | + Write-Host "##vso[task.setvariable variable=MyVar]somevalue" + displayName: Set Variable + + - task: SomeTask@1 + condition: eq(variables['MyVar'], 'somevalue') +``` + +## Common Scenarios + +### Scenario 1: Check if Variable Equals Value + +```yaml +- task: DoSomething@1 + condition: eq(variables['PREVIEW'], 'true') +``` + +### Scenario 2: Multiple Variable Conditions (OR) + +```yaml +- task: DoSomething@1 + condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) +``` + +### Scenario 3: Multiple Variable Conditions (AND) + +```yaml +- task: DoSomething@1 + condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) +``` + +### Scenario 4: Complex Conditions + +```yaml +- task: DoSomething@1 + condition: and( + succeededOrFailed(), + ne(variables['UseAzDevOpsFeed'], ''), + eq(variables['Build.SourceBranch'], 'refs/heads/master') + ) +``` + +### Scenario 5: Built-in Variables + +```yaml +- task: CodeQL3000Init@0 + condition: eq(variables['Build.SourceBranch'], 'refs/heads/master') + +- step: finalize + condition: eq(variables['Agent.JobStatus'], 'SucceededWithIssues') +``` + +### Scenario 6: Parameter vs Variable + +```yaml +parameters: + - name: OfficialBuild + type: boolean + +steps: + # Parameter condition (compile-time) + - task: SignFiles@1 + condition: eq('${{ parameters.OfficialBuild }}', 'true') + + # Variable condition (runtime) + - task: PublishArtifact@1 + condition: eq(variables['PUBLISH_ENABLED'], 'true') +``` + +## Why This Matters + +**String Expansion `$(VAR)` in Conditions:** +- When you use `'$(VAR)'` in a condition, Azure Pipelines attempts to expand it as a string +- If the variable is undefined or empty, it becomes an empty string `''` +- The condition `eq('', 'true')` will always be false +- This makes debugging difficult because there's no error message + +**Variables Array Syntax `variables['VAR']`:** +- This is the proper way to reference runtime variables in conditions +- Azure Pipelines correctly evaluates the variable's value +- Undefined variables are handled properly by the condition evaluator +- This is the standard pattern used throughout Azure Pipelines + +## Reference Examples + +Working examples can be found in: +- `.pipelines/templates/linux.yml` - Build.SourceBranch conditions +- `.pipelines/templates/windows-hosted-build.yml` - Architecture conditions +- `.pipelines/templates/compliance/apiscan.yml` - CODEQL_ENABLED conditions +- `.pipelines/templates/insert-nuget-config-azfeed.yml` - Complex AND/OR conditions + +## Quick Reference Table + +| Context | Syntax | Example | +|---------|--------|---------| +| Condition expression | `variables['Name']` | `condition: eq(variables['PREVIEW'], 'true')` | +| Script content | `$(Name)` | `pwsh: Write-Host "$(PREVIEW)"` | +| Task input | `$(Name)` | `inputs: path: '$(Build.SourcesDirectory)'` | +| Template parameter | `${{ parameters.Name }}` | `condition: eq('${{ parameters.Official }}', 'true')` | + +## Troubleshooting + +### Condition Always False +If your condition is always evaluating to false: +1. Check if you're using `'$(VAR)'` instead of `variables['VAR']` +2. Verify the variable is actually set (add a debug step to print the variable) +3. Check the variable value is exactly what you expect (case-sensitive) + +### Variable Not Found +If you get errors about variables not being found: +1. Ensure the variable is set before the condition is evaluated +2. Check that the variable name is spelled correctly +3. Verify the variable is in scope (job vs. stage vs. pipeline level) + +## Best Practices + +1. **Always use `variables['Name']` in conditions** - This is the correct Azure Pipelines pattern +2. **Use `$(Name)` for string expansion** in scripts and inputs +3. **Use `${{ parameters.Name }}` for template parameters** (compile-time) +4. **Add debug steps** to verify variable values when troubleshooting conditions +5. **Follow existing patterns** in the repository - grep for `condition:` to see examples + +## Common Mistakes + +❌ **Mistake 1: String expansion in condition** +```yaml +condition: eq('$(PREVIEW)', 'true') # WRONG +``` + +✅ **Fix:** +```yaml +condition: eq(variables['PREVIEW'], 'true') # CORRECT +``` + +❌ **Mistake 2: Missing quotes around parameter** +```yaml +condition: eq(${{ parameters.Official }}, true) # WRONG +``` + +✅ **Fix:** +```yaml +condition: eq('${{ parameters.Official }}', 'true') # CORRECT +``` + +❌ **Mistake 3: Mixing syntax** +```yaml +condition: or(eq('$(STABLE)', 'true'), eq(variables['LTS'], 'true')) # INCONSISTENT +``` + +✅ **Fix:** +```yaml +condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) # CORRECT +``` diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index cd17be2176e..3448faaec51 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -241,7 +241,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package (Preview)' - condition: eq('$(PREVIEW)', 'true') + condition: eq(variables['PREVIEW'], 'true') inputs: serviceEndpoint: 'StoreAppPublish-Preview' sbConfigPath: '$(SBConfigPath)' @@ -253,7 +253,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package (Stable/LTS)' - condition: or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true')) + condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) inputs: serviceEndpoint: 'StoreAppPublish-Stable' sbConfigPath: '$(SBConfigPath)' From c4ec0f4892eef9d1385cf5dd2bccd45a55be5b96 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 16:25:05 -0800 Subject: [PATCH 201/275] [release/v7.5] Update the macos package name for preview releases to match the previous pattern (#26820) --- .../templates/release-validate-packagenames.yml | 2 +- test/packaging/macos/package-validation.tests.ps1 | 11 ++++++----- tools/packaging/packaging.psm1 | 9 +++------ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.pipelines/templates/release-validate-packagenames.yml b/.pipelines/templates/release-validate-packagenames.yml index dbbd5c9f742..c5702775c2a 100644 --- a/.pipelines/templates/release-validate-packagenames.yml +++ b/.pipelines/templates/release-validate-packagenames.yml @@ -82,7 +82,7 @@ jobs: - pwsh: | $message = @() Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.pkg | ForEach-Object { - if($_.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?osx(\.10\.12)?\-(x64|arm64)\.pkg') + if($_.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?osx\-(x64|arm64)\.pkg') { $messageInstance = "$($_.Name) is not a valid package name" $message += $messageInstance diff --git a/test/packaging/macos/package-validation.tests.ps1 b/test/packaging/macos/package-validation.tests.ps1 index 02b09fbb078..945ffea6f7a 100644 --- a/test/packaging/macos/package-validation.tests.ps1 +++ b/test/packaging/macos/package-validation.tests.ps1 @@ -82,12 +82,13 @@ Describe "Verify macOS Package" { $script:package | Should -Not -BeNullOrEmpty # Regex pattern for valid macOS PKG package names. + # This pattern matches the validation used in release-validate-packagenames.yml # Valid examples: - # - powershell-7.4.13-osx-x64.pkg (Intel x64 - note: x64 with hyphens for compatibility) - # - powershell-7.4.13-osx-arm64.pkg (Apple Silicon) - # - powershell-preview-7.6.0-preview.6-osx-x64.pkg - # - powershell-lts-7.4.13-osx-arm64.pkg - $pkgPackageNamePattern = '^powershell(-preview|-lts)?-\d+\.\d+\.\d+(-[a-z]+\.\d+)?-osx-(x64|arm64)\.pkg$' + # - powershell-7.4.13-osx-x64.pkg (Stable release) + # - powershell-7.6.0-preview.6-osx-x64.pkg (Preview version string) + # - powershell-7.4.13-rebuild.5-osx-arm64.pkg (Rebuild version) + # - powershell-lts-7.4.13-osx-arm64.pkg (LTS package) + $pkgPackageNamePattern = '^powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?osx\-(x64|arm64)\.pkg$' $script:package.Name | Should -Match $pkgPackageNamePattern -Because "Package name should follow the standard naming convention" } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 4f397ad10b4..61e47ae9b06 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1147,15 +1147,12 @@ function New-UnixPackage { } # Determine if the version is a preview version - $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS - - # Preview versions have preview in the name + # Only LTS packages get a prefix in the name + # Preview versions are identified by the version string itself (e.g., 7.6.0-preview.6) + # Rebuild versions are also identified by the version string (e.g., 7.4.13-rebuild.5) $Name = if($LTS) { "powershell-lts" } - elseif ($IsPreview) { - "powershell-preview" - } else { "powershell" } From 9e508973f7c7fbb35ea5731c3f414d7441cfe4bf Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 16:28:12 -0800 Subject: [PATCH 202/275] [release/v7.5] Mirror .NET/runtime ICU version range in PowerShell (#26821) --- tools/packaging/packaging.psm1 | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 61e47ae9b06..05ce0ff7152 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -2113,6 +2113,22 @@ function Get-PackageDependencies # These should match those in the Dockerfiles, but exclude tools like Git, which, and curl $Dependencies = @() + + # ICU version range follows .NET runtime policy. + # See: https://github.com/dotnet/runtime/blob/3fe8518d51bbcaa179bbe275b2597fbe1b88bc5a/src/native/libs/System.Globalization.Native/pal_icushim.c#L235-L243 + # + # Version range rationale: + # - The runtime supports ICU versions >= the version it was built against + # and <= that version + 30, to allow sufficient headroom for future releases. + # - ICU typically releases about twice per year, so +30 provides roughly + # 15 years of forward compatibility. + # - On some platforms, the minimum supported version may be lower + # than the build version and we know that older versions just works. + # + $MinICUVersion = 60 # runtime minimum supported + $BuildICUVersion = 76 # current build version + $MaxICUVersion = $BuildICUVersion + 30 # headroom + if ($Distribution -eq 'deb') { $Dependencies = @( "libc6", @@ -2120,10 +2136,9 @@ function Get-PackageDependencies "libgssapi-krb5-2", "libstdc++6", "zlib1g", - "libicu76|libicu74|libicu72|libicu71|libicu70|libicu69|libicu68|libicu67|libicu66|libicu65|libicu63|libicu60|libicu57|libicu55|libicu52", + (($MaxICUVersion..$MinICUVersion).ForEach{ "libicu$_" } -join '|'), "libssl3|libssl1.1|libssl1.0.2|libssl1.0.0" ) - } elseif ($Distribution -eq 'rh') { $Dependencies = @( "openssl-libs", From f9e3b97d542def09acf15d15349d307114fcad75 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 16:29:37 -0800 Subject: [PATCH 203/275] [release/v7.5] Close pipe client handles after creating the child ssh process (#26822) --- .../remoting/common/RunspaceConnectionInfo.cs | 34 +++++++++---------- .../fanin/OutOfProcTransportManager.cs | 8 ++--- .../Remoting/SSHRemotingCmdlets.Tests.ps1 | 21 ++++++++++++ 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index d9a6d0b317b..0c99f90fa7e 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -2211,11 +2211,11 @@ internal int StartSSHProcess( CommandTypes.Application, SearchResolutionOptions.None, CommandOrigin.Internal, - context) as ApplicationInfo; + context); - if (cmdInfo != null) + if (cmdInfo is ApplicationInfo appInfo) { - filePath = cmdInfo.Path; + filePath = appInfo.Path; } } else @@ -2273,13 +2273,13 @@ internal int StartSSHProcess( // Subsystem powershell /usr/local/bin/pwsh -SSHServerMode -NoLogo -NoProfile // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified, so any file executed in the runspace would be in the user's local system/process or a system they have access to in which case restricted remoting security guidelines should be used. - System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(filePath); + ProcessStartInfo startInfo = new(filePath); // pass "-i identity_file" command line argument to ssh if KeyFilePath is set // if KeyFilePath is not set, then ssh will use IdentityFile / IdentityAgent from ssh_config if defined else none by default if (!string.IsNullOrEmpty(this.KeyFilePath)) { - if (!System.IO.File.Exists(this.KeyFilePath)) + if (!File.Exists(this.KeyFilePath)) { throw new FileNotFoundException( StringUtil.Format(RemotingErrorIdStrings.KeyFileNotFound, this.KeyFilePath)); @@ -2326,7 +2326,7 @@ internal int StartSSHProcess( // note that ssh expects IPv6 addresses to not be enclosed in square brackets so trim them if present startInfo.ArgumentList.Add(string.Create(CultureInfo.InvariantCulture, $@"-s {this.ComputerName.TrimStart('[').TrimEnd(']')} {this.Subsystem}")); - startInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(filePath); + startInfo.WorkingDirectory = Path.GetDirectoryName(filePath); startInfo.CreateNoWindow = true; startInfo.UseShellExecute = false; @@ -2580,7 +2580,7 @@ private static unsafe void AllocNullTerminatedArray(string[] arr, ref byte** arr // Allocate the unmanaged array to hold each string pointer. // It needs to have an extra element to null terminate the array. arrPtr = (byte**)Marshal.AllocHGlobal(sizeof(IntPtr) * arrLength); - System.Diagnostics.Debug.Assert(arrPtr != null, "Invalid array ptr"); + Debug.Assert(arrPtr != null, "Invalid array ptr"); // Zero the memory so that if any of the individual string allocations fails, // we can loop through the array to free any that succeeded. @@ -2597,7 +2597,7 @@ private static unsafe void AllocNullTerminatedArray(string[] arr, ref byte** arr byte[] byteArr = System.Text.Encoding.UTF8.GetBytes(arr[i]); arrPtr[i] = (byte*)Marshal.AllocHGlobal(byteArr.Length + 1); // +1 for null termination - System.Diagnostics.Debug.Assert(arrPtr[i] != null, "Invalid array ptr"); + Debug.Assert(arrPtr[i] != null, "Invalid array ptr"); Marshal.Copy(byteArr, 0, (IntPtr)arrPtr[i], byteArr.Length); // copy over the data from the managed byte array arrPtr[i][byteArr.Length] = (byte)'\0'; // null terminate @@ -2641,13 +2641,13 @@ internal static extern unsafe int ForkAndExecProcess( /// P-Invoking native APIs. ///
private static int StartSSHProcessImpl( - System.Diagnostics.ProcessStartInfo startInfo, + ProcessStartInfo startInfo, out StreamWriter stdInWriterVar, out StreamReader stdOutReaderVar, out StreamReader stdErrReaderVar) { Exception ex = null; - System.Diagnostics.Process sshProcess = null; + Process sshProcess = null; // // These std pipe handles are bound to managed Reader/Writer objects and returned to the transport // manager object, which uses them for PSRP communication. The lifetime of these handles are then @@ -2668,7 +2668,7 @@ private static int StartSSHProcessImpl( catch (InvalidOperationException e) { ex = e; } catch (ArgumentException e) { ex = e; } catch (FileNotFoundException e) { ex = e; } - catch (System.ComponentModel.Win32Exception e) { ex = e; } + catch (Win32Exception e) { ex = e; } if ((ex != null) || (sshProcess == null) || @@ -2693,9 +2693,9 @@ private static int StartSSHProcessImpl( { if (stdInWriterVar != null) { stdInWriterVar.Dispose(); } else { stdInPipeServer.Dispose(); } - if (stdOutReaderVar != null) { stdInWriterVar.Dispose(); } else { stdOutPipeServer.Dispose(); } + if (stdOutReaderVar != null) { stdOutReaderVar.Dispose(); } else { stdOutPipeServer.Dispose(); } - if (stdErrReaderVar != null) { stdInWriterVar.Dispose(); } else { stdErrPipeServer.Dispose(); } + if (stdErrReaderVar != null) { stdErrReaderVar.Dispose(); } else { stdErrPipeServer.Dispose(); } throw; } @@ -2705,7 +2705,7 @@ private static int StartSSHProcessImpl( private static void KillSSHProcessImpl(int pid) { - using (var sshProcess = System.Diagnostics.Process.GetProcessById(pid)) + using (var sshProcess = Process.GetProcessById(pid)) { if ((sshProcess != null) && (sshProcess.Handle != IntPtr.Zero) && !sshProcess.HasExited) { @@ -2736,7 +2736,7 @@ private static Process CreateProcessWithRedirectedStd( SafeFileHandle stdInPipeClient = null; SafeFileHandle stdOutPipeClient = null; SafeFileHandle stdErrPipeClient = null; - string randomName = System.IO.Path.GetFileNameWithoutExtension(System.IO.Path.GetRandomFileName()); + string randomName = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); try { @@ -2829,16 +2829,14 @@ private static Process CreateProcessWithRedirectedStd( catch (Exception) { stdInPipeServer?.Dispose(); - stdInPipeClient?.Dispose(); stdOutPipeServer?.Dispose(); - stdOutPipeClient?.Dispose(); stdErrPipeServer?.Dispose(); - stdErrPipeClient?.Dispose(); throw; } finally { + lpStartupInfo.Dispose(); lpProcessInformation.Dispose(); } } diff --git a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs index d9532c8691a..47ff6270dba 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs @@ -1733,7 +1733,7 @@ public override void CreateAsync() bool sshTerminated = false; try { - using (var sshProcess = System.Diagnostics.Process.GetProcessById(_sshProcessId)) + using (var sshProcess = Process.GetProcessById(_sshProcessId)) { sshTerminated = sshProcess == null || sshProcess.Handle == IntPtr.Zero || sshProcess.HasExited; } @@ -1847,7 +1847,7 @@ private void ProcessErrorThread(object state) // Messages in error stream from ssh are unreliable, and may just be warnings or // banner text. // So just report the messages but don't act on them. - System.Console.WriteLine(error); + Console.WriteLine(error); } catch (IOException) { } @@ -1907,10 +1907,10 @@ private void ProcessReaderThread(object state) break; } - if (data.StartsWith(System.Management.Automation.Remoting.Server.FormattedErrorTextWriter.ErrorPrefix, StringComparison.OrdinalIgnoreCase)) + if (data.StartsWith(OutOfProcessTextWriter.ErrorPrefix, StringComparison.OrdinalIgnoreCase)) { // Error message from the server. - string errorData = data.Substring(System.Management.Automation.Remoting.Server.FormattedErrorTextWriter.ErrorPrefix.Length); + string errorData = data.Substring(OutOfProcessTextWriter.ErrorPrefix.Length); HandleErrorDataReceived(errorData); } else diff --git a/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 b/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 index 1568d284d0f..c1090bdc186 100644 --- a/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 +++ b/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 @@ -70,3 +70,24 @@ Describe "SSHConnection parameter hashtable type conversions" -Tags 'Feature', ' $err.FullyQualifiedErrorId | Should -Match 'PSSessionOpenFailed' } } + +Describe "No hangs when host doesn't exist" -Tags "CI" { + $testCases = @( + @{ + Name = 'Verifies no hang for New-PSSession with non-existing host name' + ScriptBlock = { New-PSSession -HostName "test-notexist" -UserName "test" -ErrorAction Stop } + FullyQualifiedErrorId = 'PSSessionOpenFailed' + }, + @{ + Name = 'Verifies no hang for Invoke-Command with non-existing host name' + ScriptBlock = { Invoke-Command -HostName "test-notexist" -UserName "test" -ScriptBlock { 1 } -ErrorAction Stop } + FullyQualifiedErrorId = 'PSSessionStateBroken' + } + ) + + It "" -TestCases $testCases { + param ($ScriptBlock, $FullyQualifiedErrorId) + + $ScriptBlock | Should -Throw -ErrorId $FullyQualifiedErrorId -ExceptionType 'System.Management.Automation.Remoting.PSRemotingTransportException' + } +} From 54b881d10699f6b9574efb4f83743a3bda359a49 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 16:30:06 -0800 Subject: [PATCH 204/275] [release/v7.5] Fix $PSDefaultParameterValues leak causing tests to skip unexpectedly (#26823) --- .../Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 | 3 ++- .../Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 | 3 ++- test/powershell/engine/ETS/CimAdapter.Tests.ps1 | 4 +++- test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 | 2 -- test/powershell/engine/Remoting/SessionOption.Tests.ps1 | 3 ++- test/powershell/engine/Security/FileSignature.Tests.ps1 | 1 + 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 index 82f944612f9..f1937f824a6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 @@ -7,6 +7,7 @@ $DefaultResultValue = 0 try { # set up for testing + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() $PSDefaultParameterValues["it:skip"] = ! $IsWindows Enable-Testhook -testhookName $RenameTesthook # we also set TestStopComputer @@ -73,7 +74,7 @@ try } finally { - $PSDefaultParameterValues.Remove("it:skip") + $global:PSDefaultParameterValues = $originalDefaultParameterValues Disable-Testhook -testhookName $RenameTestHook Disable-Testhook -testhookName TestStopComputer Set-TesthookResult -testhookName $RenameResultName -value 0 diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 index 0e50d7c3603..52938a0b881 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 @@ -3,6 +3,7 @@ Describe "Acl cmdlets are available and operate properly" -Tag CI { Context "Windows ACL test" { BeforeAll { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() $PSDefaultParameterValues["It:Skip"] = -not $IsWindows } @@ -103,7 +104,7 @@ Describe "Acl cmdlets are available and operate properly" -Tag CI { } AfterAll { - $PSDefaultParameterValues.Remove("It:Skip") + $global:PSDefaultParameterValues = $originalDefaultParameterValues } } } diff --git a/test/powershell/engine/ETS/CimAdapter.Tests.ps1 b/test/powershell/engine/ETS/CimAdapter.Tests.ps1 index 1e71bc28b95..3cfff4bd9e4 100644 --- a/test/powershell/engine/ETS/CimAdapter.Tests.ps1 +++ b/test/powershell/engine/ETS/CimAdapter.Tests.ps1 @@ -3,6 +3,8 @@ Describe "CIM Objects are adapted properly" -Tag @("CI") { BeforeAll { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() + function getIndex { param([string[]]$strings,[string]$pattern) @@ -32,7 +34,7 @@ Describe "CIM Objects are adapted properly" -Tag @("CI") { } } AfterAll { - $PSDefaultParameterValues.Remove("it:pending") + $global:PSDefaultParameterValues = $originalDefaultParameterValues } It "Namespace-qualified Win32_Process is present" -Skip:(!$IsWindows) { diff --git a/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 b/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 index a5d49b75005..2093eaa7ce5 100644 --- a/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 +++ b/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 @@ -83,9 +83,7 @@ Describe "JEA session Transcript script test" -Tag @("Feature", 'RequireAdminOnW AfterAll { if ($skipTest) { Pop-DefaultParameterValueStack - return } - Pop-DefaultParameterValueStack } It "Configuration name should be in the transcript header" { diff --git a/test/powershell/engine/Remoting/SessionOption.Tests.ps1 b/test/powershell/engine/Remoting/SessionOption.Tests.ps1 index 1ff51e2a707..e85777e90ba 100644 --- a/test/powershell/engine/Remoting/SessionOption.Tests.ps1 +++ b/test/powershell/engine/Remoting/SessionOption.Tests.ps1 @@ -1,6 +1,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. try { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() if ( ! $IsWindows ) { $PSDefaultParameterValues['it:skip'] = $true } @@ -52,5 +53,5 @@ try { } } finally { - $PSDefaultParameterValues.remove("it:skip") + $global:PSDefaultParameterValues = $originalDefaultParameterValues } diff --git a/test/powershell/engine/Security/FileSignature.Tests.ps1 b/test/powershell/engine/Security/FileSignature.Tests.ps1 index 51194903a94..9dd26f98aed 100644 --- a/test/powershell/engine/Security/FileSignature.Tests.ps1 +++ b/test/powershell/engine/Security/FileSignature.Tests.ps1 @@ -89,6 +89,7 @@ Describe "Windows file content signatures" -Tags @('Feature', 'RequireAdminOnWin AfterAll { if ($shouldSkip) { + Pop-DefaultParameterValueStack return } From 84472833cd1d225b3dec7d84169e69091b9e2cca Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 16:30:30 -0800 Subject: [PATCH 205/275] [release/v7.5] Update `Get-ChangeLog` to handle backport PRs correctly (#26824) --- tools/releaseTools.psm1 | 113 +++++++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 26 deletions(-) diff --git a/tools/releaseTools.psm1 b/tools/releaseTools.psm1 index 6207c4be3f7..f07560d2b45 100644 --- a/tools/releaseTools.psm1 +++ b/tools/releaseTools.psm1 @@ -37,6 +37,7 @@ $Script:powershell_team = @( "dependabot-preview[bot]" "dependabot[bot]" "github-actions[bot]" + "Copilot" "Anam Navied" "Andrew Schwartzmeyer" "Jason Helmick" @@ -46,6 +47,27 @@ $Script:powershell_team = @( "Justin Chung" ) +# The powershell team members GitHub logins. We use them to decide if the original author of a backport PR is from the team. +$script:psteam_logins = @( + 'andyleejordan' + 'TravisEz13' + 'daxian-dbw' + 'adityapatwardhan' + 'SteveL-MSFT' + 'dependabot[bot]' + 'pwshBot' + 'jshigetomi' + 'SeeminglyScience' + 'anamnavi' + 'sdwheeler' + 'Copilot' + 'copilot-swe-agent' + 'app/copilot-swe-agent' + 'StevenBucher98' + 'alerickson' + 'tgauth' +) + # They are very active contributors, so we keep their email-login mappings here to save a few queries to Github. $Script:community_login_map = @{ "darpa@yandex.ru" = "iSazonov" @@ -54,11 +76,6 @@ $Script:community_login_map = @{ "info@powercode-consulting.se" = "powercode" } -# Ignore dependency bumping bot (Dependabot): -$Script:attribution_ignore_list = @( - 'dependabot[bot]@users.noreply.github.com' -) - ############################## #.SYNOPSIS #In the release workflow, the release branch will be merged back to master after the release is done, @@ -262,25 +279,76 @@ function Get-ChangeLog $clExperimental = @() foreach ($commit in $new_commits) { + $commitSubject = $commit.Subject + $prNumber = $commit.PullRequest + Write-Verbose "subject: $commitSubject" Write-Verbose "authorname: $($commit.AuthorName)" - if ($commit.AuthorEmail.EndsWith("@microsoft.com") -or $powershell_team -contains $commit.AuthorName -or $Script:attribution_ignore_list -contains $commit.AuthorEmail) { - $commit.ChangeLogMessage = "- {0}" -f (Get-ChangeLogMessage $commit.Subject) + + try { + $pr = Invoke-RestMethod ` + -Uri "https://api.github.com/repos/PowerShell/PowerShell/pulls/$prNumber" ` + -Headers $header ` + -ErrorAction Stop ` + -Verbose:$false ## Always disable verbose to avoid noise when we debug this function. + } catch { + ## A commit may not have corresponding GitHub PRs. In that case, we will get status code 404 (Not Found). + ## Otherwise, let the error bubble up. + if ($_.Exception.Response.StatusCode -ne 404) { + throw + } + } + + if ($commitSubject -match '^\[release/v\d\.\d\] ') { + ## The commit was from a backport PR. We need to get the real author in this case. + if (-not $pr) { + throw "The commit is from a backport PR (#$prNumber), but the PR cannot be found.`nPR Title: $commitSubject" + } + + $userPattern = 'Triggered by @.+ on behalf of @(.+)' + if ($pr.body -match $userPattern) { + $commit.AuthorGitHubLogin = ($Matches.1).Trim() + Write-Verbose "backport PR. real author login: $($commit.AuthorGitHubLogin)" + } else { + throw "The commit is from a backport PR (#$prNumber), but the PR description failed to match the pattern '$userPattern'. Was the template for backport PRs changed?`nPR Title: $commitSubject" + } + } + + if ($commit.AuthorGitHubLogin) { + if ($script:psteam_logins -contains $commit.AuthorGitHubLogin) { + $commit.ChangeLogMessage = "- {0}" -f (Get-ChangeLogMessage $commitSubject) + } else { + $commit.ChangeLogMessage = ("- {0} (Thanks @{1}!)" -f (Get-ChangeLogMessage $commitSubject), $commit.AuthorGitHubLogin) + $commit.ThankYouMessage = ("@{0}" -f ($commit.AuthorGitHubLogin)) + } + } elseif ($commit.AuthorEmail.EndsWith("@microsoft.com") -or $powershell_team -contains $commit.AuthorName) { + $commit.ChangeLogMessage = "- {0}" -f (Get-ChangeLogMessage $commitSubject) } else { if ($community_login_map.ContainsKey($commit.AuthorEmail)) { $commit.AuthorGitHubLogin = $community_login_map[$commit.AuthorEmail] } else { - $uri = "https://api.github.com/repos/PowerShell/PowerShell/commits/$($commit.Hash)" try{ - $response = Invoke-WebRequest -Uri $uri -Method Get -Headers $header -ErrorAction Ignore - } catch{} + ## Always disable verbose to avoid noise when we debug this function. + $response = Invoke-RestMethod ` + -Uri "https://api.github.com/repos/PowerShell/PowerShell/commits/$($commit.Hash)" ` + -Headers $header ` + -ErrorAction Stop ` + -Verbose:$false + } catch { + ## A commit could be available in ADO only. In that case, we will get status code 422 (UnprocessableEntity). + ## Otherwise, let the error bubble up. + if ($_.Exception.Response.StatusCode -ne 422) { + throw + } + } + if($response) { - $content = ConvertFrom-Json -InputObject $response.Content - $commit.AuthorGitHubLogin = $content.author.login + $commit.AuthorGitHubLogin = $response.author.login $community_login_map[$commit.AuthorEmail] = $commit.AuthorGitHubLogin } } - $commit.ChangeLogMessage = ("- {0} (Thanks @{1}!)" -f (Get-ChangeLogMessage $commit.Subject), $commit.AuthorGitHubLogin) + + $commit.ChangeLogMessage = ("- {0} (Thanks @{1}!)" -f (Get-ChangeLogMessage $commitSubject), $commit.AuthorGitHubLogin) $commit.ThankYouMessage = ("@{0}" -f ($commit.AuthorGitHubLogin)) } @@ -289,16 +357,6 @@ function Get-ChangeLog } ## Get the labels for the PR - try { - $pr = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/PowerShell/pulls/$($commit.PullRequest)" -Headers $header -ErrorAction SilentlyContinue - } - catch { - if ($_.Exception.Response.StatusCode -eq '404') { - $pr = $null - #continue - } - } - if($pr) { $clLabel = $pr.labels | Where-Object { $_.Name -match "^CL-"} @@ -328,7 +386,7 @@ function Get-ChangeLog "CL-Tools" { $clTools += $commit } "CL-Untagged" { $clUntagged += $commit } "CL-NotInBuild" { continue } - Default { throw "unknown tag '$cLabel' for PR: '$($commit.PullRequest)'" } + Default { throw "unknown tag '$cLabel' for PR: '$prNumber'" } } } } @@ -426,6 +484,9 @@ function Get-ChangeLogMessage '^Build\(deps\): ' { return $OriginalMessage.replace($Matches.0,'') } + '^\[release/v\d\.\d\] ' { + return $OriginalMessage.replace($Matches.0,'') + } default { return $OriginalMessage } @@ -867,8 +928,8 @@ function Invoke-PRBackport { ) $continue = $false while(!$continue) { - $input= Read-Host -Prompt ($Message + "`nType 'Yes' to continue 'No' to exit") - switch($input) { + $value = Read-Host -Prompt ($Message + "`nType 'Yes' to continue 'No' to exit") + switch($value) { 'yes' { $continue= $true } From 5168d157117ff52b7c9851f4300038abf0178f4b Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 13 Feb 2026 16:54:16 -0800 Subject: [PATCH 206/275] [release/v7.5] Remove unused runCodesignValidationInjection variable from pipeline templates (#26825) --- .pipelines/templates/compliance/apiscan.yml | 2 -- .pipelines/templates/compliance/generateNotice.yml | 2 -- .pipelines/templates/linux-package-build.yml | 2 -- .pipelines/templates/linux.yml | 4 ---- .pipelines/templates/mac-package-build.yml | 2 -- .pipelines/templates/mac.yml | 2 -- .pipelines/templates/nupkg.yml | 2 -- .pipelines/templates/packaging/windows/package.yml | 2 -- .pipelines/templates/release-symbols.yml | 2 -- .pipelines/templates/release-upload-buildinfo.yml | 2 -- .pipelines/templates/testartifacts.yml | 4 ---- .pipelines/templates/uploadToAzure.yml | 2 -- .pipelines/templates/variable/release-shared.yml | 4 +--- .pipelines/templates/windows-hosted-build.yml | 2 -- 14 files changed, 1 insertion(+), 33 deletions(-) diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml index a07000c7067..27cb3a83a5c 100644 --- a/.pipelines/templates/compliance/apiscan.yml +++ b/.pipelines/templates/compliance/apiscan.yml @@ -4,8 +4,6 @@ jobs: - job: APIScan variables: - - name: runCodesignValidationInjection - value : false - name: NugetSecurityAnalysisWarningLevel value: none - name: ReleaseTagVar diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml index 7de316e8b49..0a38ed8f8e6 100644 --- a/.pipelines/templates/compliance/generateNotice.yml +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -10,8 +10,6 @@ parameters: jobs: - job: generateNotice variables: - - name: runCodesignValidationInjection - value : false - name: NugetSecurityAnalysisWarningLevel value: none - name: ob_outputDirectory diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index dad43a05885..3e37d13c177 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -13,8 +13,6 @@ jobs: type: linux variables: - - name: runCodesignValidationInjection - value: false - name: nugetMultiFeedWarnLevel value: none - name: NugetSecurityAnalysisWarningLevel diff --git a/.pipelines/templates/linux.yml b/.pipelines/templates/linux.yml index cbf63c84b48..f6d6b3c841e 100644 --- a/.pipelines/templates/linux.yml +++ b/.pipelines/templates/linux.yml @@ -10,8 +10,6 @@ jobs: pool: type: linux variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE @@ -137,8 +135,6 @@ jobs: pool: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index ce53c70b066..ec98c65cfcc 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -15,8 +15,6 @@ jobs: variables: - name: HOMEBREW_NO_ANALYTICS value: 1 - - name: runCodesignValidationInjection - value: false - name: nugetMultiFeedWarnLevel value: none - name: NugetSecurityAnalysisWarningLevel diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index ff4787b9bcf..1699207c657 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -13,8 +13,6 @@ jobs: variables: - name: HOMEBREW_NO_ANALYTICS value: 1 - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - group: DotNetPrivateBuildAccess diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index 2aed6749baa..8925fcba5ff 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -6,8 +6,6 @@ jobs: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: nugetMultiFeedWarnLevel value: none - name: NugetSecurityAnalysisWarningLevel diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 03673d61c7b..1f03d65ab21 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -9,8 +9,6 @@ jobs: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: ob_sdl_codeSignValidation_enabled value: false # Skip signing validation in build-only stage - name: ob_signing_setup_enabled diff --git a/.pipelines/templates/release-symbols.yml b/.pipelines/templates/release-symbols.yml index 68b8dd4324d..680a8314dd7 100644 --- a/.pipelines/templates/release-symbols.yml +++ b/.pipelines/templates/release-symbols.yml @@ -10,8 +10,6 @@ jobs: pool: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index 2f53f99faff..f360b3ff195 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -14,8 +14,6 @@ jobs: demands: - ImageOverride -equals PSMMS2019-Secure variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE diff --git a/.pipelines/templates/testartifacts.yml b/.pipelines/templates/testartifacts.yml index 751c9d5a53b..3a6bec4a859 100644 --- a/.pipelines/templates/testartifacts.yml +++ b/.pipelines/templates/testartifacts.yml @@ -1,8 +1,6 @@ jobs: - job: build_testartifacts_win variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - group: DotNetPrivateBuildAccess @@ -73,8 +71,6 @@ jobs: - job: build_testartifacts_nonwin variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - group: DotNetPrivateBuildAccess diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index 576830ba8f4..e93bb076db2 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -7,8 +7,6 @@ jobs: variables: - name: ob_sdl_sbom_enabled value: true - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE diff --git a/.pipelines/templates/variable/release-shared.yml b/.pipelines/templates/variable/release-shared.yml index f944639a908..70d3dd2df97 100644 --- a/.pipelines/templates/variable/release-shared.yml +++ b/.pipelines/templates/variable/release-shared.yml @@ -17,9 +17,7 @@ variables: value: false - name: ob_sdl_sbom_enabled value: ${{ parameters.SBOM }} - - name: runCodesignValidationInjection - value: false - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + - name: DOTNET_NOLOGO value: 1 - group: 'mscodehub-code-read-akv' - group: 'Azure Blob variable group' diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index b3c72a51b33..e21d2253887 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -10,8 +10,6 @@ jobs: pool: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE From c5f1ca16f61fa8a8b2e5fb5f3380523090959887 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Sun, 15 Feb 2026 15:47:07 -0800 Subject: [PATCH 207/275] [release/v7.5] Update metadata.json to update the Latest attribute with a better name (#26826) --- .pipelines/templates/channelSelection.yml | 8 ++++---- .pipelines/templates/release-prep-for-ev2.yml | 8 ++++---- .pipelines/templates/release-upload-buildinfo.yml | 10 +++++++--- tools/metadata.json | 10 +++++----- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/.pipelines/templates/channelSelection.yml b/.pipelines/templates/channelSelection.yml index 9dd0f3fb216..d6ddb53256e 100644 --- a/.pipelines/templates/channelSelection.yml +++ b/.pipelines/templates/channelSelection.yml @@ -2,6 +2,10 @@ steps: - pwsh: | # Determine LTS, Preview, or Stable $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw | ConvertFrom-Json + + $LTS = $metadata.LTSRelease.PublishToChannels + $Stable = $metadata.StableRelease.PublishToChannels + $isPreview = '$(OutputReleaseTag.releaseTag)' -match '-' $releaseTag = '$(OutputReleaseTag.releaseTag)' # Rebuild branches should be treated as preview builds @@ -11,10 +15,6 @@ steps: # If you update this regex, also update it in rebuild-branch-check.yml to keep them in sync. $isRebuildBranch = '$(Build.SourceBranch)' -match 'refs/heads/rebuild/.*-rebuild\.' - $LTS = $metadata.LTSRelease.Latest - $Stable = $metadata.StableRelease.Latest - $isPreview = $releaseTag -match '-' - # If this is a rebuild branch, force preview mode and ignore LTS metadata if ($isRebuildBranch) { $IsLTS = $false diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml index cf7982cd5e1..e644bece68f 100644 --- a/.pipelines/templates/release-prep-for-ev2.yml +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -33,7 +33,7 @@ stages: - template: release-SetReleaseTagandContainerName.yml parameters: restorePhase: true - + - pwsh: | $packageVersion = '$(OutputReleaseTag.ReleaseTag)'.ToLowerInvariant() -replace '^v','' $vstsCommandString = "vso[task.setvariable variable=packageVersion]$packageVersion" @@ -42,7 +42,7 @@ stages: displayName: Set Package version env: ob_restore_phase: true - + - pwsh: | $branch = 'mirror-target' $gitArgs = "clone", @@ -151,7 +151,7 @@ stages: $metadataHash = @{} $skipPublishValue = '${{ parameters.skipPublish }}' $metadataHash["ReleaseTag"] = '$(OutputReleaseTag.ReleaseTag)' - $metadataHash["LTS"] = $metadata.LTSRelease.Latest + $metadataHash["LTS"] = $metadata.LTSRelease.PublishToChannels $metadataHash["ForProduction"] = $true $metadataHash["SkipPublish"] = [System.Convert]::ToBoolean($skipPublishValue) @@ -222,7 +222,7 @@ stages: files_to_sign: '*.ps1' search_root: '$(repoRoot)/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run' displayName: Sign Run.ps1 - + - pwsh: | # folder to tar must have: Run.ps1, settings.toml, python_dl $srcPath = Join-Path '$(ev2ServiceGroupRootFolder)' -ChildPath 'Shell' diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index f360b3ff195..c470af1fd6e 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -16,7 +16,7 @@ jobs: variables: - name: NugetSecurityAnalysisWarningLevel value: none - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + - name: DOTNET_NOLOGO value: 1 - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' @@ -39,7 +39,7 @@ jobs: - template: release-SetReleaseTagandContainerName.yml - pwsh: | - Get-ChildItem Env: + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: 'Capture Environment Variables' - download: PSPackagesOfficial @@ -58,6 +58,10 @@ jobs: $metadata = Get-Content -LiteralPath "$toolsDirectory/metadata.json" -ErrorAction Stop | ConvertFrom-Json $stableReleaseTag = $metadata.StableReleaseTag -Replace 'v','' + $currentReleaseTag = $buildInfo.ReleaseTag -Replace 'v','' + $stableRelease = $metadata.StableRelease.PublishToChannels + $ltsRelease = $metadata.LTSRelease.PublishToChannels + Write-Verbose -Verbose "Writing $jsonFile contents:" $buildInfoJsonContent = Get-Content $jsonFile -Encoding UTF8NoBom -Raw Write-Verbose -Verbose $buildInfoJsonContent @@ -142,4 +146,4 @@ jobs: Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - condition: and(succeeded(), or(eq(variables['UploadPreview'], 'YES'), eq(variables['UploadLTS'], 'YES'), eq(variables['UploadStable'], 'YES'))) \ No newline at end of file + condition: and(succeeded(), or(eq(variables['UploadPreview'], 'YES'), eq(variables['UploadLTS'], 'YES'), eq(variables['UploadStable'], 'YES'))) diff --git a/tools/metadata.json b/tools/metadata.json index 1da6d7f42e7..4a268b9e2b3 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -2,9 +2,9 @@ "StableReleaseTag": "v7.4.4", "PreviewReleaseTag": "v7.5.0-preview.3", "ServicingReleaseTag": "v7.0.13", - "ReleaseTag": "v7.4.4", - "LTSReleaseTag" : ["v7.2.22", "v7.4.4"], - "NextReleaseTag": "v7.5.0-preview.4", - "LTSRelease": { "Latest": false, "Package": false }, - "StableRelease": { "Latest": true, "Package": true } + "ReleaseTag": "v7.5.4", + "LTSReleaseTag" : ["v7.4.13"], + "NextReleaseTag": "v7.6.0-preview.6", + "LTSRelease": { "PublishToChannels": false, "Package": false }, + "StableRelease": { "PublishToChannels": false, "Package": false } } From 9aa54ee99859a05344b97459f559f3361693925a Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Sun, 15 Feb 2026 15:55:50 -0800 Subject: [PATCH 208/275] [release/v7.5] Fix macOS preview package identifier detection to use version string (#26835) --- test/packaging/packaging.tests.ps1 | 67 +++++++++++++++++++++++++++++ tools/packaging/packaging.psm1 | 69 ++++++++++++++++++++++-------- 2 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 test/packaging/packaging.tests.ps1 diff --git a/test/packaging/packaging.tests.ps1 b/test/packaging/packaging.tests.ps1 new file mode 100644 index 00000000000..cc4bbe0d728 --- /dev/null +++ b/test/packaging/packaging.tests.ps1 @@ -0,0 +1,67 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe "Packaging Module Functions" { + BeforeAll { + Import-Module $PSScriptRoot/../../build.psm1 -Force + Import-Module $PSScriptRoot/../../tools/packaging/packaging.psm1 -Force + } + + Context "Test-IsPreview function" { + It "Should return True for preview versions" { + Test-IsPreview -Version "7.6.0-preview.6" | Should -Be $true + Test-IsPreview -Version "7.5.0-rc.1" | Should -Be $true + } + + It "Should return False for stable versions" { + Test-IsPreview -Version "7.6.0" | Should -Be $false + Test-IsPreview -Version "7.5.0" | Should -Be $false + } + + It "Should return False for LTS builds regardless of version string" { + Test-IsPreview -Version "7.6.0-preview.6" -IsLTS | Should -Be $false + Test-IsPreview -Version "7.5.0" -IsLTS | Should -Be $false + } + } + + Context "Get-MacOSPackageIdentifierInfo function (New-MacOSPackage logic)" { + It "Should detect preview builds and return preview identifier" { + $result = Get-MacOSPackageIdentifierInfo -Version "7.6.0-preview.6" -LTS:$false + + $result.IsPreview | Should -Be $true + $result.PackageIdentifier | Should -Be "com.microsoft.powershell-preview" + } + + It "Should detect stable builds and return stable identifier" { + $result = Get-MacOSPackageIdentifierInfo -Version "7.6.0" -LTS:$false + + $result.IsPreview | Should -Be $false + $result.PackageIdentifier | Should -Be "com.microsoft.powershell" + } + + It "Should treat LTS builds as stable even with preview version string" { + $result = Get-MacOSPackageIdentifierInfo -Version "7.4.0-preview.1" -LTS:$true + + $result.IsPreview | Should -Be $false + $result.PackageIdentifier | Should -Be "com.microsoft.powershell" + } + + It "Should NOT use package name for preview detection (bug fix verification)" { + # This test verifies the fix for issue #26673 + # The bug was using ($Name -like '*-preview') which always returned false + # because preview builds use Name="powershell" not "powershell-preview" + + $Version = "7.6.0-preview.6" + $Name = "powershell" # Preview builds use "powershell" not "powershell-preview" + + # The INCORRECT logic (the bug): $Name -like '*-preview' + $incorrectCheck = $Name -like '*-preview' + $incorrectCheck | Should -Be $false -Because "Package name is 'powershell' not 'powershell-preview'" + + # The CORRECT logic (the fix): uses version string + $result = Get-MacOSPackageIdentifierInfo -Version $Version -LTS:$false + $result.IsPreview | Should -Be $true -Because "Version string correctly identifies preview" + $result.PackageIdentifier | Should -Be "com.microsoft.powershell-preview" + } + } +} diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 05ce0ff7152..8d2c89d4178 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1359,6 +1359,7 @@ function New-UnixPackage { AppsFolder = $AppsFolder HostArchitecture = $HostArchitecture CurrentLocation = $CurrentLocation + LTS = $LTS } try { @@ -1503,7 +1504,12 @@ function New-MacOsDistributionPackage # Get package ID if not provided if (-not $PackageIdentifier) { - $PackageIdentifier = Get-MacOSPackageId -IsPreview:$IsPreview.IsPresent + if ($IsPreview.IsPresent) { + $PackageIdentifier = 'com.microsoft.powershell-preview' + } + else { + $PackageIdentifier = 'com.microsoft.powershell' + } } # Minimum OS version @@ -1972,7 +1978,9 @@ function New-MacOSPackage [Parameter(Mandatory)] [string]$HostArchitecture, - [string]$CurrentLocation = (Get-Location) + [string]$CurrentLocation = (Get-Location), + + [switch]$LTS ) Write-Log "Creating macOS package using pkgbuild and productbuild..." @@ -2047,8 +2055,10 @@ function New-MacOSPackage Copy-Item -Path "$AppsFolder/*" -Destination $appsInPkg -Recurse -Force } - # Build the component package using pkgbuild - $pkgIdentifier = Get-MacOSPackageId -IsPreview:($Name -like '*-preview') + # Get package identifier info based on version and LTS flag + $packageInfo = Get-MacOSPackageIdentifierInfo -Version $Version -LTS:$LTS + $IsPreview = $packageInfo.IsPreview + $pkgIdentifier = $packageInfo.PackageIdentifier if ($PSCmdlet.ShouldProcess("Build component package with pkgbuild")) { Write-Log "Running pkgbuild to create component package..." @@ -2073,7 +2083,7 @@ function New-MacOSPackage -OutputDirectory $CurrentLocation ` -HostArchitecture $HostArchitecture ` -PackageIdentifier $pkgIdentifier ` - -IsPreview:($Name -like '*-preview') + -IsPreview:$IsPreview return $distributionPackage } @@ -2275,20 +2285,44 @@ function New-ManGzip } } -# Returns the macOS Package Identifier -function Get-MacOSPackageId +<# + .SYNOPSIS + Determines the package identifier and preview status for macOS packages. + .DESCRIPTION + This function determines if a package is a preview build based on the version string + and LTS flag, then returns the appropriate package identifier. + .PARAMETER Version + The version string (e.g., "7.6.0-preview.6" or "7.6.0") + .PARAMETER LTS + Whether this is an LTS build + .OUTPUTS + Hashtable with IsPreview (boolean) and PackageIdentifier (string) properties + .EXAMPLE + Get-MacOSPackageIdentifierInfo -Version "7.6.0-preview.6" -LTS:$false + Returns @{ IsPreview = $true; PackageIdentifier = "com.microsoft.powershell-preview" } +#> +function Get-MacOSPackageIdentifierInfo { param( - [switch] - $IsPreview + [Parameter(Mandatory)] + [string]$Version, + + [switch]$LTS ) - if ($IsPreview.IsPresent) - { - return 'com.microsoft.powershell-preview' + + $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS + + # Determine package identifier based on preview status + if ($IsPreview) { + $PackageIdentifier = 'com.microsoft.powershell-preview' } - else - { - return 'com.microsoft.powershell' + else { + $PackageIdentifier = 'com.microsoft.powershell' + } + + return @{ + IsPreview = $IsPreview + PackageIdentifier = $PackageIdentifier } } @@ -2302,8 +2336,9 @@ function New-MacOSLauncher [switch]$LTS ) - $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS - $packageId = Get-MacOSPackageId -IsPreview:$IsPreview + $packageInfo = Get-MacOSPackageIdentifierInfo -Version $Version -LTS:$LTS + $IsPreview = $packageInfo.IsPreview + $packageId = $packageInfo.PackageIdentifier # Define folder for launcher application. $suffix = if ($IsPreview) { "-preview" } elseif ($LTS) { "-lts" } From d5d02a1f026e8c104e6bc4148855c5ff98c41c27 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 17 Feb 2026 11:54:12 -0800 Subject: [PATCH 209/275] [release/v7.5] Add GitHub Actions annotations for Pester test failures (#26836) --- .../process-pester-results.ps1 | 56 +++++++++++++++++ build.psm1 | 63 +++++++++++++++++++ tools/metadata.json | 4 +- 3 files changed, 121 insertions(+), 2 deletions(-) diff --git a/.github/actions/test/process-pester-results/process-pester-results.ps1 b/.github/actions/test/process-pester-results/process-pester-results.ps1 index 523de3bebaa..5804bec9a94 100644 --- a/.github/actions/test/process-pester-results/process-pester-results.ps1 +++ b/.github/actions/test/process-pester-results/process-pester-results.ps1 @@ -24,6 +24,7 @@ $testIgnoredCount = 0 $testSkippedCount = 0 $testInvalidCount = 0 +# Process test results and generate annotations for failures Get-ChildItem -Path "${TestResultsFolder}/*.xml" -Recurse | ForEach-Object { $results = [xml] (get-content $_.FullName) @@ -35,6 +36,61 @@ Get-ChildItem -Path "${TestResultsFolder}/*.xml" -Recurse | ForEach-Object { $testIgnoredCount += [int]$results.'test-results'.ignored $testSkippedCount += [int]$results.'test-results'.skipped $testInvalidCount += [int]$results.'test-results'.invalid + + # Generate GitHub Actions annotations for test failures + # Select failed test cases + if ("System.Xml.XmlDocumentXPathExtensions" -as [Type]) { + $failures = [System.Xml.XmlDocumentXPathExtensions]::SelectNodes($results.'test-results', './/test-case[@result = "Failure"]') + } + else { + $failures = $results.SelectNodes('.//test-case[@result = "Failure"]') + } + + foreach ($testfail in $failures) { + $description = $testfail.description + $testName = $testfail.name + $message = $testfail.failure.message + $stack_trace = $testfail.failure.'stack-trace' + + # Parse stack trace to get file and line info + $fileInfo = Get-PesterFailureFileInfo -StackTraceString $stack_trace + + if ($fileInfo.File) { + # Convert absolute path to relative path for GitHub Actions + $filePath = $fileInfo.File + + # GitHub Actions expects paths relative to the workspace root + if ($env:GITHUB_WORKSPACE) { + $workspacePath = $env:GITHUB_WORKSPACE + if ($filePath.StartsWith($workspacePath)) { + $filePath = $filePath.Substring($workspacePath.Length).TrimStart('/', '\') + # Normalize to forward slashes for consistency + $filePath = $filePath -replace '\\', '/' + } + } + + # Create annotation title + $annotationTitle = "Test Failure: $description / $testName" + + # Build the annotation message + $annotationMessage = $message -replace "`n", "%0A" -replace "`r" + + # Build and output the workflow command + $workflowCommand = "::error file=$filePath" + if ($fileInfo.Line) { + $workflowCommand += ",line=$($fileInfo.Line)" + } + $workflowCommand += ",title=$annotationTitle::$annotationMessage" + + Write-Host $workflowCommand + + # Output a link to the test run + if ($env:GITHUB_SERVER_URL -and $env:GITHUB_REPOSITORY -and $env:GITHUB_RUN_ID) { + $logUrl = "$($env:GITHUB_SERVER_URL)/$($env:GITHUB_REPOSITORY)/actions/runs/$($env:GITHUB_RUN_ID)" + Write-Host "Test logs: $logUrl" + } + } + } } @" diff --git a/build.psm1 b/build.psm1 index 1e1899ca0c5..f51bb6ee758 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1864,6 +1864,69 @@ $stack_trace } +function Get-PesterFailureFileInfo +{ + [CmdletBinding()] + param ( + [Parameter(Mandatory)] + [string]$StackTraceString + ) + + # Parse stack trace to extract file path and line number + # Common patterns: + # "at line: 123 in C:\path\to\file.ps1" (Pester 4) + # "at C:\path\to\file.ps1:123" + # "at , C:\path\to\file.ps1: line 123" + # "at 1 | Should -Be 2, /path/to/file.ps1:123" (Pester 5) + # "at 1 | Should -Be 2, C:\path\to\file.ps1:123" (Pester 5 Windows) + + $result = @{ + File = $null + Line = $null + } + + if ([string]::IsNullOrWhiteSpace($StackTraceString)) { + return $result + } + + # Try pattern: "at line: 123 in " (Pester 4) + if ($StackTraceString -match 'at line:\s*(\d+)\s+in\s+(.+?)(?:\r|\n|$)') { + $result.Line = $matches[1] + $result.File = $matches[2].Trim() + return $result + } + + # Try pattern: ", :123" (Pester 5 format) + # This handles both Unix paths (/path/file.ps1:123) and Windows paths (C:\path\file.ps1:123) + if ($StackTraceString -match ',\s*((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1):(\d+)') { + $result.File = $matches[1].Trim() + $result.Line = $matches[2] + return $result + } + + # Try pattern: "at :123" (without comma) + # Handle both absolute Unix and Windows paths + if ($StackTraceString -match 'at\s+((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):(\d+)(?:\r|\n|$)') { + $result.File = $matches[1].Trim() + $result.Line = $matches[2] + return $result + } + + # Try pattern: ": line 123" + if ($StackTraceString -match '((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):\s*line\s+(\d+)(?:\r|\n|$)') { + $result.File = $matches[1].Trim() + $result.Line = $matches[2] + return $result + } + + # Try to extract just the file path if no line number found + if ($StackTraceString -match '(?:at\s+|in\s+)?((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1)') { + $result.File = $matches[1].Trim() + } + + return $result +} + function Test-XUnitTestResults { param( diff --git a/tools/metadata.json b/tools/metadata.json index 4a268b9e2b3..9930af35579 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -2,9 +2,9 @@ "StableReleaseTag": "v7.4.4", "PreviewReleaseTag": "v7.5.0-preview.3", "ServicingReleaseTag": "v7.0.13", - "ReleaseTag": "v7.5.4", + "ReleaseTag": "v7.4.13", "LTSReleaseTag" : ["v7.4.13"], - "NextReleaseTag": "v7.6.0-preview.6", + "NextReleaseTag": "v7.5.0-preview.4", "LTSRelease": { "PublishToChannels": false, "Package": false }, "StableRelease": { "PublishToChannels": false, "Package": false } } From 024125951b1a748e39207f8d3332c61cae0dc1a5 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 17 Feb 2026 12:28:38 -0800 Subject: [PATCH 210/275] [release/v7.5] Mark flaky Update-Help web tests as pending to unblock CI (#26837) --- ...ester-set-itresult-pattern.instructions.md | 198 ++++++++++++++++++ .../engine/Help/UpdatableHelpSystem.Tests.ps1 | 31 ++- 2 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 .github/instructions/pester-set-itresult-pattern.instructions.md diff --git a/.github/instructions/pester-set-itresult-pattern.instructions.md b/.github/instructions/pester-set-itresult-pattern.instructions.md new file mode 100644 index 00000000000..33a73ca081d --- /dev/null +++ b/.github/instructions/pester-set-itresult-pattern.instructions.md @@ -0,0 +1,198 @@ +--- +applyTo: + - "**/*.Tests.ps1" +--- + +# Pester Set-ItResult Pattern for Pending and Skipped Tests + +## Purpose + +This instruction explains when and how to use `Set-ItResult` in Pester tests to mark tests as Pending or Skipped dynamically within test execution. + +## When to Use Set-ItResult + +Use `Set-ItResult` when you need to conditionally mark a test as Pending or Skipped based on runtime conditions that can't be determined at test definition time. + +### Pending vs Skipped + +**Pending**: Use for tests that should be enabled but temporarily can't run due to: +- Intermittent external service failures (network, APIs) +- Known bugs being fixed +- Missing features being implemented +- Environmental issues that are being resolved + +**Skipped**: Use for tests that aren't applicable to the current environment: +- Platform-specific tests running on wrong platform +- Tests requiring specific hardware/configuration not present +- Tests requiring elevated permissions when not available +- Feature-specific tests when feature is disabled + +## Pattern + +### Basic Usage + +```powershell +It "Test description" { + if ($shouldBePending) { + Set-ItResult -Pending -Because "Explanation of why test is pending" + return + } + + if ($shouldBeSkipped) { + Set-ItResult -Skipped -Because "Explanation of why test is skipped" + return + } + + # Test code here +} +``` + +### Important: Always Return After Set-ItResult + +After calling `Set-ItResult`, you **must** return from the test to prevent further execution: + +```powershell +It "Test that checks environment" { + if ($env:SKIP_TESTS -eq 'true') { + Set-ItResult -Skipped -Because "SKIP_TESTS environment variable is set" + return # This is required! + } + + # Test assertions + $result | Should -Be $expected +} +``` + +**Why?** Without `return`, the test continues executing and may fail with errors unrelated to the pending/skipped condition. + +## Examples from the Codebase + +### Example 1: Pending for Intermittent Network Issues + +```powershell +It "Validate Update-Help for module" { + if ($markAsPending) { + Set-ItResult -Pending -Because "Update-Help from the web has intermittent connectivity issues. See issues #2807 and #6541." + return + } + + Update-Help -Module $moduleName -Force + # validation code... +} +``` + +### Example 2: Skipped for Missing Environment + +```powershell +It "Test requires CI environment" { + if (-not $env:CI) { + Set-ItResult -Skipped -Because "Test requires CI environment to safely install Pester" + return + } + + Install-CIPester -ErrorAction Stop +} +``` + +### Example 3: Pending for Platform-Specific Issue + +```powershell +It "Clear-Host works correctly" { + if ($IsARM64) { + Set-ItResult -Pending -Because "ARM64 runs in non-interactively mode and Clear-Host does not work." + return + } + + & { Clear-Host; 'hi' } | Should -BeExactly 'hi' +} +``` + +### Example 4: Skipped for Missing Feature + +```powershell +It "Test ACR authentication" { + if ($env:ACRTESTS -ne 'true') { + Set-ItResult -Skipped -Because "The tests require the ACRTESTS environment variable to be set to 'true' for ACR authentication." + return + } + + $psgetModuleInfo = Find-PSResource -Name $ACRTestModule -Repository $ACRRepositoryName + # test assertions... +} +``` + +## Alternative: Static -Skip and -Pending Parameters + +For conditions that can be determined at test definition time, use the static parameters instead: + +```powershell +# Static skip - condition known at definition time +It "Windows-only test" -Skip:(-not $IsWindows) { + # test code +} + +# Static pending - always pending +It "Test for feature being implemented" -Pending { + # test code that will fail until feature is done +} +``` + +**Use Set-ItResult when**: +- Condition depends on runtime state +- Condition is determined inside a helper function +- Need to check multiple conditions sequentially + +**Use static parameters when**: +- Condition is known at test definition +- Condition doesn't change during test run +- Want Pester to show the condition in test discovery + +## Best Practices + +1. **Always include -Because parameter** with a clear explanation +2. **Always return after Set-ItResult** to prevent further execution +3. **Reference issues or documentation** when relevant (e.g., "See issue #1234") +4. **Be specific in the reason** - explain what's wrong and what's needed +5. **Use Pending sparingly** - it indicates a problem that should be fixed +6. **Prefer Skipped over Pending** when test truly isn't applicable + +## Common Mistakes + +### ❌ Mistake 1: Forgetting to Return + +```powershell +It "Test" { + if ($condition) { + Set-ItResult -Pending -Because "Reason" + # Missing return - test code will still execute! + } + $value | Should -Be $expected # This runs and fails +} +``` + +### ❌ Mistake 2: Vague Reason + +```powershell +Set-ItResult -Pending -Because "Doesn't work" # Too vague +``` + +### ✅ Correct: + +```powershell +It "Test" { + if ($condition) { + Set-ItResult -Pending -Because "Update-Help has intermittent network timeouts. See issue #2807." + return + } + $value | Should -Be $expected +} +``` + +## See Also + +- [Pester Documentation: Set-ItResult](https://pester.dev/docs/commands/Set-ItResult) +- [Pester Documentation: It](https://pester.dev/docs/commands/It) +- Examples in the codebase: + - `test/powershell/Host/ConsoleHost.Tests.ps1` + - `test/infrastructure/ciModule.Tests.ps1` + - `tools/packaging/releaseTests/sbom.tests.ps1` diff --git a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 index e6e6b492410..f361f1e7cac 100644 --- a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 @@ -191,7 +191,8 @@ function RunUpdateHelpTests param ( [string]$tag = "CI", [switch]$useSourcePath, - [switch]$userscope + [switch]$userscope, + [switch]$markAsPending ) foreach ($moduleName in $modulesInBox) @@ -214,8 +215,15 @@ function RunUpdateHelpTests It ('Validate Update-Help for module ''{0}'' in {1}' -F $moduleName, [PSCustomObject] $updateScope) -Skip:(!(Test-CanWriteToPsHome) -and $userscope -eq $false) { + if ($markAsPending -or ($IsLinux -and $moduleName -eq "PackageManagement")) { + Set-ItResult -Pending -Because "Update-Help from the web has intermittent connectivity issues. See issues #2807 and #6541." + return + } + # Delete the whole help directory - Remove-Item ($moduleHelpPath) -Recurse -Force -ErrorAction SilentlyContinue + if ($moduleHelpPath) { + Remove-Item ($moduleHelpPath) -Recurse -Force -ErrorAction SilentlyContinue + } [hashtable] $UICultureParam = $(if ((Get-UICulture).Name -ne $myUICulture) { @{ UICulture = $myUICulture } } else { @{} }) [hashtable] $sourcePathParam = $(if ($useSourcePath) { @{ SourcePath = Join-Path $PSScriptRoot assets } } else { @{} }) @@ -246,8 +254,15 @@ function RunSaveHelpTests { try { - $saveHelpFolder = Join-Path $TestDrive (Get-Random).ToString() - New-Item $saveHelpFolder -Force -ItemType Directory > $null + $saveHelpFolder = if ($TestDrive) { + Join-Path $TestDrive (Get-Random).ToString() + } else { + $null + } + + if ($saveHelpFolder) { + New-Item $saveHelpFolder -Force -ItemType Directory > $null + } ## Save help has intermittent connectivity issues for downloading PackageManagement help content. ## Hence the test has been marked as Pending. @@ -283,7 +298,9 @@ function RunSaveHelpTests } finally { - Remove-Item $saveHelpFolder -Force -ErrorAction SilentlyContinue -Recurse + if ($saveHelpFolder) { + Remove-Item $saveHelpFolder -Force -ErrorAction SilentlyContinue -Recurse + } } } } @@ -316,6 +333,8 @@ Describe "Validate Update-Help from the Web for one PowerShell module." -Tags @( $ProgressPreference = $SavedProgressPreference } + ## Update-Help from the web has intermittent connectivity issues that cause CI failures. + ## Tests are marked as Pending to unblock work. See issues #2807 and #6541. RunUpdateHelpTests -Tag "CI" } @@ -328,6 +347,8 @@ Describe "Validate Update-Help from the Web for one PowerShell module for user s $ProgressPreference = $SavedProgressPreference } + ## Update-Help from the web has intermittent connectivity issues that cause CI failures. + ## Tests are marked as Pending to unblock work. See issues #2807 and #6541. RunUpdateHelpTests -Tag "CI" -UserScope } From 89227acf005d46081969f450d4c6cb3a40593fe0 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 9 Mar 2026 13:29:14 -0700 Subject: [PATCH 211/275] [release/v7.5] Merge the v7.6.0-preview.5 release branch back to master (#26958) --- .pipelines/PowerShell-Release-Official.yml | 6 +- .pipelines/store/SBConfig.json | 6 +- .pipelines/templates/package-create-msix.yml | 66 +++++-------- .pipelines/templates/release-MSIX-Publish.yml | 95 +++++++++---------- .pipelines/templates/release-githubNuget.yml | 4 +- .../release-validate-globaltools.yml | 6 ++ .pipelines/templates/release-validate-sdk.yml | 5 +- .pipelines/templates/windows-hosted-build.yml | 2 +- 8 files changed, 87 insertions(+), 103 deletions(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index cefb49abbee..62b6a78ff19 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -156,7 +156,7 @@ extends: parameters: jobName: "LinuxSDK" displayName: "Linux SDK Validation" - imageName: PSMMSUbuntu20.04-Secure + imageName: PSMMSUbuntu22.04-Secure poolName: $(ubuntuPool) - stage: gbltool @@ -358,7 +358,7 @@ extends: This is typically done by the community 1-2 days after the release. - stage: PublishMsix - dependsOn: + dependsOn: - setReleaseTagAndChangelog - PushGitTagAndMakeDraftPublic displayName: Publish MSIX to store @@ -440,4 +440,4 @@ extends: displayName: Delete release branch jobName: DeleteBranch instructions: | - Delete release + Delete release \ No newline at end of file diff --git a/.pipelines/store/SBConfig.json b/.pipelines/store/SBConfig.json index 002333cba1d..a52d60b045f 100644 --- a/.pipelines/store/SBConfig.json +++ b/.pipelines/store/SBConfig.json @@ -4,7 +4,9 @@ "packageParameters": { "PDPRootPath": "", "Release": "", - "PDPInclude": [], + "PDPInclude": [ + "PDP.xml" + ], "PDPExclude": [], "LanguageExclude": [ "default", @@ -21,7 +23,7 @@ }, "appSubmission": { "productId": "", - "targetPublishMode": "NotSet", + "targetPublishMode": "Immediate", "targetPublishDate": null, "visibility": "NotSet", "pricing": { diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 3448faaec51..4b3b79b65ee 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -13,6 +13,10 @@ jobs: - group: msixTools - group: 'Azure Blob variable group' - group: 'Store Publish Variables' + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' @@ -145,16 +149,19 @@ jobs: 'LTS' = @{ AppStoreName = 'PowerShell-LTS' ProductId = '$(productId-LTS)' + AppId = '$(AppID-LTS)' ServiceEndpoint = "StoreAppPublish-Stable" } 'Stable' = @{ AppStoreName = 'PowerShell' ProductId = '$(productId-Stable)' + AppId = '$(AppID-Stable)' ServiceEndpoint = "StoreAppPublish-Stable" } 'Preview' = @{ AppStoreName = 'PowerShell (Preview)' ProductId = '$(productId-Preview)' + AppId = '$(AppID-Preview)' ServiceEndpoint = "StoreAppPublish-Preview" } } @@ -179,16 +186,21 @@ jobs: [xml]$pdpXml = Get-Content $pdpPath -Raw - $appStoreNameElement = $pdpXml.SelectSingleNode("//AppStoreName[@_locID]") + # Create namespace manager for XML with default namespace + $nsManager = New-Object System.Xml.XmlNamespaceManager($pdpXml.NameTable) + $nsManager.AddNamespace("pd", "http://schemas.microsoft.com/appx/2012/ProductDescription") + + $appStoreNameElement = $pdpXml.SelectSingleNode("//pd:AppStoreName", $nsManager) if ($appStoreNameElement) { - $appStoreNameElement.InnerText = $config.AppStoreName - Write-Verbose -Verbose "Updated AppStoreName to: $($config.AppStoreName)" + $appStoreNameElement.SetAttribute("_locID", $config.AppStoreName) + Write-Verbose -Verbose "Updated AppStoreName _locID to: $($config.AppStoreName)" } else { Write-Warning "AppStoreName element not found in PDP file" } $pdpXml.Save($pdpPath) Write-Verbose -Verbose "PDP file updated successfully" + Get-Content -Path $pdpPath | Write-Verbose -Verbose } else { Write-Error "PDP file not found: $pdpPath" exit 1 @@ -206,6 +218,7 @@ jobs: $sbConfigJson | ConvertTo-Json -Depth 100 | Set-Content $sbConfigPath -Encoding UTF8 Write-Verbose -Verbose "SBConfig file updated successfully" + Get-Content -Path $sbConfigPath | Write-Verbose -Verbose } else { Write-Error "SBConfig file not found: $sbConfigPath" exit 1 @@ -213,55 +226,24 @@ jobs: Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" - - # These variables are used in the next tasks to determine which ServiceEndpoint to use - $ltsValue = $IsLTS.ToString().ToLower() - $stableValue = $IsStable.ToString().ToLower() - $previewValue = $IsPreview.ToString().ToLower() - - Write-Verbose -Verbose "About to set variables:" - Write-Verbose -Verbose " LTS=$ltsValue" - Write-Verbose -Verbose " STABLE=$stableValue" - Write-Verbose -Verbose " PREVIEW=$previewValue" - - Write-Host "##vso[task.setvariable variable=LTS]$ltsValue" - Write-Host "##vso[task.setvariable variable=STABLE]$stableValue" - Write-Host "##vso[task.setvariable variable=PREVIEW]$previewValue" - - Write-Verbose -Verbose "Variables set successfully" name: UpdateConfigs displayName: Update PDPs and SBConfig.json - - pwsh: | - Write-Verbose -Verbose "Checking variables after UpdateConfigs:" - Write-Verbose -Verbose "LTS=$(LTS)" - Write-Verbose -Verbose "STABLE=$(STABLE)" - Write-Verbose -Verbose "PREVIEW=$(PREVIEW)" - displayName: Debug - Check Variables - - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 - displayName: 'Create StoreBroker Package (Preview)' - condition: eq(variables['PREVIEW'], 'true') + displayName: 'Create StoreBroker Package' inputs: - serviceEndpoint: 'StoreAppPublish-Preview' + serviceEndpoint: 'StoreAppPublish-Private' sbConfigPath: '$(SBConfigPath)' sourceFolder: '$(BundleDir)' contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' - pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 - displayName: 'Create StoreBroker Package (Stable/LTS)' - condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) - inputs: - serviceEndpoint: 'StoreAppPublish-Stable' - sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(BundleDir)' - contents: '*.msixBundle' - outSBName: 'PowerShellStorePackage' - pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' - pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' + - pwsh: | + Get-Item -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue | + Copy-Item -Destination "$(ob_outputDirectory)" -Verbose + displayName: Upload Store Failure Log + condition: failed() - pwsh: | $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" @@ -279,4 +261,4 @@ jobs: else { Write-Error "Required files not found in $submissionPackageDir" } - displayName: 'Upload StoreBroker Package' + displayName: 'Upload StoreBroker Package' \ No newline at end of file diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index eb51584d9b9..4d3e0cb41c8 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -15,12 +15,15 @@ jobs: artifactName: drop_msixbundle_CreateMSIXBundle variables: - group: 'Store Publish Variables' + - name: LTS + value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsLTS'] ] + - name: STABLE + value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsStable'] ] + - name: PREVIEW + value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsPreview'] ] - template: ./variable/release-shared.yml@self parameters: RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] - LTS: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsLTS'] ] - STABLE: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsStable'] ] - PREVIEW: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsPreview'] ] steps: - task: PowerShell@2 inputs: @@ -40,15 +43,14 @@ jobs: } $middleURL = '' $tagString = "$(ReleaseTag)" - if ($tagString -match '-') { + if ($tagString -match '-preview') { $middleURL = "preview" } elseif ($tagString -match '(\d+\.\d+)') { $middleURL = $matches[1] } - - $endURL = $tagString -replace '^v','' -replace '\.','' + $endURL = $tagString -replace '^v|\.', '' $message = "Changelog: https://github.com/PowerShell/PowerShell/blob/master/CHANGELOG/$middleURL.md#$endURL" Write-Verbose -Verbose "Release Notes for the Store:" Write-Verbose -Verbose "$message" @@ -64,24 +66,14 @@ jobs: inputs: targetType: inline script: | - Write-Verbose -Verbose "Channel Selection - LTS: $(LTS), Stable: $(Stable), Preview: $(Preview)" + # Convert ADO variables to PowerShell boolean variables + $IsLTS = '$(LTS)' -eq 'true' + $IsStable = '$(STABLE)' -eq 'true' + $IsPreview = '$(PREVIEW)' -eq 'true' - # Define app configurations for each channel using secret variables - $channelConfigs = @{ - 'LTS' = @{ - AppId = '$(AppID-LTS)' - ServiceEndpoint = 'StoreAppPublish-Stable' - } - 'Stable' = @{ - AppId = '$(AppID-Stable)' - ServiceEndpoint = 'StoreAppPublish-Stable' - } - 'Preview' = @{ - AppId = '$(AppID-Preview)' - ServiceEndpoint = 'StoreAppPublish-Preview' - } - } + Write-Verbose -Verbose "Channel Selection - LTS: $(LTS), Stable: $(STABLE), Preview: $(PREVIEW)" + # Determine the current channel for logging purposes $currentChannel = if ($IsLTS) { 'LTS' } elseif ($IsStable) { 'Stable' } elseif ($IsPreview) { 'Preview' } @@ -89,36 +81,17 @@ jobs: Write-Error "No valid channel detected" exit 1 } - - # Assign AppID for Store-Publish Task - $appID = $null - if ($IsLTS) { - $appID = '$(AppID-LTS)' - } - elseif ($IsStable) { - $appID = '$(AppID-Stable)' - } - else { - $appID = '$(AppID-Preview)' - } - - Write-Host "##vso[task.setvariable variable=AppID]$appID" + Write-Verbose -Verbose "Selected channel: $currentChannel" - Write-Verbose -Verbose "App ID: $($config.AppId)" - Write-Verbose -Verbose "Service Endpoint: $($config.ServiceEndpoint)" - - # Set pipeline variables for use in the store-publish task - Write-Host "##vso[task.setvariable variable=SelectedAppId]$($config.AppId)" - Write-Host "##vso[task.setvariable variable=SelectedServiceEndpoint]$($config.ServiceEndpoint)" - Write-Host "##vso[task.setvariable variable=SelectedChannel]$currentChannel" - displayName: 'Set StoreBroker Configurations' + Write-Verbose -Verbose "Conditional tasks will handle the publishing based on channel variables" + displayName: 'Validate Channel Selection' - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 - displayName: 'Publish StoreBroker Package (Stable/LTS)' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true'))) + displayName: 'Publish LTS StoreBroker Package' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['LTS'], 'true')) inputs: - serviceEndpoint: 'StoreAppPublish-Stable' - appId: '$(AppID)' + serviceEndpoint: 'StoreAppPublish-Private' + appId: '$(AppID-LTS)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' @@ -127,14 +100,32 @@ jobs: targetPublishMode: 'Immediate' - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 - displayName: 'Publish StoreBroker Package (Preview)' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq('$(PREVIEW)', 'true')) + displayName: 'Publish Stable StoreBroker Package' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['STABLE'], 'true')) inputs: - serviceEndpoint: 'StoreAppPublish-Preview' - appId: '$(AppID)' + serviceEndpoint: 'StoreAppPublish-Private' + appId: '$(AppID-Stable)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' numberOfPackagesToKeep: 2 jsonZipUpdateMetadata: true targetPublishMode: 'Immediate' + + - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 + displayName: 'Publish Preview StoreBroker Package' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) + inputs: + serviceEndpoint: 'StoreAppPublish-Private' + appId: '$(AppID-Preview)' + inputMethod: JsonAndZip + jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' + zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' + numberOfPackagesToKeep: 2 + jsonZipUpdateMetadata: true + targetPublishMode: 'Immediate' + + - pwsh: | + Get-Content -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue + displayName: Upload Store Failure Log + condition: failed() diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index 5a053514d6b..348afe66c7b 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -121,13 +121,13 @@ jobs: $middleURL = '' $tagString = "$(ReleaseTag)" Write-Verbose -Verbose "Use the following command to push the tag:" - if ($tagString -match '-') { + if ($tagString -match '-preview') { $middleURL = "preview" } elseif ($tagString -match '(\d+\.\d+)') { $middleURL = $matches[1] } - $endURL = $tagString -replace '[v\.]','' + $endURL = $tagString -replace '^v|\.', '' $message = "https://github.com/PowerShell/PowerShell/blob/master/CHANGELOG/$middleURL.md#$endURL" Write-Verbose -Verbose "git tag -a $(ReleaseTag) $env:BUILD_SOURCEVERSION -m $message" displayName: Git Push Tag Command diff --git a/.pipelines/templates/release-validate-globaltools.yml b/.pipelines/templates/release-validate-globaltools.yml index 11e124e33d6..4234087c1b1 100644 --- a/.pipelines/templates/release-validate-globaltools.yml +++ b/.pipelines/templates/release-validate-globaltools.yml @@ -43,6 +43,9 @@ jobs: - pwsh: | $repoRoot = "$(Build.SourcesDirectory)/PowerShell" + Import-Module "$repoRoot/build.psm1" -Force -Verbose + Start-PSBootstrap -Scenario Dotnet + $toolPath = New-Item -ItemType Directory "$(System.DefaultWorkingDirectory)/toolPath" | Select-Object -ExpandProperty FullName Write-Verbose -Verbose "dotnet tool list -g" @@ -75,6 +78,9 @@ jobs: - pwsh: | $repoRoot = "$(Build.SourcesDirectory)/PowerShell" + Import-Module "$repoRoot/build.psm1" -Force -Verbose + Start-PSBootstrap -Scenario Dotnet + $exeName = if ($IsWindows) { "pwsh.exe" } else { "pwsh" } $toolPath = "$(System.DefaultWorkingDirectory)/toolPath/${{ parameters.globalToolExeName }}" diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index 3e58101f7e3..b90dbb71d05 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -51,7 +51,10 @@ jobs: - pwsh: | $repoRoot = "$(Build.SourcesDirectory)" - $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + Import-Module "$repoRoot/build.psm1" -Force -Verbose + Start-PSBootstrap -Scenario Dotnet + + $env:DOTNET_NOLOGO=1 $localLocation = "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" $xmlElement = @" diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index e21d2253887..b6d64d7a96d 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -268,7 +268,7 @@ jobs: 'Microsoft.PowerShell.PSResourceGet' 'Microsoft.PowerShell.Archive' 'PSReadLine' - 'ThreadJob' + 'Microsoft.PowerShell.ThreadJob' ) $sourceModulePath = Join-Path '$(GlobalToolArtifactPath)' 'publish' 'PowerShell.Windows.x64' 'release' 'Modules' From b770669f4c39ad10f69956e562eab029d9622a54 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 9 Mar 2026 14:07:12 -0700 Subject: [PATCH 212/275] [release/v7.5] Bring Release Changes from v7.6.0-preview.6 (#26963) --- build.psm1 | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/build.psm1 b/build.psm1 index f51bb6ee758..d87833513b8 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2548,19 +2548,21 @@ function Start-PSBootstrap { Write-LogGroupEnd -Title "Install Windows Dependencies" } - if ($Scenario -in 'All', 'Tools') { - Write-LogGroupStart -Title "Install .NET Global Tools" - Write-Log -message "Installing .NET global tools" + # Ensure dotnet is available + Find-Dotnet - # Ensure dotnet is available - Find-Dotnet + if (-not $env:TF_BUILD) { + if ($Scenario -in 'All', 'Tools') { + Write-LogGroupStart -Title "Install .NET Global Tools" + Write-Log -message "Installing .NET global tools" - # Install dotnet-format - Write-Verbose -Verbose "Installing dotnet-format global tool" - Start-NativeExecution { - dotnet tool install --global dotnet-format + # Install dotnet-format + Write-Verbose -Verbose "Installing dotnet-format global tool" + Start-NativeExecution { + dotnet tool install --global dotnet-format + } + Write-LogGroupEnd -Title "Install .NET Global Tools" } - Write-LogGroupEnd -Title "Install .NET Global Tools" } if ($env:TF_BUILD) { From f25efeb5350d95d6c504bd404379712ea2d68427 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 9 Mar 2026 16:20:44 -0700 Subject: [PATCH 213/275] [release/v7.5] Correct the package name for .deb and .rpm packages (#26964) --- .github/workflows/macos-ci.yml | 3 ++- tools/packaging/packaging.psm1 | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index e359623bbeb..6633cd0467b 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -54,6 +54,7 @@ jobs: outputs: source: ${{ steps.filter.outputs.source }} buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} + packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout uses: actions/checkout@v5 @@ -158,7 +159,7 @@ jobs: name: macOS packaging and testing needs: - changes - if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + if: ${{ needs.changes.outputs.packagingChanged == 'true' }} runs-on: - macos-15-large steps: diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 8d2c89d4178..3d001aaba34 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1147,12 +1147,16 @@ function New-UnixPackage { } # Determine if the version is a preview version - # Only LTS packages get a prefix in the name - # Preview versions are identified by the version string itself (e.g., 7.6.0-preview.6) - # Rebuild versions are also identified by the version string (e.g., 7.4.13-rebuild.5) + $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS + + # For deb/rpm packages, use the '-lts' and '-preview' channel suffix variants to match existing names on packages.microsoft.com. + # For osxpkg package, only LTS packages get a channel suffix in the name. $Name = if($LTS) { "powershell-lts" } + elseif ($IsPreview -and $Type -ne "osxpkg") { + "powershell-preview" + } else { "powershell" } From d056f9cc5100670aeaafa0039ad26319c8f59655 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 9 Mar 2026 16:21:00 -0700 Subject: [PATCH 214/275] [release/v7.5] Fix a preview detection test for the packaging script (#26966) --- test/packaging/packaging.tests.ps1 | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/test/packaging/packaging.tests.ps1 b/test/packaging/packaging.tests.ps1 index cc4bbe0d728..a7d322205bc 100644 --- a/test/packaging/packaging.tests.ps1 +++ b/test/packaging/packaging.tests.ps1 @@ -46,18 +46,15 @@ Describe "Packaging Module Functions" { $result.PackageIdentifier | Should -Be "com.microsoft.powershell" } - It "Should NOT use package name for preview detection (bug fix verification)" { + It "Should NOT use package name for preview detection (bug fix verification) - " -TestCases @( + @{ Version = "7.6.0-preview.6"; Name = "Preview" } + @{ Version = "7.6.0-rc.1"; Name = "RC" } + ) { # This test verifies the fix for issue #26673 # The bug was using ($Name -like '*-preview') which always returned false # because preview builds use Name="powershell" not "powershell-preview" - - $Version = "7.6.0-preview.6" - $Name = "powershell" # Preview builds use "powershell" not "powershell-preview" - - # The INCORRECT logic (the bug): $Name -like '*-preview' - $incorrectCheck = $Name -like '*-preview' - $incorrectCheck | Should -Be $false -Because "Package name is 'powershell' not 'powershell-preview'" - + param($Version) + # The CORRECT logic (the fix): uses version string $result = Get-MacOSPackageIdentifierInfo -Version $Version -LTS:$false $result.IsPreview | Should -Be $true -Because "Version string correctly identifies preview" From d4d5585ad5769731f5314b2e2590104dcc817ca0 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 9 Mar 2026 16:21:15 -0700 Subject: [PATCH 215/275] [release/v7.5] Split TPN manifest and Component Governance manifest (#26967) --- .../templates/compliance/generateNotice.yml | 2 +- .vsts-ci/linux-internal.yml | 2 +- .vsts-ci/mac.yml | 2 +- .vsts-ci/psresourceget-acr.yml | 2 +- .vsts-ci/windows-arm64.yml | 2 +- tools/{ => cgmanifest/main}/cgmanifest.json | 0 tools/cgmanifest/tpn/cgmanifest.json | 755 ++++++++++++++++++ tools/clearlyDefined/ClearlyDefined.ps1 | 2 +- .../Find-LastHarvestedVersion.ps1 | 156 ++++ .../src/ClearlyDefined/ClearlyDefined.psm1 | 275 ++++++- tools/findMissingNotices.ps1 | 234 +++++- tools/packaging/packaging.psm1 | 2 +- 12 files changed, 1411 insertions(+), 23 deletions(-) rename tools/{ => cgmanifest/main}/cgmanifest.json (100%) create mode 100644 tools/cgmanifest/tpn/cgmanifest.json create mode 100644 tools/clearlyDefined/Find-LastHarvestedVersion.ps1 diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml index 0a38ed8f8e6..90fd08dd8d9 100644 --- a/.pipelines/templates/compliance/generateNotice.yml +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -55,7 +55,7 @@ jobs: - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 displayName: 'Component Detection' inputs: - sourceScanPath: '$(repoRoot)\tools' + sourceScanPath: '$(repoRoot)\tools\cgmanifest\tpn' - pwsh: | $(repoRoot)/tools/clearlyDefined/ClearlyDefined.ps1 -TestAndHarvest diff --git a/.vsts-ci/linux-internal.yml b/.vsts-ci/linux-internal.yml index 6286a03fb52..af5bccfe53e 100644 --- a/.vsts-ci/linux-internal.yml +++ b/.vsts-ci/linux-internal.yml @@ -34,7 +34,7 @@ pr: - .vsts-ci/misc-analysis.yml - .vsts-ci/windows.yml - .vsts-ci/windows/* - - tools/cgmanifest.json + - tools/cgmanifest/* - LICENSE.txt - test/common/markdown/* - test/perf/* diff --git a/.vsts-ci/mac.yml b/.vsts-ci/mac.yml index 05d6d71ea71..7dec9c8ccd9 100644 --- a/.vsts-ci/mac.yml +++ b/.vsts-ci/mac.yml @@ -34,7 +34,7 @@ pr: - .vsts-ci/misc-analysis.yml - .vsts-ci/windows.yml - .vsts-ci/windows/* - - tools/cgmanifest.json + - tools/cgmanifest/* - LICENSE.txt - test/common/markdown/* - test/perf/* diff --git a/.vsts-ci/psresourceget-acr.yml b/.vsts-ci/psresourceget-acr.yml index 1a24983b5b5..a7b596acc09 100644 --- a/.vsts-ci/psresourceget-acr.yml +++ b/.vsts-ci/psresourceget-acr.yml @@ -34,7 +34,7 @@ pr: - .github/ISSUE_TEMPLATE/* - .github/workflows/* - .vsts-ci/misc-analysis.yml - - tools/cgmanifest.json + - tools/cgmanifest/* - LICENSE.txt - test/common/markdown/* - test/perf/* diff --git a/.vsts-ci/windows-arm64.yml b/.vsts-ci/windows-arm64.yml index be4cfcbaf4c..5b94aa3db77 100644 --- a/.vsts-ci/windows-arm64.yml +++ b/.vsts-ci/windows-arm64.yml @@ -28,7 +28,7 @@ pr: - .dependabot/config.yml - .github/ISSUE_TEMPLATE/* - .vsts-ci/misc-analysis.yml - - tools/cgmanifest.json + - tools/cgmanifest/* - LICENSE.txt - test/common/markdown/* - test/perf/* diff --git a/tools/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json similarity index 100% rename from tools/cgmanifest.json rename to tools/cgmanifest/main/cgmanifest.json diff --git a/tools/cgmanifest/tpn/cgmanifest.json b/tools/cgmanifest/tpn/cgmanifest.json new file mode 100644 index 00000000000..a0746028a56 --- /dev/null +++ b/tools/cgmanifest/tpn/cgmanifest.json @@ -0,0 +1,755 @@ +{ + "Registrations": [ + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "DotNetAnalyzers.DocumentationAnalyzers.Unstable", + "Version": "1.0.0.59" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "DotNetAnalyzers.DocumentationAnalyzers", + "Version": "1.0.0-beta.59" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Humanizer.Core", + "Version": "2.14.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Json.More.Net", + "Version": "2.1.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "JsonPointer.Net", + "Version": "5.3.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "JsonSchema.Net", + "Version": "7.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Markdig.Signed", + "Version": "0.45.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.ApplicationInsights", + "Version": "2.23.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Bcl.AsyncInterfaces", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.CodeAnalysis.Analyzers", + "Version": "3.11.0" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.CodeAnalysis.Common", + "Version": "5.0.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.CodeAnalysis.CSharp", + "Version": "5.0.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Extensions.ObjectPool", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Management.Infrastructure.Runtime.Win", + "Version": "3.0.0" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.PowerShell.MarkdownRender", + "Version": "7.2.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Security.Extensions", + "Version": "1.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Win32.Registry.AccessControl", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Win32.SystemEvents", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Windows.Compatibility", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Newtonsoft.Json", + "Version": "13.0.4" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.android-arm.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.android-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.android-x86.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.native.System.Data.SqlClient.sni", + "Version": "4.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.win-arm64.runtime.native.System.Data.SqlClient.sni", + "Version": "4.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.win-x64.runtime.native.System.Data.SqlClient.sni", + "Version": "4.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.win-x86.runtime.native.System.Data.SqlClient.sni", + "Version": "4.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "StyleCop.Analyzers.Unstable", + "Version": "1.2.0.556" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "StyleCop.Analyzers", + "Version": "1.1.118" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.CodeDom", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ComponentModel.Composition.Registration", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ComponentModel.Composition", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Configuration.ConfigurationManager", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Data.Odbc", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Data.OleDb", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Data.SqlClient", + "Version": "4.9.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Diagnostics.EventLog", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Diagnostics.PerformanceCounter", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.DirectoryServices.AccountManagement", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.DirectoryServices.Protocols", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.DirectoryServices", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Drawing.Common", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.IO.Packaging", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Management", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Net.Http.WinHttpHandler", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Reflection.Context", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Runtime.Caching", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.Cryptography.Pkcs", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.Cryptography.ProtectedData", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.Cryptography.Xml", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.Permissions", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.Http", + "Version": "10.0.652802" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.NetFramingBase", + "Version": "10.0.652802" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.NetTcp", + "Version": "10.0.652802" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.Primitives", + "Version": "10.0.652802" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.Syndication", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceProcess.ServiceController", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Speech", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Web.Services.Description", + "Version": "8.1.2" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Windows.Extensions", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + } + ], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" +} diff --git a/tools/clearlyDefined/ClearlyDefined.ps1 b/tools/clearlyDefined/ClearlyDefined.ps1 index 1830c2969e5..c5303b8622b 100644 --- a/tools/clearlyDefined/ClearlyDefined.ps1 +++ b/tools/clearlyDefined/ClearlyDefined.ps1 @@ -21,7 +21,7 @@ if ($ForceModuleReload) { Import-Module -Name "$PSScriptRoot/src/ClearlyDefined" @extraParams -$cgManfest = Get-Content "$PSScriptRoot/../cgmanifest.json" | ConvertFrom-Json +$cgManfest = Get-Content "$PSScriptRoot/../cgmanifest/main/cgmanifest.json" | ConvertFrom-Json $fullCgList = $cgManfest.Registrations.Component | ForEach-Object { [Pscustomobject]@{ diff --git a/tools/clearlyDefined/Find-LastHarvestedVersion.ps1 b/tools/clearlyDefined/Find-LastHarvestedVersion.ps1 new file mode 100644 index 00000000000..a989a3e1fc4 --- /dev/null +++ b/tools/clearlyDefined/Find-LastHarvestedVersion.ps1 @@ -0,0 +1,156 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +<# +.SYNOPSIS + Find the last harvested version of a NuGet package from ClearlyDefined. + +.DESCRIPTION + Searches for the last harvested version of a package by checking versions + backwards from the specified current version. This is useful for reverting + to a known-good harvested version when a newer version hasn't been harvested yet. + +.PARAMETER Name + The NuGet package name to search for. + +.PARAMETER CurrentVersion + The version to start searching backwards from. Version comparison uses semantic versioning. + +.PARAMETER PackageSourceName + The NuGet package source name to use when searching for available versions. + Default is 'findMissingNoticesNugetOrg' if not specified. + +.EXAMPLE + Find-LastHarvestedVersion -Name "Microsoft.Windows.Compatibility" -CurrentVersion "8.0.24" + + # This will return "8.0.22" if that's the last harvested version + +.NOTES + Requires the ClearlyDefined module to be imported: + Import-Module ".\clearlyDefined\src\ClearlyDefined" -Force +#> + +function Find-LastHarvestedVersion { + [CmdletBinding()] + param( + [parameter(Mandatory)] + [string]$Name, + + [parameter(Mandatory)] + [string]$CurrentVersion, + + [string]$PackageSourceName = 'findMissingNoticesNugetOrg' + ) + + try { + Write-Verbose "Finding last harvested version for $Name starting from v$CurrentVersion..." + + # Parse the current version + try { + [System.Management.Automation.SemanticVersion]$currentSemVer = $CurrentVersion + } catch { + [Version]$currentSemVer = $CurrentVersion + } + + # First try the ClearlyDefined search API (more efficient) + try { + Write-Verbose "Searching ClearlyDefined API for versions of $Name (sorted by release date)..." + # Get versions sorted by release date descending (newest first) for efficiency + $versions = Get-ClearlyDefinedPackageVersions -PackageName $Name + + if ($versions -and $versions.Count -gt 0) { + # Results are already sorted by release date newest first + # Filter to versions <= current version + foreach ($versionInfo in $versions) { + try { + $versionObj = [System.Management.Automation.SemanticVersion]$versionInfo.Version + if ($versionObj -le $currentSemVer) { + # Check harvest status + if ($versionInfo.Harvested) { + Write-Verbose "Found harvested version: v$($versionInfo.Version)" + return $versionInfo.Version + } else { + Write-Verbose "v$($versionInfo.Version) - Not harvested, continuing..." + } + } + } catch { + # Skip versions that can't be parsed + } + } + + Write-Verbose "No harvested version found in ClearlyDefined results" + return $null + } + } catch { + Write-Verbose "ClearlyDefined search API failed ($_), falling back to NuGet search..." + } + + # Fallback: Get all available versions from NuGet and check individually + Write-Verbose "Falling back to NuGet source search..." + + # Ensure package source exists + if (!(Get-PackageSource -Name $PackageSourceName -ErrorAction SilentlyContinue)) { + Write-Verbose "Registering package source: $PackageSourceName" + $null = Register-PackageSource -Name $PackageSourceName -Location https://www.nuget.org/api/v2 -ProviderName NuGet + } + + # Get all available versions from NuGet + try { + $allVersions = Find-Package -Name $Name -AllowPrereleaseVersions -source $PackageSourceName -AllVersions -ErrorAction SilentlyContinue | ForEach-Object { + try { + $packageVersion = [System.Management.Automation.SemanticVersion]$_.Version + } catch { + $packageVersion = [Version]$_.Version + } + $_ | Add-Member -Name SemVer -MemberType NoteProperty -Value $packageVersion -PassThru + } | Where-Object { $_.SemVer -le $currentSemVer } | Sort-Object -Property SemVer -Descending | ForEach-Object { $_.Version } + } catch { + Write-Warning "Failed to get versions for $Name : $_" + return $null + } + + if (!$allVersions) { + Write-Verbose "No versions found for $Name" + return $null + } + + # Check each version backwards until we find one that's harvested + foreach ($version in $allVersions) { + $pkg = [PSCustomObject]@{ + type = "nuget" + Name = $Name + PackageVersion = $version + } + + try { + $result = $pkg | Get-ClearlyDefinedData + if ($result -and $result.harvested) { + Write-Verbose "Found harvested version: v$version" + return $version + } else { + Write-Verbose "v$version - Not harvested, continuing..." + } + } catch { + Write-Verbose "Error checking v$version : $_" -Verbose + } + } + + Write-Verbose "No harvested version found for $Name" + return $null + } finally { + Save-ClearlyDefinedCache + } +} + +# If this script is called directly (not sourced), run a test +if ($MyInvocation.InvocationName -eq '.' -or $MyInvocation.Line -like '. "*Find-LastHarvestedVersion*') { + # Script was sourced, just load the function +} else { + # Script was called directly + Write-Host "Testing Find-LastHarvestedVersion function..." + Write-Host "Ensure ClearlyDefined module is loaded first:" + Write-Host ' Import-Module ".\clearlydefined\src\ClearlyDefined" -Force' + Write-Host "" + Write-Host "Example usage:" + Write-Host ' Find-LastHarvestedVersion -Name "Microsoft.Windows.Compatibility" -CurrentVersion "8.0.24"' +} diff --git a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 index 4d874402977..4e3d375dc5a 100644 --- a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 +++ b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 @@ -2,6 +2,9 @@ # Licensed under the MIT License. # Start the collection (known as harvest) of ClearlyDefined data for a package + +$retryIntervalSec = 90 +$maxRetryCount = 5 function Start-ClearlyDefinedHarvest { [CmdletBinding()] param( @@ -27,7 +30,9 @@ function Start-ClearlyDefinedHarvest { $coordinates = Get-ClearlyDefinedCoordinates @PSBoundParameters $body = @{tool='package';coordinates=$coordinates} | convertto-json Write-Verbose $body -Verbose - (Invoke-WebRequest -Method Post -Uri 'https://api.clearlydefined.io/harvest' -Body $body -ContentType 'application/json' -MaximumRetryCount 5 -RetryIntervalSec 60 -Verbose).Content + Start-job -ScriptBlock { + Invoke-WebRequest -Method Post -Uri 'https://api.clearlydefined.io/harvest' -Body $using:body -ContentType 'application/json' -MaximumRetryCount $using:maxRetryCount -RetryIntervalSec $using:retryIntervalSec + } } } @@ -74,6 +79,207 @@ Function Get-ClearlyDefinedCoordinates { # Cache of ClearlyDefined data $cdCache = @{} +function Test-ClearlyDefinedCachePersistenceAllowed { + [CmdletBinding()] + param() + + if ($env:TF_BUILD -or $env:ADO_BUILD_ID -or $env:BUILD_BUILDID) { + return $false + } + + if ($env:GITHUB_ACTIONS -or $env:GITHUB_RUN_ID) { + return $false + } + + return $true +} + +function Get-ClearlyDefinedCachePath { + [CmdletBinding()] + param() + + $tempPath = [System.IO.Path]::GetTempPath() + return (Join-Path -Path $tempPath -ChildPath 'clearlydefined-cache.json') +} + +function Save-ClearlyDefinedCache { + [CmdletBinding()] + param() + + if (-not (Test-ClearlyDefinedCachePersistenceAllowed)) { + Write-Verbose 'Skipping cache persistence for CI environment.' + return + } + + if ($cdCache.Count -eq 0) { + Write-Verbose 'No cache entries to persist.' + return + } + + $cachePath = Get-ClearlyDefinedCachePath + $entries = foreach ($key in $cdCache.Keys) { + [PSCustomObject]@{ + coordinates = $key + data = $cdCache[$key] + } + } + + $cachePayload = @{ + savedAtUtc = (Get-Date).ToUniversalTime() + entries = $entries + } | ConvertTo-Json -Depth 20 + + $cachePayload | Set-Content -Path $cachePath -Encoding UTF8 + Write-Verbose "Persisted cache to $cachePath" +} + +function Import-ClearlyDefinedCache { + [CmdletBinding()] + param() + + if (-not (Test-ClearlyDefinedCachePersistenceAllowed)) { + Write-Verbose 'Skipping cache import for CI environment.' + return + } + + $cachePath = Get-ClearlyDefinedCachePath + if (-not (Test-Path -Path $cachePath)) { + Write-Verbose 'No persisted cache found.' + return + } + + try { + $payload = Get-Content -Path $cachePath -Raw | ConvertFrom-Json + } catch { + Write-Verbose "Failed to read cache file: $cachePath" + return + } + + if (-not $payload.entries) { + Write-Verbose 'Cache file did not contain entries.' + return + } + + foreach ($entry in $payload.entries) { + if (-not $entry.coordinates -or -not $entry.data) { + continue + } + + try { + $entry.data.cachedTime = [datetime]$entry.data.cachedTime + } catch { + continue + } + + $cdCache[$entry.coordinates] = $entry.data + } + + Write-Verbose "Imported $($cdCache.Count) cache entries from $cachePath" +} + +# Search for packages in ClearlyDefined +Function Search-ClearlyDefined { + [CmdletBinding()] + param( + [string]$Type = 'nuget', + [string]$Provider = 'nuget', + [string]$Namespace, + [string]$Name, + [string]$Pattern, + [datetime]$ReleasedAfter, + [datetime]$ReleasedBefore, + [ValidateSet('releaseDate', 'name')] + [string]$Sort, + [switch]$SortDesc + ) + + $queryParams = @() + if ($Type) { $queryParams += "type=$([System.Uri]::EscapeDataString($Type))" } + if ($Provider) { $queryParams += "provider=$([System.Uri]::EscapeDataString($Provider))" } + if ($Namespace) { $queryParams += "namespace=$([System.Uri]::EscapeDataString($Namespace))" } + if ($Name) { $queryParams += "name=$([System.Uri]::EscapeDataString($Name))" } + if ($Pattern) { $queryParams += "pattern=$([System.Uri]::EscapeDataString($Pattern))" } + if ($ReleasedAfter) { $queryParams += "releasedAfter=$($ReleasedAfter.ToString('o'))" } + if ($ReleasedBefore) { $queryParams += "releasedBefore=$($ReleasedBefore.ToString('o'))" } + if ($Sort) { $queryParams += "sort=$([System.Uri]::EscapeDataString($Sort))" } + if ($SortDesc) { $queryParams += "sortDesc=true" } + + $searchUri = "https://api.clearlydefined.io/definitions?" + ($queryParams -join '&') + Write-Verbose "Searching ClearlyDefined: $searchUri" + + try { + $results = Invoke-RestMethod -Uri $searchUri -MaximumRetryCount $maxRetryCount -RetryIntervalSec $retryIntervalSec + return $results + } catch { + if ($retryIntervalSec -lt 300) { + $retryIntervalSec++ + } + + Write-Warning "Failed to search ClearlyDefined: $_" + return $null + } +} + +# Get available versions for a NuGet package with harvest status +Function Get-ClearlyDefinedPackageVersions { + [CmdletBinding()] + param( + [parameter(mandatory = $true)] + [string] + $PackageName, + + [validateset('nuget')] + [string] + $PackageType = 'nuget' + ) + + # Search for all definitions of this package, sorted by release date (newest first) + Write-Verbose "Fetching versions of $PackageName from ClearlyDefined..." + + $results = Search-ClearlyDefined -Type $PackageType -Provider nuget -Name $PackageName -Sort releaseDate -SortDesc + + if (!$results) { + Write-Verbose "No results found for $PackageName" + return @() + } + + # Convert results to version info objects + $versions = @() + + # API returns results in different formats depending on the query + $dataArray = $null + if ($results.data) { + $dataArray = $results.data + } elseif ($results -is [array]) { + $dataArray = $results + } elseif ($results.PSObject.Properties.Count -gt 0) { + # If it's an object with properties, try to extract the actual results + foreach ($prop in $results.PSObject.Properties) { + if ($prop.Value -is [object] -and $prop.Value.revision) { + $dataArray += $prop.Value + } + } + } + + if ($dataArray) { + foreach ($item in $dataArray) { + if ($item.revision) { + $harvested = if ($item.licensed -and $item.licensed.declared) { $true } else { $false } + + $versions += [PSCustomObject]@{ + Name = $item.name + Version = $item.revision + Harvested = $harvested + Licensed = $item.licensed.declared + } + } + } + } + + # Results are already sorted by API, no need to re-sort + return $versions +} + # Get the ClearlyDefined data for a package Function Get-ClearlyDefinedData { [CmdletBinding()] @@ -96,8 +302,9 @@ Function Get-ClearlyDefinedData { ) Begin { - $cacheMinutes = 60 - $cacheCutoff = (get-date).AddMinutes(-$cacheMinutes) + # Different TTLs for different cache types + $harvestedCacheMinutes = 60 # Cache positive results for 60 minutes + $nonHarvestedCacheMinutes = 30 # Cache negative results for 30 minutes (less aggressive) $coordinateList = @() } @@ -111,19 +318,55 @@ Function Get-ClearlyDefinedData { foreach($coordinates in $coordinateList) { Write-Progress -Activity "Getting ClearlyDefined data" -Status "Getting data for $coordinates" -PercentComplete (($completed / $total) * 100) $containsKey = $cdCache.ContainsKey($coordinates) - if ($containsKey -and $cdCache[$coordinates].cachedTime -gt $cacheCutoff) { - Write-Verbose "Returning cached data for $coordinates" - Write-Output $cdCache[$coordinates] - continue + + if ($containsKey) { + $cached = $cdCache[$coordinates] + # Check if cache entry is still valid based on its type + $cacheCutoff = if ($cached.harvestedResult) { + (get-date).AddMinutes(-$harvestedCacheMinutes) + } else { + (get-date).AddMinutes(-$nonHarvestedCacheMinutes) + } + + if ($cached.cachedTime -gt $cacheCutoff) { + Write-Progress -Activity "Getting ClearlyDefined data" -Status "Getting data for $coordinates - cache hit" -PercentComplete (($completed / $total) * 100) + Write-Verbose "Returning cached data for $coordinates (harvested: $($cached.harvestedResult))" + Write-Output $cached + $completed++ + continue + } } - Invoke-RestMethod -Uri "https://api.clearlydefined.io/definitions/$coordinates" -MaximumRetryCount 5 -RetryIntervalSec 60 | ForEach-Object { - [bool] $harvested = if ($_.licensed.declared) { $true } else { $false } - Add-Member -NotePropertyName cachedTime -NotePropertyValue (get-date) -InputObject $_ -PassThru | Add-Member -NotePropertyName harvested -NotePropertyValue $harvested -PassThru - if ($_.harvested) { - Write-Verbose "Caching data for $coordinates" - $cdCache[$coordinates] = $_ + Write-Progress -Activity "Getting ClearlyDefined data" -Status "Getting data for $coordinates - cache miss" -PercentComplete (($completed / $total) * 100) + + try { + Invoke-RestMethod -Uri "https://api.clearlydefined.io/definitions/$coordinates" -MaximumRetryCount $maxRetryCount -RetryIntervalSec $retryIntervalSec | ForEach-Object { + [bool] $harvested = if ($_.licensed.declared) { $true } else { $false } + # Always cache, with harvestedResult property to distinguish for TTL purposes + Add-Member -NotePropertyName cachedTime -NotePropertyValue (get-date) -InputObject $_ -PassThru | + Add-Member -NotePropertyName harvested -NotePropertyValue $harvested -PassThru | + Add-Member -NotePropertyName harvestedResult -NotePropertyValue $harvested -PassThru | + ForEach-Object { + Write-Verbose "Caching data for $coordinates (harvested: $($_.harvested))" + $cdCache[$coordinates] = $_ + Write-Output $_ + } + } + } catch { + if ($retryIntervalSec -lt 300) { + $retryIntervalSec++ + } + + Write-Warning "Failed to get ClearlyDefined data for $coordinates : $_" + # Return a minimal object indicating failure/not harvested so the pipeline continues + $failedResult = [PSCustomObject]@{ + coordinates = $coordinates + harvested = $false + harvestedResult = $false + cachedTime = (get-date) + licensed = @{ declared = $null } } + Write-Output $failedResult } $completed++ } @@ -134,4 +377,10 @@ Export-ModuleMember -Function @( 'Start-ClearlyDefinedHarvest' 'Get-ClearlyDefinedData' 'ConvertFrom-ClearlyDefinedCoordinates' + 'Search-ClearlyDefined' + 'Get-ClearlyDefinedPackageVersions' + 'Save-ClearlyDefinedCache' + 'Import-ClearlyDefinedCache' + 'Test-ClearlyDefinedCachePersistenceAllowed' + 'Get-ClearlyDefinedCachePath' ) diff --git a/tools/findMissingNotices.ps1 b/tools/findMissingNotices.ps1 index 3200bdeeaaf..e5695fdf0d0 100644 --- a/tools/findMissingNotices.ps1 +++ b/tools/findMissingNotices.ps1 @@ -7,12 +7,14 @@ param( [switch] $Fix, - [switch] $IsStable + [switch] $IsStable, + [switch] $ForceHarvestedOnly ) Import-Module dotnet.project.assets Import-Module "$PSScriptRoot\..\.github\workflows\GHWorkflowHelper" -Force . "$PSScriptRoot\..\tools\buildCommon\startNativeExecution.ps1" +. "$PSScriptRoot\clearlyDefined\Find-LastHarvestedVersion.ps1" $packageSourceName = 'findMissingNoticesNugetOrg' if (!(Get-PackageSource -Name $packageSourceName -ErrorAction SilentlyContinue)) { @@ -20,7 +22,7 @@ if (!(Get-PackageSource -Name $packageSourceName -ErrorAction SilentlyContinue)) } $existingRegistrationTable = @{} -$cgManifestPath = (Resolve-Path -Path $PSScriptRoot\..\tools\cgmanifest.json).ProviderPath +$cgManifestPath = (Resolve-Path -Path $PSScriptRoot\cgmanifest\main\cgmanifest.json).ProviderPath $existingRegistrationsJson = Get-Content $cgManifestPath | ConvertFrom-Json -AsHashtable $existingRegistrationsJson.Registrations | ForEach-Object { $registration = [Registration]$_ @@ -335,8 +337,91 @@ if ($IsStable) { } $count = $newRegistrations.Count +$registrationsToSave = $newRegistrations +$tpnRegistrationsToSave = $null + +# If -ForceHarvestedOnly is specified with -Fix, only include harvested packages +# and revert non-harvested packages to their previous versions +if ($Fix -and $ForceHarvestedOnly) { + Write-Verbose "Checking harvest status and filtering to harvested packages with reversion..." -Verbose + + # Import ClearlyDefined module to check harvest status + Import-Module -Name "$PSScriptRoot/clearlyDefined/src/ClearlyDefined" -Force + + # Import cache from previous runs to speed up lookups + Import-ClearlyDefinedCache + + # Get harvest data for all registrations + $fullCgList = $newRegistrations | + ForEach-Object { + [PSCustomObject]@{ + type = $_.Component.Type + Name = $_.Component.Nuget.Name + PackageVersion = $_.Component.Nuget.Version + } + } + + $fullList = $fullCgList | Get-ClearlyDefinedData + + # Build a lookup table of harvest status by package name + version + $harvestStatus = @{} + foreach ($item in $fullList) { + $key = "$($item.Name)|$($item.PackageVersion)" + $harvestStatus[$key] = $item.harvested + } + + # Build a lookup table of old versions from existing manifest + $oldVersions = @{} + foreach ($registration in $existingRegistrationsJson.Registrations) { + $name = $registration.Component.Nuget.Name + if (!$oldVersions.ContainsKey($name)) { + $oldVersions[$name] = $registration + } + } + + # Process each new registration: keep harvested, revert non-harvested + $tpnRegistrationsToSave = @() + $harvestedCount = 0 + $revertedCount = 0 + + foreach ($reg in $newRegistrations) { + $name = $reg.Component.Nuget.Name + $version = $reg.Component.Nuget.Version + $key = "$name|$version" + + if ($harvestStatus.ContainsKey($key) -and $harvestStatus[$key]) { + # Package is harvested, include it + $tpnRegistrationsToSave += $reg + $harvestedCount++ + } else { + # Package not harvested, find last harvested version + $lastHarvestedVersion = Find-LastHarvestedVersion -Name $name -CurrentVersion $version + + # Use last harvested version if found, otherwise use old version as fallback + if ($lastHarvestedVersion) { + if ($lastHarvestedVersion -ne $version) { + $revertedReg = New-NugetComponent -Name $name -Version $lastHarvestedVersion -DevelopmentDependency:$reg.DevelopmentDependency + $tpnRegistrationsToSave += $revertedReg + $revertedCount++ + Write-Verbose "Reverted $name from v$version to last harvested v$lastHarvestedVersion" -Verbose + } else { + $tpnRegistrationsToSave += $reg + } + } elseif ($oldVersions.ContainsKey($name)) { + $tpnRegistrationsToSave += $oldVersions[$name] + $revertedCount++ + Write-Verbose "Reverted $name to previous version (no harvested version found)" -Verbose + } else { + Write-Warning "$name v$version not harvested and no previous version found. Excluding from manifest." + } + } + } + + Write-Verbose "Completed filtering for TPN: $harvestedCount harvested + $revertedCount reverted = $($tpnRegistrationsToSave.Count) total" -Verbose +} + $newJson = @{ - Registrations = $newRegistrations + Registrations = $registrationsToSave '$schema' = "https://json.schemastore.org/component-detection-manifest.json" } | ConvertTo-Json -depth 99 @@ -345,6 +430,149 @@ if ($Fix -and $registrationChanged) { Set-GWVariable -Name CGMANIFEST_PATH -Value $cgManifestPath } +# If -ForceHarvestedOnly was used, write the TPN manifest with filtered registrations +if ($Fix -and $ForceHarvestedOnly -and $tpnRegistrationsToSave.Count -gt 0) { + $tpnManifestDir = Join-Path -Path $PSScriptRoot -ChildPath "cgmanifest\tpn" + New-Item -ItemType Directory -Path $tpnManifestDir -Force | Out-Null + $tpnManifestPath = Join-Path -Path $tpnManifestDir -ChildPath "cgmanifest.json" + + $tpnManifest = @{ + Registrations = @($tpnRegistrationsToSave) + '$schema' = "https://json.schemastore.org/component-detection-manifest.json" + } + + $tpnJson = $tpnManifest | ConvertTo-Json -depth 99 + $tpnJson | Set-Content $tpnManifestPath -Encoding utf8NoBOM + Write-Verbose "TPN manifest created/updated with $($tpnRegistrationsToSave.Count) registrations (filtered for harvested packages)" -Verbose +} + +# Skip legacy TPN update when -ForceHarvestedOnly already produced a filtered manifest +if ($Fix -and $registrationChanged -and -not $ForceHarvestedOnly) { + # Import ClearlyDefined module to check harvest status + Write-Verbose "Checking harvest status for newly added packages..." -Verbose + Import-Module -Name "$PSScriptRoot/clearlyDefined/src/ClearlyDefined" -Force + + # Get harvest data for all registrations + $fullCgList = $newRegistrations | + ForEach-Object { + [PSCustomObject]@{ + type = $_.Component.Type + Name = $_.Component.Nuget.Name + PackageVersion = $_.Component.Nuget.Version + } + } + + $fullList = $fullCgList | Get-ClearlyDefinedData + $needHarvest = $fullList | Where-Object { !$_.harvested } + + if ($needHarvest.Count -gt 0) { + Write-Verbose "Found $($needHarvest.Count) packages that need harvesting. Starting harvest..." -Verbose + $needHarvest | Select-Object -ExpandProperty coordinates | ConvertFrom-ClearlyDefinedCoordinates | Start-ClearlyDefinedHarvest + } else { + Write-Verbose "All packages are already harvested." -Verbose + } + + # After manifest update and harvest, update TPN manifest with individual package status + Write-Verbose "Updating TPN manifest with individual package harvest status..." -Verbose + $tpnManifestDir = Join-Path -Path $PSScriptRoot -ChildPath "cgmanifest\tpn" + $tpnManifestPath = Join-Path -Path $tpnManifestDir -ChildPath "cgmanifest.json" + + # Load current TPN manifest to get previous versions + $currentTpnManifest = @() + if (Test-Path $tpnManifestPath) { + $currentTpnJson = Get-Content $tpnManifestPath | ConvertFrom-Json -AsHashtable + $currentTpnManifest = $currentTpnJson.Registrations + } + + # Build a lookup table of old versions + $oldVersions = @{} + foreach ($registration in $currentTpnManifest) { + $name = $registration.Component.Nuget.Name + if (!$oldVersions.ContainsKey($name)) { + $oldVersions[$name] = $registration + } + } + + # Note: Do not recheck harvest status here. Harvesting is an async process that takes a significant amount of time. + # Use the harvest data from the initial check. Newly triggered harvests will be captured + # on the next run of this script after harvesting completes. + $finalHarvestData = $fullList + + # Update packages individually based on harvest status + $tpnRegistrations = @() + $harvestedCount = 0 + $restoredCount = 0 + + foreach ($item in $finalHarvestData) { + $matchingNewRegistration = $newRegistrations | Where-Object { + $_.Component.Nuget.Name -eq $item.Name -and + $_.Component.Nuget.Version -eq $item.PackageVersion + } + + if ($matchingNewRegistration) { + if ($item.harvested) { + # Use new harvested version + $tpnRegistrations += $matchingNewRegistration + $harvestedCount++ + } else { + # Package not harvested - find the last harvested version from ClearlyDefined API + Write-Verbose "Finding last harvested version for $($item.Name)..." -Verbose + + $lastHarvestedVersion = $null + try { + # Search through all versions of this package to find the last harvested one + # Create a list of versions we know about from all runtimes + $packageVersionsToCheck = $newRegistrations | Where-Object { + $_.Component.Nuget.Name -eq $item.Name + } | ForEach-Object { $_.Component.Nuget.Version } | Sort-Object -Unique -Descending + + foreach ($versionToCheck in $packageVersionsToCheck) { + $versionCheckList = [PSCustomObject]@{ + type = "nuget" + Name = $item.Name + PackageVersion = $versionToCheck + } + + $versionStatus = $versionCheckList | Get-ClearlyDefinedData + if ($versionStatus -and $versionStatus.harvested) { + $lastHarvestedVersion = $versionToCheck + break # Found the most recent harvested version + } + } + } catch { + Write-Verbose "Error checking harvested versions for $($item.Name): $_" -Verbose + } + + # Use last harvested version if found, otherwise use old version as fallback + if ($lastHarvestedVersion) { + $revertedReg = New-NugetComponent -Name $item.Name -Version $lastHarvestedVersion -DevelopmentDependency:$matchingNewRegistration.DevelopmentDependency + $tpnRegistrations += $revertedReg + $restoredCount++ + Write-Verbose "Reverted $($item.Name) from v$($item.PackageVersion) to last harvested v$lastHarvestedVersion" -Verbose + } elseif ($oldVersions.ContainsKey($item.Name)) { + $tpnRegistrations += $oldVersions[$item.Name] + $restoredCount++ + Write-Verbose "Reverted $($item.Name) to previous version in TPN (no harvested version found)" -Verbose + } else { + Write-Warning "$($item.Name) v$($item.PackageVersion) not harvested and no harvested version found. Excluding from TPN manifest." + } + } + } + } + + # Save updated TPN manifest + if ($tpnRegistrations.Count -gt 0) { + $tpnManifest = @{ + Registrations = @($tpnRegistrations) + '$schema' = "https://json.schemastore.org/component-detection-manifest.json" + } + + $tpnJson = $tpnManifest | ConvertTo-Json -depth 99 + $tpnJson | Set-Content $tpnManifestPath -Encoding utf8NoBOM + Write-Verbose "TPN manifest updated: $harvestedCount new harvested + $restoredCount reverted to last harvested versions" -Verbose + } +} + if (!$Fix -and $registrationChanged) { $temp = Get-GWTempPath diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 3d001aaba34..65414612101 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4903,7 +4903,7 @@ function New-GlobalToolNupkgSource } # Set VSTS environment variable for CGManifest file path. - $globalToolCGManifestPFilePath = Join-Path -Path "$env:REPOROOT" -ChildPath "tools\cgmanifest.json" + $globalToolCGManifestPFilePath = Join-Path -Path "$env:REPOROOT" -ChildPath "tools/cgmanifest/main/cgmanifest.json" $globalToolCGManifestFilePath = Resolve-Path -Path $globalToolCGManifestPFilePath -ErrorAction SilentlyContinue if (($null -eq $globalToolCGManifestFilePath) -or (! (Test-Path -Path $globalToolCGManifestFilePath))) { From e0b61278af925f2f217da47c6a0b1a072fb88dac Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 9 Mar 2026 16:21:31 -0700 Subject: [PATCH 216/275] [release/v7.5] Hardcode Official templates (#26968) --- .../PowerShell-Coordinated_Packages-Official.yml | 14 +++++--------- .pipelines/PowerShell-Packages-Official.yml | 11 +++-------- .pipelines/PowerShell-Release-Official-Azure.yml | 9 ++------- .pipelines/PowerShell-Release-Official.yml | 11 +++-------- .pipelines/PowerShell-vPack-Official.yml | 9 ++------- 5 files changed, 15 insertions(+), 39 deletions(-) diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 7e9c44edac8..9be4baff1c1 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -25,11 +25,8 @@ parameters: displayName: Enable MSBuild Binary Logs type: boolean default: false - - name: OfficialBuild - type: boolean - default: false -name: bins-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) +name: bins-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) resources: repositories: @@ -76,10 +73,9 @@ variables: value: ${{ parameters.SKIP_SIGNING }} - group: mscodehub-feed-read-general - group: mscodehub-feed-read-akv + - name: ENABLE_MSBUILD_BINLOGS - name: ENABLE_MSBUILD_BINLOGS value: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} # Fix for BinSkim ICU package error in Linux containers - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT value: true @@ -87,10 +83,10 @@ variables: - name: ob_sdl_binskim_enabled value: false - name: ps_official_build - value: ${{ parameters.OfficialBuild }} + value: true extends: - template: ${{ variables.templateFile }} + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: customTags: 'ES365AIMigrationTooling' featureFlags: @@ -308,4 +304,4 @@ extends: Copy-Item -Path "$(Build.StagingDirectory)\release.json" -Destination "$(ob_outputDirectory)\metadata" -Force displayName: Create and upload release.json file to build artifact retryCountOnTaskFailure: 2 - - template: /.pipelines/templates/step/finalize.yml@self + - template: /.pipelines/templates/step/finalize.yml@self \ No newline at end of file diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 18ef7b2d14c..a13ef12378a 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -24,14 +24,11 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Signing type: string default: 'NO' - - name: OfficialBuild - type: boolean - default: false - name: disableNetworkIsolation type: boolean default: false -name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -67,8 +64,6 @@ variables: - name: branchCounter value: $[counter(variables['branchCounterKey'], 1)] - group: MSIXSigningProfile - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} - name: disableNetworkIsolation value: ${{ parameters.disableNetworkIsolation }} @@ -89,7 +84,7 @@ resources: ref: refs/heads/main extends: - template: ${{ variables.templateFile }} + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: cloudvault: enabled: false @@ -294,7 +289,7 @@ extends: jobs: - template: /.pipelines/templates/package-create-msix.yml@self parameters: - OfficialBuild: ${{ parameters.OfficialBuild }} + OfficialBuild: true - stage: upload displayName: 'Upload' diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index f4c41143b5f..81543420460 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -13,11 +13,8 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Signing type: string default: 'NO' - - name: OfficialBuild - type: boolean - default: false -name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) +name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -49,8 +46,6 @@ variables: - name: LinuxContainerImage value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - group: PoolNames - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} resources: repositories: @@ -72,7 +67,7 @@ resources: - releases/* extends: - template: ${{ variables.templateFile }} + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: featureFlags: WindowsHostVersion: diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 62b6a78ff19..02a255a1db6 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -29,11 +29,8 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip MSIX Publish type: boolean default: false - - name: OfficialBuild - type: boolean - default: false -name: release-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) +name: release-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -65,10 +62,8 @@ variables: - name: ReleaseTagVar value: ${{ parameters.ReleaseTagVar }} - group: PoolNames - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} - name: releaseEnvironment - value: ${{ iif ( parameters.OfficialBuild, 'Production', 'Test' ) }} + value: 'Production' # Fix for BinSkim ICU package error in Linux containers - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT value: true @@ -97,7 +92,7 @@ resources: - releases/* extends: - template: ${{ variables.templateFile }} + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: release: category: NonAzure diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 096dfb574a4..fbbf3683db5 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -1,9 +1,6 @@ trigger: none parameters: # parameters are shown up in ADO UI in a build queue time -- name: OfficialBuild - type: boolean - default: true - name: 'createVPack' displayName: 'Create and Submit VPack' type: boolean @@ -33,7 +30,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time - Netlock default: "R1" -name: vPack_$(Build.SourceBranchName)_Prod.${{ parameters.OfficialBuild }}_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) +name: vPack_$(Build.SourceBranchName)_Prod.true_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -58,8 +55,6 @@ variables: value: ${{ parameters.ReleaseTagVar }} - group: Azure Blob variable group - group: certificate_logical_to_actual # used within signing task - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/Microsoft.Official.yml@onebranchTemplates', 'v2/Microsoft.NonOfficial.yml@onebranchTemplates' ) }} - group: DotNetPrivateBuildAccess - group: certificate_logical_to_actual - name: netiso @@ -75,7 +70,7 @@ resources: ref: refs/heads/main extends: - template: ${{ variables.templateFile }} + template: v2/Microsoft.Official.yml@onebranchTemplates parameters: platform: name: 'windows_undocked' # windows undocked From 5e34b61a71c6f5fd7380f43dc6c86a92766bbd0e Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 10 Mar 2026 11:55:49 -0700 Subject: [PATCH 217/275] Update CGManifests (#26981) --- tools/cgmanifest/main/cgmanifest.json | 10 +- tools/cgmanifest/tpn/cgmanifest.json | 254 ++++++++++++++++++-------- 2 files changed, 187 insertions(+), 77 deletions(-) diff --git a/tools/cgmanifest/main/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json index dd6bf54f46d..78f759bddc6 100644 --- a/tools/cgmanifest/main/cgmanifest.json +++ b/tools/cgmanifest/main/cgmanifest.json @@ -1,5 +1,4 @@ { - "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -86,7 +85,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "8.0.0" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -116,7 +115,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "8.0.21" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -656,7 +655,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Metadata", - "Version": "8.0.1" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -861,5 +860,6 @@ }, "DevelopmentDependency": false } - ] + ], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" } diff --git a/tools/cgmanifest/tpn/cgmanifest.json b/tools/cgmanifest/tpn/cgmanifest.json index a0746028a56..78f759bddc6 100644 --- a/tools/cgmanifest/tpn/cgmanifest.json +++ b/tools/cgmanifest/tpn/cgmanifest.json @@ -35,7 +35,7 @@ "Type": "nuget", "Nuget": { "Name": "Json.More.Net", - "Version": "2.1.1" + "Version": "2.0.2" } }, "DevelopmentDependency": false @@ -45,7 +45,7 @@ "Type": "nuget", "Nuget": { "Name": "JsonPointer.Net", - "Version": "5.3.1" + "Version": "5.0.2" } }, "DevelopmentDependency": false @@ -55,7 +55,7 @@ "Type": "nuget", "Nuget": { "Name": "JsonSchema.Net", - "Version": "7.4.0" + "Version": "7.2.3" } }, "DevelopmentDependency": false @@ -65,7 +65,7 @@ "Type": "nuget", "Nuget": { "Name": "Markdig.Signed", - "Version": "0.45.0" + "Version": "0.38.0" } }, "DevelopmentDependency": false @@ -75,7 +75,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.ApplicationInsights", - "Version": "2.23.0" + "Version": "2.22.0" } }, "DevelopmentDependency": false @@ -85,27 +85,17 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "Microsoft.CodeAnalysis.Analyzers", - "Version": "3.11.0" - } - }, - "DevelopmentDependency": true - }, { "Component": { "Type": "nuget", "Nuget": { "Name": "Microsoft.CodeAnalysis.Common", - "Version": "5.0.0" + "Version": "4.11.0" } }, "DevelopmentDependency": false @@ -115,7 +105,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.CodeAnalysis.CSharp", - "Version": "5.0.0" + "Version": "4.11.0" } }, "DevelopmentDependency": false @@ -125,7 +115,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -165,7 +155,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -175,7 +165,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -185,7 +175,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -205,7 +195,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -215,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -225,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -235,7 +225,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -245,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -255,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -265,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -275,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -285,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -295,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -305,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -315,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -325,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -335,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -355,7 +345,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -365,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -375,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -435,7 +425,17 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "10.0.3" + "Version": "9.0.10" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Collections.Immutable", + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -445,7 +445,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -455,7 +455,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -465,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -475,7 +475,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -485,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -500,12 +500,22 @@ }, "DevelopmentDependency": false }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Diagnostics.DiagnosticSource", + "Version": "9.0.10" + } + }, + "DevelopmentDependency": false + }, { "Component": { "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -515,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -525,7 +535,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -535,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -545,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -555,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -565,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -575,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -585,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -595,7 +605,27 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "10.0.3" + "Version": "9.0.10" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Numerics.Vectors", + "Version": "4.5.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Private.ServiceModel", + "Version": "4.10.3" } }, "DevelopmentDependency": false @@ -605,7 +635,27 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "10.0.3" + "Version": "9.0.10" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Reflection.DispatchProxy", + "Version": "4.7.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Reflection.Metadata", + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -615,7 +665,17 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "10.0.3" + "Version": "9.0.10" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.AccessControl", + "Version": "6.0.1" } }, "DevelopmentDependency": false @@ -625,7 +685,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -635,7 +695,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -645,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -655,7 +715,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -664,8 +724,8 @@ "Component": { "Type": "nuget", "Nuget": { - "Name": "System.ServiceModel.Http", - "Version": "10.0.652802" + "Name": "System.Security.Principal.Windows", + "Version": "5.0.0" } }, "DevelopmentDependency": false @@ -674,8 +734,18 @@ "Component": { "Type": "nuget", "Nuget": { - "Name": "System.ServiceModel.NetFramingBase", - "Version": "10.0.652802" + "Name": "System.ServiceModel.Duplex", + "Version": "4.10.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.Http", + "Version": "4.10.3" } }, "DevelopmentDependency": false @@ -685,7 +755,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.NetTcp", - "Version": "10.0.652802" + "Version": "4.10.3" } }, "DevelopmentDependency": false @@ -695,7 +765,17 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Primitives", - "Version": "10.0.652802" + "Version": "4.10.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.Security", + "Version": "4.10.3" } }, "DevelopmentDependency": false @@ -705,7 +785,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -715,7 +795,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -725,7 +805,37 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "10.0.3" + "Version": "9.0.10" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Text.Encoding.CodePages", + "Version": "9.0.10" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Text.Encodings.Web", + "Version": "9.0.10" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Threading.AccessControl", + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -735,7 +845,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Web.Services.Description", - "Version": "8.1.2" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -745,7 +855,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "10.0.3" + "Version": "9.0.10" } }, "DevelopmentDependency": false From dbd6caf19b801b3179748435b7d3859b4ab57a2f Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 10 Mar 2026 15:52:13 -0700 Subject: [PATCH 218/275] [release/v7.5] Fix ConvertFrom-ClearlyDefinedCoordinates to handle API object coordinates (#26987) --- .../src/ClearlyDefined/ClearlyDefined.psm1 | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 index 4e3d375dc5a..88fc1f7cabd 100644 --- a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 +++ b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 @@ -40,19 +40,30 @@ function ConvertFrom-ClearlyDefinedCoordinates { [CmdletBinding()] param( [parameter(mandatory = $true, ValueFromPipeline = $true)] - [string] + [object] $Coordinates ) Begin {} Process { - $parts = $Coordinates.Split('/') - [PSCustomObject]@{ - type = $parts[0] - provider = $parts[1] - namespace = $parts[2] - name = $parts[3] - revision = $parts[4] + if ($Coordinates -is [string]) { + $parts = $Coordinates.Split('/') + [PSCustomObject]@{ + type = $parts[0] + provider = $parts[1] + namespace = $parts[2] + name = $parts[3] + revision = $parts[4] + } + } else { + # Coordinates is already an object (e.g., from ClearlyDefined API response) + [PSCustomObject]@{ + type = $Coordinates.type + provider = $Coordinates.provider + namespace = $Coordinates.namespace + name = $Coordinates.name + revision = $Coordinates.revision + } } } End {} From 7155b0357369f5011cdaceed21be27edfaba09be Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 10 Mar 2026 19:41:34 -0400 Subject: [PATCH 219/275] [release/v7.5] Update branch for release (#26990) --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 8 +- ...soft.PowerShell.Commands.Management.csproj | 4 +- ...crosoft.PowerShell.Commands.Utility.csproj | 8 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 103 ++++++++-------- .../Microsoft.WSMan.Management.csproj | 4 +- .../PSVersionInfoGenerator.csproj | 5 +- .../System.Management.Automation.csproj | 24 ++-- .../BenchmarkDotNet.Extensions.csproj | 11 +- .../ResultsComparer/ResultsComparer.csproj | 11 +- ...soft.PowerShell.NamedPipeConnection.csproj | 26 ++-- test/tools/TestService/TestService.csproj | 97 +++++++-------- test/tools/WebListener/WebListener.csproj | 6 +- tools/cgmanifest/main/cgmanifest.json | 112 +++++++++--------- 16 files changed, 217 insertions(+), 208 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 6f09eb2d6ed..670d68870ea 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "9.0.306", + "sdkImageVersion": "9.0.312", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 345f67e389e..f903f66dc23 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.306" + "version": "9.0.312" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 00eac01d55c..0c53b99662d 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,11 +7,11 @@ - - - + + + - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index d992c2eab25..835483b822b 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 3edc422be02..381bcf2854c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -13,8 +13,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + @@ -41,8 +41,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 04df0482c35..7898716fb97 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 8cb31a949bb..13a377fd85b 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,56 +16,57 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 6195d3a80e1..99859a621e4 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,11 +7,11 @@ - + - + diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index 44449ff15bc..d14e7a41f80 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -17,7 +17,8 @@ - - + + + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index c04785cacf3..399014b9111 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,25 +32,25 @@ - - - - - - + + + + + + - + - - - - + + + + - + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 564f890365b..b5bae18d946 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -10,15 +10,18 @@ + - + - + - + + - + + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index debfbb0e1e3..b76542f6002 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -10,16 +10,19 @@ + - + - + - + + - + + diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index 87fab6299ec..a76f1675d61 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -17,22 +17,22 @@ - + - + - - - - - - + + + + + + - - - - - + + + + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 7a3d777f431..850888b41ff 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,56 +15,57 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index b8f1899736a..e68b3df38da 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,10 +7,10 @@ - - + + - + diff --git a/tools/cgmanifest/main/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json index 78f759bddc6..242178a883d 100644 --- a/tools/cgmanifest/main/cgmanifest.json +++ b/tools/cgmanifest/main/cgmanifest.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -85,7 +86,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -115,7 +116,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -155,7 +156,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -165,7 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -175,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -195,7 +196,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -205,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -215,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -225,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -235,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -245,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -255,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -265,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -275,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -285,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -295,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -305,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -315,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -325,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -345,7 +346,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -355,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -365,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -425,7 +426,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -445,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -455,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -465,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -475,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -485,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -495,7 +496,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.SqlClient", - "Version": "4.9.0" + "Version": "4.9.1" } }, "DevelopmentDependency": false @@ -505,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.DiagnosticSource", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -515,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -525,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -535,7 +536,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -545,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -555,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -565,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -575,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -585,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -595,7 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -605,7 +606,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -635,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -655,7 +656,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Metadata", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -665,7 +666,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -685,7 +686,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -695,7 +696,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -705,7 +706,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -715,7 +716,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -785,7 +786,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -795,7 +796,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -805,7 +806,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -815,7 +816,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encoding.CodePages", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -825,7 +826,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encodings.Web", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -835,7 +836,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false @@ -855,11 +856,10 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.10" + "Version": "9.0.14" } }, "DevelopmentDependency": false } - ], - "$schema": "https://json.schemastore.org/component-detection-manifest.json" + ] } From 67488e6b4e8e9f9593eb1a75aaf9cf7e895d5359 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 11 Mar 2026 02:10:22 +0000 Subject: [PATCH 220/275] Merged PR 38910: Update MaxVisitCount and MaxHashtableKeyCount if visitor safe value context indicates SkipLimitCheck is true Update MaxVisitCount and MaxHashtableKeyCount if visitor safe value context indicates SkipLimitCheck is true Related work items: #163517 --- .../engine/parser/SafeValues.cs | 14 +++++++++----- .../PowerShellData.tests.ps1 | 6 ++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/parser/SafeValues.cs b/src/System.Management.Automation/engine/parser/SafeValues.cs index 05c87daab5b..38181168a66 100644 --- a/src/System.Management.Automation/engine/parser/SafeValues.cs +++ b/src/System.Management.Automation/engine/parser/SafeValues.cs @@ -47,11 +47,15 @@ public static bool IsAstSafe(Ast ast, GetSafeValueVisitor.SafeValueContext safeV internal IsSafeValueVisitor(GetSafeValueVisitor.SafeValueContext safeValueContext) { _safeValueContext = safeValueContext; + + bool skipSizeCheck = safeValueContext is GetSafeValueVisitor.SafeValueContext.SkipHashtableSizeCheck; + _maxVisitCount = skipSizeCheck ? uint.MaxValue : 5000; + _maxHashtableKeyCount = skipSizeCheck ? int.MaxValue : 500; } internal bool IsAstSafe(Ast ast) { - if ((bool)ast.Accept(this) && _visitCount < MaxVisitCount) + if ((bool)ast.Accept(this) && _visitCount < _maxVisitCount) { return true; } @@ -65,8 +69,8 @@ internal bool IsAstSafe(Ast ast) // This is a check of the number of visits private uint _visitCount = 0; - private const uint MaxVisitCount = 5000; - private const int MaxHashtableKeyCount = 500; + private readonly uint _maxVisitCount; + private readonly int _maxHashtableKeyCount; // Used to determine if we are being called within a GetPowerShell() context, // which does some additional security verification outside of the scope of @@ -330,7 +334,7 @@ public object VisitArrayLiteral(ArrayLiteralAst arrayLiteralAst) public object VisitHashtable(HashtableAst hashtableAst) { - if (hashtableAst.KeyValuePairs.Count > MaxHashtableKeyCount) + if (hashtableAst.KeyValuePairs.Count > _maxHashtableKeyCount) { return false; } @@ -373,7 +377,7 @@ public static object GetSafeValue(Ast ast, ExecutionContext context, SafeValueCo { t_context = context; - if (safeValueContext == SafeValueContext.SkipHashtableSizeCheck || IsSafeValueVisitor.IsAstSafe(ast, safeValueContext)) + if (IsSafeValueVisitor.IsAstSafe(ast, safeValueContext)) { return ast.Accept(new GetSafeValueVisitor()); } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 index cfba4a4cbed..148993b69b1 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 @@ -49,4 +49,10 @@ Describe "Tests for the Import-PowerShellDataFile cmdlet" -Tags "CI" { $result = Import-PowerShellDataFile $largePsd1Path -SkipLimitCheck $result.Keys.Count | Should -Be 501 } + + It 'Fails if psd1 file is insecure while -SkipLimitCheck is used' { + $path = Setup -f insecure2.psd1 -Content '@{ Foo = [object] (calc.exe) }' -pass + { Import-PowerShellDataFile $path -SkipLimitCheck -ErrorAction Stop } | + Should -Throw -ErrorId "System.InvalidOperationException,Microsoft.PowerShell.Commands.ImportPowerShellDataFileCommand" + } } From e65d3dc6979cd4817385b47a21d23ca543bc10c1 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 11 Mar 2026 08:40:24 -0700 Subject: [PATCH 221/275] Revert change to module name ThreadJob (#26997) --- .pipelines/templates/windows-hosted-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index b6d64d7a96d..e21d2253887 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -268,7 +268,7 @@ jobs: 'Microsoft.PowerShell.PSResourceGet' 'Microsoft.PowerShell.Archive' 'PSReadLine' - 'Microsoft.PowerShell.ThreadJob' + 'ThreadJob' ) $sourceModulePath = Join-Path '$(GlobalToolArtifactPath)' 'publish' 'PowerShell.Windows.x64' 'release' 'Modules' From 6c861249a0320894f9757ee79a132d8c2cbce8a7 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 11 Mar 2026 12:47:58 -0700 Subject: [PATCH 222/275] [release/v7.5.5] Fix MSIX Stages (#27002) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung --- .pipelines/templates/package-create-msix.yml | 53 +++++++++++++--- .pipelines/templates/release-MSIX-Publish.yml | 61 ++++++++++--------- 2 files changed, 76 insertions(+), 38 deletions(-) diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 4b3b79b65ee..255915ab02c 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -115,13 +115,11 @@ jobs: $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File Write-Verbose -Verbose "Signed bundle: $signedBundle" - # Ensure the destination directory exists - if (-not (Test-Path -Path "$(ob_outputDirectory)")) { - Write-Verbose -Verbose "Creating destination directory: $(ob_outputDirectory)" - New-Item -Path "$(ob_outputDirectory)" -ItemType Directory -Force | Out-Null + if (-not (Test-Path $(ob_outputDirectory))) { + New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force } - Copy-Item -Path $signedBundle.FullName -Destination "$(ob_outputDirectory)\$($signedBundle.Name)" -Verbose + Copy-Item -Path $signedBundle.FullName -Destination "$(ob_outputDirectory)" -Verbose Write-Verbose -Verbose "Uploaded Bundle:" Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose @@ -189,7 +187,7 @@ jobs: # Create namespace manager for XML with default namespace $nsManager = New-Object System.Xml.XmlNamespaceManager($pdpXml.NameTable) $nsManager.AddNamespace("pd", "http://schemas.microsoft.com/appx/2012/ProductDescription") - + $appStoreNameElement = $pdpXml.SelectSingleNode("//pd:AppStoreName", $nsManager) if ($appStoreNameElement) { $appStoreNameElement.SetAttribute("_locID", $config.AppStoreName) @@ -226,17 +224,54 @@ jobs: Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" + + # These variables are used in the next tasks to determine which ServiceEndpoint to use + $ltsValue = $IsLTS.ToString().ToLower() + $stableValue = $IsStable.ToString().ToLower() + $previewValue = $IsPreview.ToString().ToLower() + + Write-Verbose -Verbose "About to set variables:" + Write-Verbose -Verbose " LTS=$ltsValue" + Write-Verbose -Verbose " STABLE=$stableValue" + Write-Verbose -Verbose " PREVIEW=$previewValue" + + Write-Host "##vso[task.setvariable variable=LTS]$ltsValue" + Write-Host "##vso[task.setvariable variable=STABLE]$stableValue" + Write-Host "##vso[task.setvariable variable=PREVIEW]$previewValue" + + Write-Verbose -Verbose "Variables set successfully" name: UpdateConfigs displayName: Update PDPs and SBConfig.json + - pwsh: | + Write-Verbose -Verbose "Checking variables after UpdateConfigs:" + Write-Verbose -Verbose "LTS=$(LTS)" + Write-Verbose -Verbose "STABLE=$(STABLE)" + Write-Verbose -Verbose "PREVIEW=$(PREVIEW)" + displayName: Debug - Check Variables + + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 + displayName: 'Create StoreBroker Package (Preview)' + condition: eq(variables['PREVIEW'], 'true') + inputs: + serviceEndpoint: 'StoreAppPublish-Preview' + sbConfigPath: '$(SBConfigPath)' + sourceFolder: '$(BundleDir)' + contents: '*.msixBundle' + outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 - displayName: 'Create StoreBroker Package' + displayName: 'Create StoreBroker Package (Stable/LTS)' + condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) inputs: - serviceEndpoint: 'StoreAppPublish-Private' + serviceEndpoint: 'StoreAppPublish-Stable' sbConfigPath: '$(SBConfigPath)' sourceFolder: '$(BundleDir)' contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - pwsh: | @@ -261,4 +296,4 @@ jobs: else { Write-Error "Required files not found in $submissionPackageDir" } - displayName: 'Upload StoreBroker Package' \ No newline at end of file + displayName: 'Upload StoreBroker Package' diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index 4d3e0cb41c8..a92c71f826b 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -50,7 +50,7 @@ jobs: $middleURL = $matches[1] } - $endURL = $tagString -replace '^v|\.', '' + $endURL = $tagString -replace '^v','' -replace '\.','' $message = "Changelog: https://github.com/PowerShell/PowerShell/blob/master/CHANGELOG/$middleURL.md#$endURL" Write-Verbose -Verbose "Release Notes for the Store:" Write-Verbose -Verbose "$message" @@ -59,8 +59,15 @@ jobs: $json.listings.'en-us'.baseListing.releaseNotes = $message + # Add PowerShell version to the top of the description + $description = $json.listings.'en-us'.baseListing.description + $version = "$(ReleaseTag)" + $updatedDescription = "Version: $version`n`n$description" + $json.listings.'en-us'.baseListing.description = $updatedDescription + Write-Verbose -Verbose "Updated description: $updatedDescription" + $json | ConvertTo-Json -Depth 100 | Set-Content $jsonPath -Encoding UTF8 - displayName: 'Update Release Notes in JSON' + displayName: 'Add Changelog Link and Version Number to SBJSON' - task: PowerShell@2 inputs: @@ -73,7 +80,6 @@ jobs: Write-Verbose -Verbose "Channel Selection - LTS: $(LTS), Stable: $(STABLE), Preview: $(PREVIEW)" - # Determine the current channel for logging purposes $currentChannel = if ($IsLTS) { 'LTS' } elseif ($IsStable) { 'Stable' } elseif ($IsPreview) { 'Preview' } @@ -81,30 +87,31 @@ jobs: Write-Error "No valid channel detected" exit 1 } - + + # Assign AppID for Store-Publish Task + $appID = $null + if ($IsLTS) { + $appID = '$(AppID-LTS)' + } + elseif ($IsStable) { + $appID = '$(AppID-Stable)' + } + else { + $appID = '$(AppID-Preview)' + } + + Write-Host "##vso[task.setvariable variable=AppID]$appID" Write-Verbose -Verbose "Selected channel: $currentChannel" Write-Verbose -Verbose "Conditional tasks will handle the publishing based on channel variables" displayName: 'Validate Channel Selection' - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 - displayName: 'Publish LTS StoreBroker Package' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['LTS'], 'true')) - inputs: - serviceEndpoint: 'StoreAppPublish-Private' - appId: '$(AppID-LTS)' - inputMethod: JsonAndZip - jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' - zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' - numberOfPackagesToKeep: 2 - jsonZipUpdateMetadata: true - targetPublishMode: 'Immediate' - - - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 - displayName: 'Publish Stable StoreBroker Package' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['STABLE'], 'true')) + displayName: 'Publish StoreBroker Package (Stable/LTS)' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true'))) + continueOnError: true inputs: - serviceEndpoint: 'StoreAppPublish-Private' - appId: '$(AppID-Stable)' + serviceEndpoint: 'StoreAppPublish-Stable' + appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' @@ -113,19 +120,15 @@ jobs: targetPublishMode: 'Immediate' - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 - displayName: 'Publish Preview StoreBroker Package' + displayName: 'Publish StoreBroker Package (Preview)' condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) + continueOnError: true inputs: - serviceEndpoint: 'StoreAppPublish-Private' - appId: '$(AppID-Preview)' + serviceEndpoint: 'StoreAppPublish-Preview' + appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' numberOfPackagesToKeep: 2 jsonZipUpdateMetadata: true targetPublishMode: 'Immediate' - - - pwsh: | - Get-Content -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue - displayName: Upload Store Failure Log - condition: failed() From 7577c8657cded334e85d6df247c57f04e06901fc Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 11 Mar 2026 14:34:42 -0700 Subject: [PATCH 223/275] [Backport release/v7.5.5] Update metadata.json for correctly build and release MSIX (#27009) --- tools/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/metadata.json b/tools/metadata.json index 9930af35579..3d8ba1203fc 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -6,5 +6,5 @@ "LTSReleaseTag" : ["v7.4.13"], "NextReleaseTag": "v7.5.0-preview.4", "LTSRelease": { "PublishToChannels": false, "Package": false }, - "StableRelease": { "PublishToChannels": false, "Package": false } + "StableRelease": { "PublishToChannels": true, "Package": true } } From 7b8792e4e9008e76a009fb9eca4ef6d1488106a4 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Wed, 11 Mar 2026 21:02:37 -0500 Subject: [PATCH 224/275] Try private service connection for package step (#27010) Co-authored-by: Justin Chung --- .pipelines/templates/package-create-msix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 255915ab02c..b6b0ec291de 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -266,7 +266,7 @@ jobs: displayName: 'Create StoreBroker Package (Stable/LTS)' condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) inputs: - serviceEndpoint: 'StoreAppPublish-Stable' + serviceEndpoint: 'StoreAppPublish-Private' sbConfigPath: '$(SBConfigPath)' sourceFolder: '$(BundleDir)' contents: '*.msixBundle' From dd349fca236932fbacf32b7091b41a9da3b76e16 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 12 Mar 2026 08:16:24 -0700 Subject: [PATCH 225/275] [release/v7.5.5] Update change log for v7.5.5 (#27012) --- CHANGELOG/7.5.md | 118 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index e231ce6b0e2..2e34970c248 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -1,5 +1,123 @@ # 7.5 Changelog +## [7.5.5] + +### Engine Updates and Fixes + +- Fix up `SSHConnectionInfo` ssh PATH checks (#26165) (Thanks @jborean93!) + +### General Cmdlet Updates and Fixes + +- Close pipe client handles after creating the child ssh process (#26822) +- Fix the progress preference variable in script cmdlets (#26791) (Thanks @cmkb3!) + +### Tools + +- Add merge conflict marker detection to `linux-ci` workflow and refactor existing actions to use reusable `get-changed-files` action (#26812) +- Add reusable `get-changed-files` action and refactor existing actions (#26811) +- Create GitHub Copilot setup workflow (#26807) +- Refactor analyze job to reusable workflow and enable on Windows CI (#26799) + +### Tests + +- Mark flaky `Update-Help` web tests as pending to unblock CI (#26837) +- Add GitHub Actions annotations for Pester test failures (#26836) +- Fix `$PSDefaultParameterValues` leak causing tests to skip unexpectedly (#26823) +- Fix merge conflict checker for empty file lists and filter `*.cs` files (#26813) +- Update the `Update-Help` tests to use `-Force` to remove read-only files (#26788) +- Add markdown link verification for PRs (#26407) + +### Build and Packaging Improvements + +
+ + +

Update to .NET SDK 9.0.312

+

We thank the following contributors!

+

@kasperk81, @RichardSlater

+ +
+ +
    +
  • Revert change to module name ThreadJob (#26997)
  • +
  • Update branch for release (#26990)
  • +
  • Fix ConvertFrom-ClearlyDefinedCoordinates to handle API object coordinates (#26987)
  • +
  • Update CGManifests (#26981)
  • +
  • Hardcode Official templates (#26968)
  • +
  • Split TPN manifest and Component Governance manifest (#26967)
  • +
  • Fix a preview detection test for the packaging script (#26966)
  • +
  • Correct the package name for .deb and .rpm packages (#26964)
  • +
  • Bring Release Changes from v7.6.0-preview.6 (#26963)
  • +
  • Merge the v7.6.0-preview.5 release branch back to master (#26958)
  • +
  • Fix macOS preview package identifier detection to use version string (#26835)
  • +
  • Update metadata.json to update the Latest attribute with a better name (#26826)
  • +
  • Remove unused runCodesignValidationInjection variable from pipeline templates (#26825)
  • +
  • Update Get-ChangeLog to handle backport PRs correctly (#26824)
  • +
  • Mirror .NET/runtime ICU version range in PowerShell (#26821) (Thanks @kasperk81!)
  • +
  • Update the macos package name for preview releases to match the previous pattern (#26820)
  • +
  • Fix condition syntax for StoreBroker package tasks in MSIX pipeline (#26819)
  • +
  • Fix template path for rebuild branch check in package.yml (#26818)
  • +
  • Add rebuild branch support with conditional MSIX signing (#26817)
  • +
  • Move package validation to package pipeline (#26816)
  • +
  • Optimize/split windows package signing (#26815)
  • +
  • Improve ADO package build and validation across platforms (#26814)
  • +
  • Add log grouping to build.psm1 for collapsible GitHub Actions logs (#26810)
  • +
  • Remove usage of fpm for DEB package generation (#26809)
  • +
  • Replace fpm with native macOS packaging tools (pkgbuild/productbuild) (#26801)
  • +
  • Fix build to only enable ready-to-run for the Release configuration (#26798)
  • +
  • Fix R2R for fxdependent packaging (#26797)
  • +
  • Refactor: Centralize xUnit tests into reusable workflow and remove legacy verification (#26794)
  • +
  • Replace fpm with native rpmbuild for RPM package generation (#26793)
  • +
  • Add libicu76 dependency to support Debian 13 (#26792) (Thanks @RichardSlater!)
  • +
  • Specify .NET search by build type (#26408)
  • +
  • Fix buildinfo.json uploading for preview, LTS, and stable releases (#26773)
  • +
  • Fix path to metadata.json in channel selection script (#26400)
  • +
  • Separate store automation service endpoints and resolve AppID (#26266)
  • +
  • Update a few packages to use the right version corresponding to .NET 9 (#26671)
  • +
  • Add network isolation policy parameter to vPack pipeline (#26393)
  • +
  • Convert Azure DevOps Linux Packaging pipeline to GitHub Actions workflow (#26391)
  • +
  • Integrate Windows packaging into windows-ci workflow using reusable workflow (#26390)
  • +
  • GitHub Workflow cleanup (#26389)
  • +
  • Update vPack name (#26221)
  • +
+ +
+ +[7.5.5]: https://github.com/PowerShell/PowerShell/compare/v7.5.4...v7.5.5 + + +## [7.5.4] + +### Build and Packaging Improvements + +
+ + + +

Update to .NET SDK 9.0.306

+ +
+ +
    +
  • [release/v7.5] Update Ev2 Shell Extension Image to AzureLinux 3 for PMC Release (#26032)
  • +
  • [release/v7.5] Fix variable reference for release environment in pipeline (#26013)
  • +
  • [release/v7.5] Add v7.5.3 Changelog (#26015)
  • +
  • [release/v7.5] Add LinuxHost Network configuration to PowerShell Packages pipeline (#26002)
  • +
  • Backport Release Pipeline Changes (Internal 37168)
  • +
  • [release/v7.5] Update branch for release (#26195)
  • +
  • [release/v7.5] Mark the 3 consistently failing tests as pending to unblock PRs (#26196)
  • +
  • [release/v7.5] add CodeQL suppresion for NativeCommandProcessor (#26173)
  • +
  • [release/v7.5] add CodeQL suppressions for UpdatableHelp and NativeCommandProcessor methods (#26171)
  • +
  • [release/v7.5] Remove UseDotnet task and use the dotnet-install script (#26169)
  • +
  • [release/v7.5] Automate Store Publishing (#26164)
  • +
  • [release/v7.5] Ensure that socket timeouts are set only during the token validation (#26079)
  • +
  • [release/v7.5] Suppress false positive PSScriptAnalyzer warnings in tests and build scripts (#26059)
  • +
+ +
+ +[7.5.4]: https://github.com/PowerShell/PowerShell/compare/v7.5.3...v7.5.4 + ## [7.5.3] ### General Cmdlet Updates and Fixes From ddf61070a09cf1d056ed512a3ae01b8e0b6b0711 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 17:56:12 -0700 Subject: [PATCH 226/275] [release/v7.5.6] Separate Official and NonOfficial templates for ADO pipelines (#27155) --- .github/agents/SplitADOPipelines.agent.md | 164 ++++++++ ...Shell-Coordinated_Packages-NonOfficial.yml | 97 +++++ .../PowerShell-Packages-NonOfficial.yml | 97 +++++ .../PowerShell-Release-Azure-NonOfficial.yml | 76 ++++ .../PowerShell-Release-NonOfficial.yml | 106 ++++++ .../PowerShell-vPack-NonOfficial.yml | 88 +++++ ...werShell-Coordinated_Packages-Official.yml | 261 ++----------- .pipelines/PowerShell-Packages-Official.yml | 227 +---------- .../PowerShell-Release-Official-Azure.yml | 34 +- .pipelines/PowerShell-Release-Official.yml | 358 +----------------- .pipelines/PowerShell-vPack-Official.yml | 268 +------------ .pipelines/templates/release-MSIX-Publish.yml | 2 +- .pipelines/templates/release-githubNuget.yml | 4 +- ...PowerShell-Coordinated_Packages-Stages.yml | 202 ++++++++++ .../stages/PowerShell-Packages-Stages.yml | 186 +++++++++ .../stages/PowerShell-Release-Stages.yml | 323 ++++++++++++++++ .../stages/PowerShell-vPack-Stages.yml | 236 ++++++++++++ ...erShell-Coordinated_Packages-Variables.yml | 67 ++++ .../PowerShell-Packages-Variables.yml | 50 +++ .../PowerShell-Release-Azure-Variables.yml | 35 ++ .../PowerShell-Release-Variables.yml | 41 ++ .../variables/PowerShell-vPack-Variables.yml | 39 ++ .../release-shared.yml | 0 23 files changed, 1871 insertions(+), 1090 deletions(-) create mode 100644 .github/agents/SplitADOPipelines.agent.md create mode 100644 .pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml create mode 100644 .pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml create mode 100644 .pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml create mode 100644 .pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml create mode 100644 .pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml create mode 100644 .pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml create mode 100644 .pipelines/templates/stages/PowerShell-Packages-Stages.yml create mode 100644 .pipelines/templates/stages/PowerShell-Release-Stages.yml create mode 100644 .pipelines/templates/stages/PowerShell-vPack-Stages.yml create mode 100644 .pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml create mode 100644 .pipelines/templates/variables/PowerShell-Packages-Variables.yml create mode 100644 .pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml create mode 100644 .pipelines/templates/variables/PowerShell-Release-Variables.yml create mode 100644 .pipelines/templates/variables/PowerShell-vPack-Variables.yml rename .pipelines/templates/{variable => variables}/release-shared.yml (100%) diff --git a/.github/agents/SplitADOPipelines.agent.md b/.github/agents/SplitADOPipelines.agent.md new file mode 100644 index 00000000000..8322f473e7b --- /dev/null +++ b/.github/agents/SplitADOPipelines.agent.md @@ -0,0 +1,164 @@ +--- +name: SplitADOPipelines +description: This agent will implement and restructure the repository's existing ADO pipelines into Official and NonOfficial pipelines. +tools: ['vscode', 'execute', 'read', 'agent', 'edit', 'search', 'todo'] +--- + +This agent will implement and restructure the repository's existing ADO pipelines into Official and NonOfficial pipelines. + +A repository will have under the ./pipelines directory a series of yaml files that define the ADO pipelines for the repository. + +First confirm if the pipelines are using a toggle switch for Official and NonOfficial. This will look something like this + +```yaml +parameters: + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} +``` + +Followed by: + +```yaml +extends: + template: ${{ variables.templateFile }} +``` + +This is an indicator that this work needs to be done. This toggle switch is no longer allowed and the templates need to be hard coded. + +## Refactoring Steps + +### Step 1: Extract Shared Templates + +For each pipeline file that uses the toggle switch pattern (e.g., `PowerShell-Packages.yml`): + +1. Create a `./pipelines/templates` directory if it doesn't exist +2. Extract the **variables section** into `./pipelines/templates/PowerShell-Packages-Variables.yml` +3. Extract the **stages section** into `./pipelines/templates/PowerShell-Packages-Stages.yml` + +**IMPORTANT**: Only extract the `variables:` and `stages:` sections. All other sections (parameters, resources, extends, etc.) remain in the pipeline files. + +### Step 2: Create Official Pipeline (In-Place Refactoring) + +The original toggle-based file becomes the Official pipeline: + +1. **Keep the file in its original location** (e.g., `./pipelines/PowerShell-Packages.yml` stays where it is) +2. Remove the toggle switch parameter (`templateFile` parameter) +3. Hard-code the Official template reference: + ```yaml + extends: + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates + ``` +4. Replace the `variables:` section with a template reference: + ```yaml + variables: + - template: templates/PowerShell-Packages-Variables.yml + ``` +5. Replace the `stages:` section with a template reference: + ```yaml + stages: + - template: templates/PowerShell-Packages-Stages.yml + ``` + +### Step 3: Create NonOfficial Pipeline + +1. Create `./pipelines/NonOfficial` directory if it doesn't exist +2. Create the NonOfficial pipeline file (e.g., `./pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`) +3. Copy the structure from the refactored Official pipeline +4. Hard-code the NonOfficial template reference: + ```yaml + extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + ``` +5. Reference the same shared templates: + ```yaml + variables: + - template: ../templates/PowerShell-Packages-Variables.yml + + stages: + - template: ../templates/PowerShell-Packages-Stages.yml + ``` + +**Note**: The NonOfficial pipeline uses `../templates/` because it's one directory deeper than the Official pipeline. + +### Step 4: Link NonOfficial Pipelines to NonOfficial Dependencies + +After creating NonOfficial pipelines, ensure they consume artifacts from other **NonOfficial** pipelines, not Official ones. + +1. **Check the `resources:` section** in each NonOfficial pipeline for `pipelines:` dependencies +2. **Identify Official pipeline references** that need to be changed to NonOfficial +3. **Update the `source:` field** to point to the NonOfficial version + +**Example Problem:** NonOfficial pipeline pointing to Official dependency +```yaml +resources: + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated Binaries-Official' # ❌ Wrong - Official! +``` + +**Solution:** Update to NonOfficial dependency +```yaml +resources: + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated Binaries-NonOfficial' # ✅ Correct - NonOfficial! +``` + +**IMPORTANT**: The `source:` field must match the **exact ADO pipeline definition name** as it appears in Azure DevOps, not necessarily the file name. + +### Step 5: Configure Release Environment Parameters (NonAzure Only) + +**This step only applies if the pipeline uses `category: NonAzure` in the release configuration.** + +If you detect this pattern in the original pipeline: + +```yaml +extends: + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates # or NonOfficial + parameters: + release: + category: NonAzure +``` + +Then you must configure the `ob_release_environment` parameter when referencing the stages template. + +#### Official Pipeline Configuration + +In the Official pipeline (e.g., `./pipelines/PowerShell-Packages.yml`): + +```yaml +stages: + - template: templates/PowerShell-Packages-Stages.yml + parameters: + ob_release_environment: Production +``` + +#### NonOfficial Pipeline Configuration + +In the NonOfficial pipeline (e.g., `./pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`): + +```yaml +stages: + - template: ../templates/PowerShell-Packages-Stages.yml + parameters: + ob_release_environment: Test +``` + +#### Update Stages Template to Accept Parameter + +The extracted stages template (e.g., `./pipelines/templates/PowerShell-Packages-Stages.yml`) must declare the parameter at the top: + +```yaml +parameters: + - name: ob_release_environment + type: string + +stages: + # ... rest of stages configuration using ${{ parameters.ob_release_environment }} +``` + +**IMPORTANT**: +- Only configure this for pipelines with `category: NonAzure` +- Official pipelines always use `ob_release_environment: Production` +- NonOfficial pipelines always use `ob_release_environment: Test` +- The stages template must accept this parameter and use it in the appropriate stage configurations diff --git a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml new file mode 100644 index 00000000000..55d4c4557d8 --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml @@ -0,0 +1,97 @@ +trigger: none + +parameters: + - name: InternalSDKBlobURL + displayName: URL to the blob having internal .NET SDK + type: string + default: ' ' + - name: ReleaseTagVar + displayName: Release Tag + type: string + default: 'fromBranch' + - name: SKIP_SIGNING + displayName: Debugging - Skip Signing + type: string + default: 'NO' + - name: RUN_TEST_AND_RELEASE + displayName: Debugging - Run Test and Release Artifacts Stage + type: boolean + default: true + - name: RUN_WINDOWS + displayName: Debugging - Enable Windows Stage + type: boolean + default: true + - name: ENABLE_MSBUILD_BINLOGS + displayName: Debugging - Enable MSBuild Binary Logs + type: boolean + default: false + - name: FORCE_CODEQL + displayName: Debugging - Enable CodeQL and set cadence to 1 hour + type: boolean + default: false + +name: bins-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) + +resources: + repositories: + - repository: ComplianceRepo + type: github + endpoint: ComplianceGHRepo + name: PowerShell/compliance + ref: master + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +variables: + - template: ../templates/variables/PowerShell-Coordinated_Packages-Variables.yml + parameters: + InternalSDKBlobURL: ${{ parameters.InternalSDKBlobURL }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + SKIP_SIGNING: ${{ parameters.SKIP_SIGNING }} + ENABLE_MSBUILD_BINLOGS: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} + FORCE_CODEQL: ${{ parameters.FORCE_CODEQL }} + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + parameters: + customTags: 'ES365AIMigrationTooling' + featureFlags: + LinuxHostVersion: + Network: KS3 + WindowsHostVersion: + Network: KS3 + incrementalSDLBinaryAnalysis: true + globalSdl: + disableLegacyManifest: true + # disabled Armorty as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + sbom: + enabled: true + codeql: + compiled: + enabled: $(CODEQL_ENABLED) + tsaEnabled: true # This enables TSA bug filing only for CodeQL 3000 + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + cg: + enabled: true + ignoreDirectories: '.devcontainer,demos,docker,docs,src,test,tools/packaging' + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config\tsaoptions.json + + stages: + - template: ../templates/stages/PowerShell-Coordinated_Packages-Stages.yml + parameters: + RUN_WINDOWS: ${{ parameters.RUN_WINDOWS }} + RUN_TEST_AND_RELEASE: ${{ parameters.RUN_TEST_AND_RELEASE }} + OfficialBuild: false diff --git a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml new file mode 100644 index 00000000000..81f343a04a0 --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml @@ -0,0 +1,97 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time + - name: ForceAzureBlobDelete + displayName: Delete Azure Blob + type: string + values: + - true + - false + default: false + - name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + - name: InternalSDKBlobURL + displayName: URL to the blob having internal .NET SDK + type: string + default: ' ' + - name: ReleaseTagVar + displayName: Release Tag + type: string + default: 'fromBranch' + - name: SKIP_SIGNING + displayName: Skip Signing + type: string + default: 'NO' + - name: disableNetworkIsolation + type: boolean + default: false + +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) + +variables: + - template: ../templates/variables/PowerShell-Packages-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ForceAzureBlobDelete: ${{ parameters.ForceAzureBlobDelete }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + disableNetworkIsolation: ${{ parameters.disableNetworkIsolation }} + +resources: + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated_Packages-NonOfficial' + trigger: + branches: + include: + - master + - releases/* + + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + parameters: + cloudvault: + enabled: false + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: KS3 + LinuxHostVersion: + Network: KS3 + linuxEsrpSigning: true + incrementalSDLBinaryAnalysis: true + disableNetworkIsolation: ${{ variables.disableNetworkIsolation }} + globalSdl: + disableLegacyManifest: true + # disabled Armorty as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + sbom: + enabled: true + compiled: + enabled: false + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + cg: + enabled: true + ignoreDirectories: '.devcontainer,demos,docker,docs,src,test,tools/packaging' + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config\tsaoptions.json + stages: + - template: ../templates/stages/PowerShell-Packages-Stages.yml + parameters: + OfficialBuild: false diff --git a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml new file mode 100644 index 00000000000..681babb2220 --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml @@ -0,0 +1,76 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time + - name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + - name: skipPublish + displayName: Skip PMC Publish + type: boolean + default: false + - name: SKIP_SIGNING + displayName: Skip Signing + type: string + default: 'NO' + +name: ev2-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) + +variables: + - template: ../templates/variables/PowerShell-Release-Azure-Variables.yml + parameters: + debug: ${{ parameters.debug }} + +resources: + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated_Packages-NonOfficial' + + - pipeline: PSPackagesOfficial + source: 'PowerShell-Packages-NonOfficial' + trigger: + branches: + include: + - master + - releases/* + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + parameters: + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: Netlock + linuxEsrpSigning: true + incrementalSDLBinaryAnalysis: true + cloudvault: + enabled: false + globalSdl: + disableLegacyManifest: true + # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + tsa: + enabled: true + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + break: false # always break the build on binskim issues in addition to TSA upload + exactToolVersion: 4.4.2 + policheck: + break: true # always break the build on policheck issues. You can disable it by setting to 'false' + tsaOptionsFile: .config\tsaoptions.json + stages: + - template: /.pipelines/templates/release-prep-for-ev2.yml@self + parameters: + skipPublish: ${{ parameters.skipPublish }} + + - template: /.pipelines/templates/release-publish-pmc.yml@self diff --git a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml new file mode 100644 index 00000000000..ca5a6383f33 --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml @@ -0,0 +1,106 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time + - name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + - name: InternalSDKBlobURL + displayName: URL to the blob having internal .NET SDK + type: string + default: ' ' + - name: ReleaseTagVar + displayName: Release Tag + type: string + default: 'fromBranch' + - name: SKIP_SIGNING + displayName: Skip Signing + type: string + default: 'NO' + - name: SkipPublish + displayName: Skip Publishing to Nuget + type: boolean + default: false + - name: SkipPSInfraInstallers + displayName: Skip Copying Archives and Installers to PSInfrastructure Public Location + type: boolean + default: false + - name: skipMSIXPublish + displayName: Skip MSIX Publish + type: boolean + default: false + +name: release-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) + +variables: + - template: ../templates/variables/PowerShell-Release-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + +resources: + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + - repository: PSInternalTools + type: git + name: PowerShellCore/Internal-PowerShellTeam-Tools + ref: refs/heads/master + + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated_Packages-NonOfficial' + + # NOTE: The alias name "PSPackagesOfficial" is intentionally reused here even + # for the NonOfficial pipeline source. Downstream shared templates (for example, + # release-validate-sdk.yml and release-upload-buildinfo.yml) reference artifacts + # using `download: PSPackagesOfficial`, so changing this alias would break them. + - pipeline: PSPackagesOfficial + source: 'PowerShell-Packages-NonOfficial' + trigger: + branches: + include: + - master + - releases/* + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + parameters: + release: + category: NonAzure + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: KS3 + incrementalSDLBinaryAnalysis: true + cloudvault: + enabled: false + globalSdl: + disableLegacyManifest: true + # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + tsa: + enabled: true + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + break: false # always break the build on binskim issues in addition to TSA upload + exactToolVersion: 4.4.2 + policheck: + break: true # always break the build on policheck issues. You can disable it by setting to 'false' + # suppression: + # suppressionFile: $(Build.SourcesDirectory)\.gdn\global.gdnsuppress + tsaOptionsFile: .config\tsaoptions.json + + stages: + - template: ../templates/stages/PowerShell-Release-Stages.yml + parameters: + releaseEnvironment: Test + SkipPublish: ${{ parameters.SkipPublish }} + SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} + skipMSIXPublish: ${{ parameters.skipMSIXPublish }} diff --git a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml new file mode 100644 index 00000000000..642b169adaf --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml @@ -0,0 +1,88 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time +- name: 'createVPack' + displayName: 'Create and Submit VPack' + type: boolean + default: true +- name: vPackName + type: string + displayName: 'VPack Name:' + default: 'PowerShell.BuildTool' + values: + - PowerShell.BuildTool + - PowerShell + - PowerShellDoNotUse +- name: 'ReleaseTagVar' + type: string + displayName: 'Release Tag Var:' + default: 'fromBranch' +- name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false +- name: netiso + displayName: "Network Isolation Policy" + type: string + values: + - KS4 + - R1 + - Netlock + default: "R1" + +name: vPack_$(Build.SourceBranchName)_NonOfficial_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) + +variables: + - template: ../templates/variables/PowerShell-vPack-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + netiso: ${{ parameters.netiso }} + +resources: + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: v2/Microsoft.NonOfficial.yml@onebranchTemplates + parameters: + platform: + name: 'windows_undocked' # windows undocked + + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: ${{ variables.netiso }} + + cloudvault: + enabled: false + + globalSdl: + useCustomPolicy: true # for signing code + disableLegacyManifest: true + # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + sbom: + enabled: true + compiled: + enabled: false + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config/tsaoptions.json + stages: + - template: ../templates/stages/PowerShell-vPack-Stages.yml + parameters: + createVPack: ${{ parameters.createVPack }} + vPackName: ${{ parameters.vPackName }} diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 9be4baff1c1..82f129a0a5e 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -10,23 +10,27 @@ parameters: type: string default: 'fromBranch' - name: SKIP_SIGNING - displayName: Skip Signing + displayName: Debugging - Skip Signing type: string default: 'NO' - name: RUN_TEST_AND_RELEASE - displayName: Run Test and Release Artifacts Stage + displayName: Debugging - Run Test and Release Artifacts Stage type: boolean default: true - name: RUN_WINDOWS - displayName: Enable Windows Stage + displayName: Debugging - Enable Windows Stage type: boolean default: true - name: ENABLE_MSBUILD_BINLOGS - displayName: Enable MSBuild Binary Logs + displayName: Debugging - Enable MSBuild Binary Logs + type: boolean + default: false + - name: FORCE_CODEQL + displayName: Debugging - Enable CodeQL and set cadence to 1 hour type: boolean default: false -name: bins-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) +name: bins-$(BUILD.SOURCEBRANCHNAME)-prod-$(Build.BuildId) resources: repositories: @@ -41,49 +45,13 @@ resources: ref: refs/heads/main variables: - - name: PS_RELEASE_BUILD - value: 1 - - name: DOTNET_CLI_TELEMETRY_OPTOUT - value: 1 - - name: POWERSHELL_TELEMETRY_OPTOUT - value: 1 - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipNugetSecurityAnalysis - value: true - - name: branchCounterKey - value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] - - name: branchCounter - value: $[counter(variables['branchCounterKey'], 1)] - - name: BUILDSECMON_OPT_IN - value: true - - name: __DOTNET_RUNTIME_FEED - value: ${{ parameters.InternalSDKBlobURL }} - - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - - name: WindowsContainerImage - value: onebranch.azurecr.io/windows/ltsc2019/vse2022:latest - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] - - name: ReleaseTagVar - value: ${{ parameters.ReleaseTagVar }} - - name: SKIP_SIGNING - value: ${{ parameters.SKIP_SIGNING }} - - group: mscodehub-feed-read-general - - group: mscodehub-feed-read-akv - - name: ENABLE_MSBUILD_BINLOGS - - name: ENABLE_MSBUILD_BINLOGS - value: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} - # Fix for BinSkim ICU package error in Linux containers - - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT - value: true - # Disable BinSkim at job level to override NonOfficial template defaults - - name: ob_sdl_binskim_enabled - value: false - - name: ps_official_build - value: true + - template: templates/variables/PowerShell-Coordinated_Packages-Variables.yml + parameters: + InternalSDKBlobURL: ${{ parameters.InternalSDKBlobURL }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + SKIP_SIGNING: ${{ parameters.SKIP_SIGNING }} + ENABLE_MSBUILD_BINLOGS: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} + FORCE_CODEQL: ${{ parameters.FORCE_CODEQL }} extends: template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates @@ -93,6 +61,7 @@ extends: LinuxHostVersion: Network: KS3 WindowsHostVersion: + Version: 2022 Network: KS3 incrementalSDLBinaryAnalysis: true globalSdl: @@ -102,11 +71,10 @@ extends: enabled: false sbom: enabled: true - compiled: - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/master') }}: - enabled: true - ${{ else }}: - enabled: false + codeql: + compiled: + enabled: $(CODEQL_ENABLED) + tsaEnabled: true # This enables TSA bug filing only for CodeQL 3000 credscan: enabled: true scanFolder: $(Build.SourcesDirectory) @@ -123,185 +91,8 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - stage: prep - jobs: - - job: SetVars - displayName: Set Variables - pool: - type: linux - - variables: - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT/BuildJson' - - name: ob_sdl_codeSignValidation_enabled - value: false - - name: ob_sdl_codeql_compiled_enabled - value: false - - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - - name: ob_signing_setup_enabled - value: false - - name: ob_sdl_sbom_enabled - value: false - - steps: - - checkout: self - clean: true - env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - - - pwsh: | - Get-ChildItem Env: - displayName: Capture environment variables - env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - - - template: /.pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - - - stage: macos - displayName: macOS - build and sign - dependsOn: ['prep'] - jobs: - - template: /.pipelines/templates/mac.yml@self - parameters: - buildArchitecture: x64 - - template: /.pipelines/templates/mac.yml@self - parameters: - buildArchitecture: arm64 - - - stage: linux - displayName: linux - build and sign - dependsOn: ['prep'] - jobs: - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-x64' - JobName: 'linux_x64' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-x64' - JobName: 'linux_x64_minSize' - BuildConfiguration: 'minSize' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-arm' - JobName: 'linux_arm' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-arm64' - JobName: 'linux_arm64' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'fxdependent-linux-x64' - JobName: 'linux_fxd_x64_mariner' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'fxdependent-linux-arm64' - JobName: 'linux_fxd_arm64_mariner' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'fxdependent-noopt-linux-musl-x64' - JobName: 'linux_fxd_x64_alpine' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'fxdependent' - JobName: 'linux_fxd' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-musl-x64' - JobName: 'linux_x64_alpine' - - - stage: windows - displayName: windows - build and sign - dependsOn: ['prep'] - condition: and(succeeded(),eq('${{ parameters.RUN_WINDOWS }}','true')) - jobs: - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: x64 - BuildConfiguration: release - JobName: build_windows_x64_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: x64 - BuildConfiguration: minSize - JobName: build_windows_x64_minSize_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: x86 - JobName: build_windows_x86_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: arm64 - JobName: build_windows_arm64_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: fxdependent - JobName: build_windows_fxdependent_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: fxdependentWinDesktop - JobName: build_windows_fxdependentWinDesktop_release - - - stage: test_and_release_artifacts - displayName: Test and Release Artifacts - dependsOn: ['prep'] - condition: and(succeeded(),eq('${{ parameters.RUN_TEST_AND_RELEASE }}','true')) - jobs: - - template: /.pipelines/templates/testartifacts.yml@self - - - job: release_json - displayName: Create and Upload release.json - pool: - type: windows - variables: - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - steps: - - checkout: self - clean: true - - template: /.pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - template: /.pipelines/templates/rebuild-branch-check.yml@self - - powershell: | - $metadata = Get-Content '$(Build.SourcesDirectory)/PowerShell/tools/metadata.json' -Raw | ConvertFrom-Json - - # Use the rebuild branch check from the template - $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' - - # Don't mark as LTS release for rebuild branches - $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch - - if ($isRebuildBranch) { - Write-Verbose -Message "Rebuild branch detected, not marking as LTS release" -Verbose - } - - @{ ReleaseVersion = "$(Version)"; LTSRelease = $LTS } | ConvertTo-Json | Out-File "$(Build.StagingDirectory)\release.json" - Get-Content "$(Build.StagingDirectory)\release.json" - - if (-not (Test-Path "$(ob_outputDirectory)\metadata")) { - New-Item -ItemType Directory -Path "$(ob_outputDirectory)\metadata" - } - - Copy-Item -Path "$(Build.StagingDirectory)\release.json" -Destination "$(ob_outputDirectory)\metadata" -Force - displayName: Create and upload release.json file to build artifact - retryCountOnTaskFailure: 2 - - template: /.pipelines/templates/step/finalize.yml@self \ No newline at end of file + - template: templates/stages/PowerShell-Coordinated_Packages-Stages.yml + parameters: + RUN_WINDOWS: ${{ parameters.RUN_WINDOWS }} + RUN_TEST_AND_RELEASE: ${{ parameters.RUN_TEST_AND_RELEASE }} + OfficialBuild: true diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index a13ef12378a..8afce29ede7 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -28,44 +28,15 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false -name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod-$(Build.BuildId) variables: - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] # needed for onebranch.pipeline.version task - - name: system.debug - value: ${{ parameters.debug }} - - name: ENABLE_PRS_DELAYSIGN - value: 1 - - name: ROOT - value: $(Build.SourcesDirectory) - - name: ForceAzureBlobDelete - value: ${{ parameters.ForceAzureBlobDelete }} - - name: NUGET_XMLDOC_MODE - value: none - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipNugetSecurityAnalysis - value: true - - name: ReleaseTagVar - value: ${{ parameters.ReleaseTagVar }} - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' # Docker image which is used to build the project - - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - - group: mscodehub-feed-read-general - - group: mscodehub-feed-read-akv - - name: branchCounterKey - value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] - - name: branchCounter - value: $[counter(variables['branchCounterKey'], 1)] - - group: MSIXSigningProfile - - name: disableNetworkIsolation - value: ${{ parameters.disableNetworkIsolation }} + - template: templates/variables/PowerShell-Packages-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ForceAzureBlobDelete: ${{ parameters.ForceAzureBlobDelete }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + disableNetworkIsolation: ${{ parameters.disableNetworkIsolation }} resources: pipelines: @@ -121,184 +92,6 @@ extends: enabled: false tsaOptionsFile: .config\tsaoptions.json stages: - - stage: prep - displayName: 'Prep BuildInfo+Az' - jobs: - - template: /.pipelines/templates/checkAzureContainer.yml@self - - - stage: mac_package - displayName: 'macOS Pkg+Sign' - dependsOn: [] - jobs: - - template: /.pipelines/templates/mac-package-build.yml@self - parameters: - buildArchitecture: x64 - - - template: /.pipelines/templates/mac-package-build.yml@self - parameters: - buildArchitecture: arm64 - - - stage: windows_package_build - displayName: 'Win Pkg (unsigned)' - dependsOn: [] - jobs: - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: x64 - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: arm64 - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: x86 - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: fxdependent - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: fxdependentWinDesktop - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: minsize - - - stage: windows_package_sign - displayName: 'Win Pkg Sign' - dependsOn: [windows_package_build] - jobs: - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: x64 - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: arm64 - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: x86 - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: fxdependent - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: fxdependentWinDesktop - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: minsize - - - stage: linux_package - displayName: 'Linux Pkg+Sign' - dependsOn: [] - jobs: - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64' - signedDrop: 'drop_linux_sign_linux_x64' - packageType: deb - jobName: deb - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_fxd_x64_mariner' - signedDrop: 'drop_linux_sign_linux_fxd_x64_mariner' - packageType: rpm-fxdependent #mariner-x64 - jobName: mariner_x64 - signingProfile: 'CP-459159-pgpdetached' - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_fxd_arm64_mariner' - signedDrop: 'drop_linux_sign_linux_fxd_arm64_mariner' - packageType: rpm-fxdependent-arm64 #mariner-arm64 - jobName: mariner_arm64 - signingProfile: 'CP-459159-pgpdetached' - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64' - signedDrop: 'drop_linux_sign_linux_x64' - packageType: rpm - jobName: rpm - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_arm' - signedDrop: 'drop_linux_sign_linux_arm' - packageType: tar-arm - jobName: tar_arm - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_arm64' - signedDrop: 'drop_linux_sign_linux_arm64' - packageType: tar-arm64 - jobName: tar_arm64 - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64_alpine' - signedDrop: 'drop_linux_sign_linux_x64_alpine' - packageType: tar-alpine - jobName: tar_alpine - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_fxd' - signedDrop: 'drop_linux_sign_linux_fxd' - packageType: fxdependent - jobName: fxdependent - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64' - signedDrop: 'drop_linux_sign_linux_x64' - packageType: tar - jobName: tar - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_fxd_x64_alpine' - signedDrop: 'drop_linux_sign_linux_fxd_x64_alpine' - packageType: tar-alpine-fxdependent - jobName: tar_alpine_fxd - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64_minSize' - signedDrop: 'drop_linux_sign_linux_x64_minSize' - packageType: min-size - jobName: minSize - - - stage: nupkg - displayName: 'NuGet Pkg+Sign' - dependsOn: [] - jobs: - - template: /.pipelines/templates/nupkg.yml@self - - - stage: msixbundle - displayName: 'MSIX Bundle+Sign' - dependsOn: [windows_package_build] # Only depends on unsigned packages - jobs: - - template: /.pipelines/templates/package-create-msix.yml@self - parameters: - OfficialBuild: true - - - stage: upload - displayName: 'Upload' - dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON - jobs: - - template: /.pipelines/templates/uploadToAzure.yml@self - - - stage: validatePackages - displayName: 'Validate Packages' - dependsOn: [upload] - jobs: - - template: /.pipelines/templates/release-validate-packagenames.yml@self + - template: templates/stages/PowerShell-Packages-Stages.yml + parameters: + OfficialBuild: true diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index 81543420460..24040a2463d 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -14,38 +14,12 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: string default: 'NO' -name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) +name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod-$(Build.BuildId) variables: - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] - - name: system.debug - value: ${{ parameters.debug }} - - name: ENABLE_PRS_DELAYSIGN - value: 1 - - name: ROOT - value: $(Build.SourcesDirectory) - - name: REPOROOT - value: $(Build.SourcesDirectory) - - name: OUTPUTROOT - value: $(REPOROOT)\out - - name: NUGET_XMLDOC_MODE - value: none - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipNugetSecurityAnalysis - value: true - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\.config\tsaoptions.json - - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - - group: PoolNames + - template: templates/variables/PowerShell-Release-Azure-Variables.yml + parameters: + debug: ${{ parameters.debug }} resources: repositories: diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 02a255a1db6..3528e6b1471 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -30,43 +30,13 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false -name: release-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) +name: release-$(BUILD.SOURCEBRANCHNAME)-prod-$(Build.BuildId) variables: - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] - - name: system.debug - value: ${{ parameters.debug }} - - name: ENABLE_PRS_DELAYSIGN - value: 1 - - name: ROOT - value: $(Build.SourcesDirectory) - - name: REPOROOT - value: $(Build.SourcesDirectory) - - name: OUTPUTROOT - value: $(REPOROOT)\out - - name: NUGET_XMLDOC_MODE - value: none - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipNugetSecurityAnalysis - value: true - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - - name: ReleaseTagVar - value: ${{ parameters.ReleaseTagVar }} - - group: PoolNames - - name: releaseEnvironment - value: 'Production' - # Fix for BinSkim ICU package error in Linux containers - - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT - value: true + - template: templates/variables/PowerShell-Release-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} resources: repositories: @@ -124,315 +94,9 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - stage: setReleaseTagAndChangelog - displayName: 'Set Release Tag and Upload Changelog' - jobs: - - template: /.pipelines/templates/release-SetTagAndChangelog.yml@self - - - stage: validateSdk - displayName: 'Validate SDK' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-validate-sdk.yml@self - parameters: - jobName: "windowsSDK" - displayName: "Windows SDK Validation" - imageName: PSMMS2019-Secure - poolName: $(windowsPool) - - - template: /.pipelines/templates/release-validate-sdk.yml@self - parameters: - jobName: "MacOSSDK" - displayName: "MacOS SDK Validation" - imageName: macOS-latest - poolName: Azure Pipelines - - - template: /.pipelines/templates/release-validate-sdk.yml@self - parameters: - jobName: "LinuxSDK" - displayName: "Linux SDK Validation" - imageName: PSMMSUbuntu22.04-Secure - poolName: $(ubuntuPool) - - - stage: gbltool - displayName: 'Validate Global tools' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-validate-globaltools.yml@self - parameters: - jobName: "WindowsGlobalTools" - displayName: "Windows Global Tools Validation" - jobtype: windows - - - template: /.pipelines/templates/release-validate-globaltools.yml@self - parameters: - jobName: "LinuxGlobalTools" - displayName: "Linux Global Tools Validation" - jobtype: linux - globalToolExeName: 'pwsh' - globalToolPackageName: 'PowerShell.Linux.x64' - - - stage: fxdpackages - displayName: 'Validate FXD Packages' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-validate-fxdpackages.yml@self - parameters: - jobName: 'winfxd' - displayName: 'Validate Win Fxd Packages' - jobtype: 'windows' - artifactName: 'drop_windows_package_package_win_fxdependent' - packageNamePattern: '**/*win-fxdependent.zip' - - - template: /.pipelines/templates/release-validate-fxdpackages.yml@self - parameters: - jobName: 'winfxdDesktop' - displayName: 'Validate WinDesktop Fxd Packages' - jobtype: 'windows' - artifactName: 'drop_windows_package_package_win_fxdependentWinDesktop' - packageNamePattern: '**/*win-fxdependentwinDesktop.zip' - - - template: /.pipelines/templates/release-validate-fxdpackages.yml@self - parameters: - jobName: 'linuxfxd' - displayName: 'Validate Linux Fxd Packages' - jobtype: 'linux' - artifactName: 'drop_linux_package_fxdependent' - packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' - - - template: /.pipelines/templates/release-validate-fxdpackages.yml@self - parameters: - jobName: 'linuxArm64fxd' - displayName: 'Validate Linux ARM64 Fxd Packages' - jobtype: 'linux' - artifactName: 'drop_linux_package_fxdependent' - # this is really an architecture independent package - packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' - arm64: 'yes' - enableCredScan: false - - - stage: ManualValidation - dependsOn: [] - displayName: Manual Validation - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Validate Windows Packages - jobName: ValidateWinPkg - instructions: | - Validate zip package on windows - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Validate OSX Packages - jobName: ValidateOsxPkg - instructions: | - Validate tar.gz package on osx-arm64 - - - stage: ReleaseAutomation - dependsOn: [] - displayName: 'Release Automation' - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Start Release Automation - jobName: StartRA - instructions: | - Kick off Release automation build at: https://dev.azure.com/powershell-rel/Release-Automation/_build?definitionId=10&_a=summary - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Triage results - jobName: TriageRA - dependsOnJob: StartRA - instructions: | - Triage ReleaseAutomation results - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Signoff Tests - dependsOnJob: TriageRA - jobName: SignoffTests - instructions: | - Signoff ReleaseAutomation results - - - stage: UpdateChangeLog - displayName: Update the changelog - dependsOn: - - ManualValidation - - ReleaseAutomation - - fxdpackages - - gbltool - - validateSdk - - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Make sure the changelog is updated - jobName: MergeChangeLog - instructions: | - Update and merge the changelog for the release. - This step is required for creating GitHub draft release. - - - stage: PublishGitHubReleaseAndNuget - displayName: Publish GitHub and Nuget Release - dependsOn: - - setReleaseTagAndChangelog - - UpdateChangeLog - variables: - ob_release_environment: ${{ variables.releaseEnvironment }} - jobs: - - template: /.pipelines/templates/release-githubNuget.yml@self - parameters: - skipPublish: ${{ parameters.SkipPublish }} - - - stage: PushGitTagAndMakeDraftPublic - displayName: Push Git Tag and Make Draft Public - dependsOn: PublishGitHubReleaseAndNuget - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Push Git Tag - jobName: PushGitTag - instructions: | - Push the git tag to upstream - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Make Draft Public - dependsOnJob: PushGitTag - jobName: DraftPublic - instructions: | - Make the GitHub Release Draft Public - - - stage: BlobPublic - displayName: Make Blob Public - dependsOn: - - UpdateChangeLog - - PushGitTagAndMakeDraftPublic - jobs: - - template: /.pipelines/templates/release-MakeBlobPublic.yml@self - parameters: - SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} - - - stage: PublishPMC - displayName: Publish PMC - dependsOn: PushGitTagAndMakeDraftPublic - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Publish to PMC - jobName: ReleaseToPMC - instructions: | - Run PowerShell-Release-Official-Azure.yml pipeline to publish to PMC - - - stage: UpdateDotnetDocker - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Update DotNet SDK Docker images - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Update .NET SDK docker images - jobName: DotnetDocker - instructions: | - Create PR for updating dotnet-docker images to use latest PowerShell version. - 1. Fork and clone https://github.com/dotnet/dotnet-docker.git - 2. git checkout upstream/nightly -b updatePS - 3. dotnet run --project .\eng\update-dependencies\ specific --product-version powershell= --compute-shas - 4. create PR targeting nightly branch - - - stage: UpdateWinGet - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Add manifest entry to winget - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Add manifest entry to winget - jobName: UpdateWinGet - instructions: | - This is typically done by the community 1-2 days after the release. - - - stage: PublishMsix - dependsOn: - - setReleaseTagAndChangelog - - PushGitTagAndMakeDraftPublic - displayName: Publish MSIX to store - variables: - ob_release_environment: ${{ variables.releaseEnvironment }} - jobs: - - template: /.pipelines/templates/release-MSIX-Publish.yml@self - parameters: - skipMSIXPublish: ${{ parameters.skipMSIXPublish }} - - - stage: PublishVPack - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Release vPack - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Start 2 vPack Release pipelines - jobName: PublishVPack - instructions: | - 1. Kick off PowerShell-vPack-Official pipeline - 2. Kick off PowerShell-MSIXBundle-VPack pipeline - - # Need to verify if the Az PS / CLI team still uses this. Skippinng for this release. - # - stage: ReleaseDeps - # dependsOn: GitHubTasks - # displayName: Update pwsh.deps.json links - # jobs: - # - template: templates/release-UpdateDepsJson.yml - - - stage: UploadBuildInfoJson - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Upload BuildInfo.json - jobs: - - template: /.pipelines/templates/release-upload-buildinfo.yml@self - - - stage: ReleaseSymbols - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Release Symbols - jobs: - - template: /.pipelines/templates/release-symbols.yml@self - - - stage: ChangesToMaster - displayName: Ensure changes are in GH master - dependsOn: - - PublishPMC - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Make sure changes are in master - jobName: MergeToMaster - instructions: | - Make sure that changes README.md and metadata.json are merged into master on GitHub. - - - stage: ReleaseToMU - displayName: Release to MU - dependsOn: PushGitTagAndMakeDraftPublic # This only needs the blob to be available - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Release to MU - instructions: | - Notify the PM team to start the process of releasing to MU. - - - stage: ReleaseClose - displayName: Finish Release - dependsOn: - - ReleaseToMU - - ReleaseSymbols - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Retain Build - jobName: RetainBuild - instructions: | - Retain the build - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Delete release branch - jobName: DeleteBranch - instructions: | - Delete release \ No newline at end of file + - template: templates/stages/PowerShell-Release-Stages.yml + parameters: + releaseEnvironment: Production + SkipPublish: ${{ parameters.SkipPublish }} + SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} + skipMSIXPublish: ${{ parameters.skipMSIXPublish }} diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index fbbf3683db5..13087fbbf65 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -30,37 +30,14 @@ parameters: # parameters are shown up in ADO UI in a build queue time - Netlock default: "R1" -name: vPack_$(Build.SourceBranchName)_Prod.true_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) +name: vPack_$(Build.SourceBranchName)_Prod_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] - - name: system.debug - value: ${{ parameters.debug }} - - name: BuildSolution - value: $(Build.SourcesDirectory)\dirs.proj - - name: BuildConfiguration - value: Release - - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' - - name: Codeql.Enabled - value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack - - name: DOTNET_CLI_TELEMETRY_OPTOUT - value: 1 - - name: POWERSHELL_TELEMETRY_OPTOUT - value: 1 - - name: nugetMultiFeedWarnLevel - value: none - - name: ReleaseTagVar - value: ${{ parameters.ReleaseTagVar }} - - group: Azure Blob variable group - - group: certificate_logical_to_actual # used within signing task - - group: DotNetPrivateBuildAccess - - group: certificate_logical_to_actual - - name: netiso - value: ${{ parameters.netiso }} -# We shouldn't be using PATs anymore -# - group: mscodehub-feed-read-general + - template: templates/variables/PowerShell-vPack-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + netiso: ${{ parameters.netiso }} resources: repositories: @@ -105,232 +82,7 @@ extends: enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - - stage: BuildStage - jobs: - - job: BuildJob - pool: - type: windows - - strategy: - matrix: - x86: - architecture: x86 - - x64: - architecture: x64 - - arm64: - architecture: arm64 - - variables: - ArtifactPlatform: 'windows' - ob_artifactBaseName: drop_build_$(architecture) - ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' - ob_createvpack_enabled: ${{ parameters.createVPack }} - ob_createvpack_owneralias: tplunk - ob_createvpack_versionAs: parts - ob_createvpack_propsFile: true - ob_createvpack_verbose: true - ob_createvpack_packagename: '${{ parameters.vPackName }}.$(architecture)' - ob_createvpack_description: PowerShell $(architecture) $(version) - # I think the variables reload after we transition back to the host so this works. 🤷‍♂️ - ob_createvpack_majorVer: $(pwshMajorVersion) - ob_createvpack_minorVer: $(pwshMinorVersion) - ob_createvpack_patchVer: $(pwshPatchVersion) - ${{ if ne(variables['pwshPrereleaseVersion'], '') }}: - ob_createvpack_prereleaseVer: $(pwshPrereleaseVersion) - ${{ else }}: - ob_createvpack_prereleaseVer: $(Build.SourceVersion) - - steps: - - checkout: self - displayName: Checkout source code - during restore - clean: true - path: s - env: - ob_restore_phase: true - - - template: .pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - - - pwsh: | - $version = '$(Version)' - Write-Verbose -Verbose "Version: $version" - if(!$version) { - throw "Version is not set." - } - - $mainVersionParts = $version -split '-' - - Write-Verbose -Verbose "mainVersionParts: $($mainVersionParts[0]) ; $($mainVersionParts[1])" - $versionParts = $mainVersionParts[0] -split '[.]'; - $major = $versionParts[0] - $minor = $versionParts[1] - $patch = $versionParts[2] - - $previewPart = $mainVersionParts[1] - Write-Verbose -Verbose "previewPart: $previewPart" - - Write-Host "major: $major; minor: $minor; patch: $patch;" - - $vstsCommandString = "vso[task.setvariable variable=pwshMajorVersion]$major" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - $vstsCommandString = "vso[task.setvariable variable=pwshMinorVersion]$minor" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - $vstsCommandString = "vso[task.setvariable variable=pwshPatchVersion]$patch" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - if($previewPart) { - $vstsCommandString = "vso[task.setvariable variable=pwshPrereleaseVersion]$previewPart" - } else { - Write-Verbose -Verbose "No prerelease part found in version string." - } - displayName: Set ob_createvpack_*Ver - env: - ob_restore_phase: true - - # Validate pwsh*Version variables - - pwsh: | - $variables = @("pwshMajorVersion", "pwshMinorVersion", "pwshPatchVersion") - foreach ($var in $variables) { - if (-not (get-item "Env:\$var" -ErrorAction SilentlyContinue).value) { - throw "Required variable '`$env:$var' is not set." - } - } - displayName: Validate pwsh*Version variables - env: - ob_restore_phase: true - - - pwsh: | - if($env:RELEASETAGVAR -match '-') { - throw "Don't release a preview build without coordinating with Windows Engineering Build Tools Team" - } - displayName: Stop any preview release - env: - ob_restore_phase: true - - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - packageType: sdk - version: 3.1.x - installationPath: $(Agent.ToolsDirectory)/dotnet - - ### BUILD ### - - - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self - parameters: - repoRoot: $(repoRoot) - - - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. - env: - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - inputs: - Enabled: true - AnalyzeInPipeline: false # Do not upload results - Language: csharp - - - task: UseDotNet@2 - displayName: 'Install .NET based on global.json' - inputs: - useGlobalJson: true - workingDirectory: $(repoRoot) - env: - ob_restore_phase: true - - - pwsh: | - # Need to set PowerShellRoot variable for obp-file-signing template - $vstsCommandString = "vso[task.setvariable variable=PowerShellRoot]$(repoRoot)" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - $Architecture = '$(Architecture)' - $runtime = switch ($Architecture) - { - "x64" { "win7-x64" } - "x86" { "win7-x86" } - "arm64" { "win-arm64" } - } - - $params = @{} - if ($env:BuildConfiguration -eq 'minSize') { - $params['ForMinimalSize'] = $true - } - - $vstsCommandString = "vso[task.setvariable variable=Runtime]$runtime" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - Write-Verbose -Message "Building PowerShell with Runtime: $runtime for '$env:BuildConfiguration' configuration" - Import-Module -Name $(repoRoot)/build.psm1 -Force - $buildWithSymbolsPath = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/Symbols_$Architecture" -Force - - Start-PSBootstrap -Scenario Package - $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose - - $ReleaseTagParam = @{} - - if ($env:RELEASETAGVAR) { - $ReleaseTagParam['ReleaseTag'] = $env:RELEASETAGVAR - } - - Start-PSBuild -Runtime $runtime -Configuration Release -Output $buildWithSymbolsPath -Clean -PSModuleRestore @params @ReleaseTagParam - - $refFolderPath = Join-Path $buildWithSymbolsPath 'ref' - Write-Verbose -Verbose "refFolderPath: $refFolderPath" - $outputPath = Join-Path '$(ob_outputDirectory)' 'psoptions' - $null = New-Item -ItemType Directory -Path $outputPath -Force - $psOptPath = "$outputPath/psoptions.json" - Save-PSOptions -PSOptionsPath $psOptPath - - Write-Verbose -Verbose "Completed building PowerShell for '$env:BuildConfiguration' configuration" - displayName: Build Windows Universal - $(Architecture) -$(BuildConfiguration) Symbols folder - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - - - task: CodeQL3000Finalize@0 # Add CodeQL Finalize task right after your 'Build' step. - env: - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(repoRoot)\src' - ob_restore_phase: true - - - template: /.pipelines/templates/obp-file-signing.yml@self - parameters: - binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' - SigningProfile: $(windows_build_tools_cert_id) - OfficialBuild: false - vPackScenario: true - - ### END OF BUILD ### - - - pwsh: | - Get-ChildItem env:/ob_createvpack_*Ver - Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse - Get-Content "$(Pipeline.Workspace)\PowerShell\preview.json" -ErrorAction SilentlyContinue | Write-Host - displayName: Debug Output Directory and Version - condition: succeededOrFailed() - - - pwsh: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - displayName: Capture Environment - condition: succeededOrFailed() - - - pwsh: | - $vpackFiles = Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse - if($vpackFiles.Count -eq 0) { - throw "No files found in $(Pipeline.Workspace)\Symbols_$(Architecture)" - } - $vpackFiles - displayName: Debug Output Directory and Version - condition: succeededOrFailed() + - template: templates/stages/PowerShell-vPack-Stages.yml + parameters: + createVPack: ${{ parameters.createVPack }} + vPackName: ${{ parameters.vPackName }} diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index a92c71f826b..aaef3c6f269 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -21,7 +21,7 @@ jobs: value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsStable'] ] - name: PREVIEW value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsPreview'] ] - - template: ./variable/release-shared.yml@self + - template: ./variables/release-shared.yml@self parameters: RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] steps: diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index 348afe66c7b..899e9bd572a 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -17,7 +17,7 @@ jobs: pipeline: PSPackagesOfficial artifactName: drop_upload_upload_packages variables: - - template: ./variable/release-shared.yml@self + - template: ./variables/release-shared.yml@self parameters: RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] @@ -159,7 +159,7 @@ jobs: pipeline: PSPackagesOfficial artifactName: drop_upload_upload_packages variables: - - template: ./variable/release-shared.yml@self + - template: ./variables/release-shared.yml@self parameters: VERSION: $[ stageDependencies.setReleaseTagAndChangelog.SetTagAndChangelog.outputs['OutputVersion.Version'] ] diff --git a/.pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml new file mode 100644 index 00000000000..cd0a4ebc065 --- /dev/null +++ b/.pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml @@ -0,0 +1,202 @@ +parameters: + - name: RUN_WINDOWS + type: boolean + default: true + - name: RUN_TEST_AND_RELEASE + type: boolean + default: true + - name: OfficialBuild + type: boolean + +stages: +- stage: prep + jobs: + - job: SetVars + displayName: Set Variables + pool: + type: linux + + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT/BuildJson' + - name: ob_sdl_codeSignValidation_enabled + value: false + - name: ob_sdl_codeql_compiled_enabled + value: false + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_sbom_enabled + value: false + + steps: + - checkout: self + clean: true + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + + - pwsh: | + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture environment variables + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: yes + +- stage: macos + displayName: macOS - build and sign + dependsOn: ['prep'] + variables: + - name: ps_official_build + value: ${{ parameters.OfficialBuild }} + jobs: + - template: /.pipelines/templates/mac.yml@self + parameters: + buildArchitecture: x64 + - template: /.pipelines/templates/mac.yml@self + parameters: + buildArchitecture: arm64 + +- stage: linux + displayName: linux - build and sign + dependsOn: ['prep'] + variables: + - name: ps_official_build + value: ${{ parameters.OfficialBuild }} + jobs: + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-x64' + JobName: 'linux_x64' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-x64' + JobName: 'linux_x64_minSize' + BuildConfiguration: 'minSize' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-arm' + JobName: 'linux_arm' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-arm64' + JobName: 'linux_arm64' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'fxdependent-linux-x64' + JobName: 'linux_fxd_x64_mariner' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'fxdependent-linux-arm64' + JobName: 'linux_fxd_arm64_mariner' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'fxdependent-noopt-linux-musl-x64' + JobName: 'linux_fxd_x64_alpine' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'fxdependent' + JobName: 'linux_fxd' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-musl-x64' + JobName: 'linux_x64_alpine' + +- stage: windows + displayName: windows - build and sign + dependsOn: ['prep'] + condition: and(succeeded(),eq('${{ parameters.RUN_WINDOWS }}','true')) + variables: + - name: ps_official_build + value: ${{ parameters.OfficialBuild }} + jobs: + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: x64 + BuildConfiguration: release + JobName: build_windows_x64_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: x64 + BuildConfiguration: minSize + JobName: build_windows_x64_minSize_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: x86 + JobName: build_windows_x86_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: arm64 + JobName: build_windows_arm64_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: fxdependent + JobName: build_windows_fxdependent_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: fxdependentWinDesktop + JobName: build_windows_fxdependentWinDesktop_release + +- stage: test_and_release_artifacts + displayName: Test and Release Artifacts + dependsOn: ['prep'] + condition: and(succeeded(),eq('${{ parameters.RUN_TEST_AND_RELEASE }}','true')) + jobs: + - template: /.pipelines/templates/testartifacts.yml@self + + - job: release_json + displayName: Create and Upload release.json + pool: + type: windows + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + steps: + - checkout: self + clean: true + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + - template: /.pipelines/templates/rebuild-branch-check.yml@self + - powershell: | + $metadata = Get-Content '$(Build.SourcesDirectory)/PowerShell/tools/metadata.json' -Raw | ConvertFrom-Json + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't mark as LTS release for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, not marking as LTS release" -Verbose + } + + @{ ReleaseVersion = "$(Version)"; LTSRelease = $LTS } | ConvertTo-Json | Out-File "$(Build.StagingDirectory)\release.json" + Get-Content "$(Build.StagingDirectory)\release.json" + + if (-not (Test-Path "$(ob_outputDirectory)\metadata")) { + New-Item -ItemType Directory -Path "$(ob_outputDirectory)\metadata" + } + + Copy-Item -Path "$(Build.StagingDirectory)\release.json" -Destination "$(ob_outputDirectory)\metadata" -Force + displayName: Create and upload release.json file to build artifact + retryCountOnTaskFailure: 2 + - template: /.pipelines/templates/step/finalize.yml@self diff --git a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml new file mode 100644 index 00000000000..ff40941e31b --- /dev/null +++ b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml @@ -0,0 +1,186 @@ +parameters: + - name: OfficialBuild + type: boolean + +stages: +- stage: prep + displayName: 'Prep BuildInfo+Az' + jobs: + - template: /.pipelines/templates/checkAzureContainer.yml@self + +- stage: mac_package + displayName: 'macOS Pkg+Sign' + dependsOn: [] + jobs: + - template: /.pipelines/templates/mac-package-build.yml@self + parameters: + buildArchitecture: x64 + + - template: /.pipelines/templates/mac-package-build.yml@self + parameters: + buildArchitecture: arm64 + +- stage: windows_package_build + displayName: 'Win Pkg (unsigned)' + dependsOn: [] + jobs: + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: x64 + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: arm64 + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: x86 + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: fxdependent + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: fxdependentWinDesktop + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: minsize + +- stage: windows_package_sign + displayName: 'Win Pkg Sign' + dependsOn: [windows_package_build] + jobs: + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: x64 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: arm64 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: x86 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: fxdependent + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: fxdependentWinDesktop + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: minsize + +- stage: linux_package + displayName: 'Linux Pkg+Sign' + dependsOn: [] + jobs: + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' + packageType: deb + jobName: deb + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_fxd_x64_mariner' + signedDrop: 'drop_linux_sign_linux_fxd_x64_mariner' + packageType: rpm-fxdependent #mariner-x64 + jobName: mariner_x64 + signingProfile: 'CP-459159-pgpdetached' + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_fxd_arm64_mariner' + signedDrop: 'drop_linux_sign_linux_fxd_arm64_mariner' + packageType: rpm-fxdependent-arm64 #mariner-arm64 + jobName: mariner_arm64 + signingProfile: 'CP-459159-pgpdetached' + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' + packageType: rpm + jobName: rpm + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_arm' + signedDrop: 'drop_linux_sign_linux_arm' + packageType: tar-arm + jobName: tar_arm + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_arm64' + signedDrop: 'drop_linux_sign_linux_arm64' + packageType: tar-arm64 + jobName: tar_arm64 + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64_alpine' + signedDrop: 'drop_linux_sign_linux_x64_alpine' + packageType: tar-alpine + jobName: tar_alpine + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_fxd' + signedDrop: 'drop_linux_sign_linux_fxd' + packageType: fxdependent + jobName: fxdependent + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' + packageType: tar + jobName: tar + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_fxd_x64_alpine' + signedDrop: 'drop_linux_sign_linux_fxd_x64_alpine' + packageType: tar-alpine-fxdependent + jobName: tar_alpine_fxd + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64_minSize' + signedDrop: 'drop_linux_sign_linux_x64_minSize' + packageType: min-size + jobName: minSize + +- stage: nupkg + displayName: 'NuGet Pkg+Sign' + dependsOn: [] + jobs: + - template: /.pipelines/templates/nupkg.yml@self + +- stage: msixbundle + displayName: 'MSIX Bundle+Sign' + dependsOn: [windows_package_build] # Only depends on unsigned packages + jobs: + - template: /.pipelines/templates/package-create-msix.yml@self + parameters: + OfficialBuild: ${{ parameters.OfficialBuild }} + +- stage: upload + displayName: 'Upload' + dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON + jobs: + - template: /.pipelines/templates/uploadToAzure.yml@self + +- stage: validatePackages + displayName: 'Validate Packages' + dependsOn: [upload] + jobs: + - template: /.pipelines/templates/release-validate-packagenames.yml@self diff --git a/.pipelines/templates/stages/PowerShell-Release-Stages.yml b/.pipelines/templates/stages/PowerShell-Release-Stages.yml new file mode 100644 index 00000000000..52ce428a663 --- /dev/null +++ b/.pipelines/templates/stages/PowerShell-Release-Stages.yml @@ -0,0 +1,323 @@ +parameters: + - name: releaseEnvironment + type: string + - name: SkipPublish + type: boolean + - name: SkipPSInfraInstallers + type: boolean + - name: skipMSIXPublish + type: boolean + +stages: +- stage: setReleaseTagAndChangelog + displayName: 'Set Release Tag and Upload Changelog' + jobs: + - template: /.pipelines/templates/release-SetTagAndChangelog.yml@self + +- stage: validateSdk + displayName: 'Validate SDK' + dependsOn: [] + jobs: + - template: /.pipelines/templates/release-validate-sdk.yml@self + parameters: + jobName: "windowsSDK" + displayName: "Windows SDK Validation" + imageName: PSMMS2019-Secure + poolName: $(windowsPool) + + - template: /.pipelines/templates/release-validate-sdk.yml@self + parameters: + jobName: "MacOSSDK" + displayName: "MacOS SDK Validation" + imageName: macOS-latest + poolName: Azure Pipelines + + - template: /.pipelines/templates/release-validate-sdk.yml@self + parameters: + jobName: "LinuxSDK" + displayName: "Linux SDK Validation" + imageName: PSMMSUbuntu22.04-Secure + poolName: $(ubuntuPool) + +- stage: gbltool + displayName: 'Validate Global tools' + dependsOn: [] + jobs: + - template: /.pipelines/templates/release-validate-globaltools.yml@self + parameters: + jobName: "WindowsGlobalTools" + displayName: "Windows Global Tools Validation" + jobtype: windows + + - template: /.pipelines/templates/release-validate-globaltools.yml@self + parameters: + jobName: "LinuxGlobalTools" + displayName: "Linux Global Tools Validation" + jobtype: linux + globalToolExeName: 'pwsh' + globalToolPackageName: 'PowerShell.Linux.x64' + +- stage: fxdpackages + displayName: 'Validate FXD Packages' + dependsOn: [] + jobs: + - template: /.pipelines/templates/release-validate-fxdpackages.yml@self + parameters: + jobName: 'winfxd' + displayName: 'Validate Win Fxd Packages' + jobtype: 'windows' + artifactName: 'drop_windows_package_package_win_fxdependent' + packageNamePattern: '**/*win-fxdependent.zip' + + - template: /.pipelines/templates/release-validate-fxdpackages.yml@self + parameters: + jobName: 'winfxdDesktop' + displayName: 'Validate WinDesktop Fxd Packages' + jobtype: 'windows' + artifactName: 'drop_windows_package_package_win_fxdependentWinDesktop' + packageNamePattern: '**/*win-fxdependentwinDesktop.zip' + + - template: /.pipelines/templates/release-validate-fxdpackages.yml@self + parameters: + jobName: 'linuxfxd' + displayName: 'Validate Linux Fxd Packages' + jobtype: 'linux' + artifactName: 'drop_linux_package_fxdependent' + packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' + + - template: /.pipelines/templates/release-validate-fxdpackages.yml@self + parameters: + jobName: 'linuxArm64fxd' + displayName: 'Validate Linux ARM64 Fxd Packages' + jobtype: 'linux' + artifactName: 'drop_linux_package_fxdependent' + # this is really an architecture independent package + packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' + arm64: 'yes' + enableCredScan: false + +- stage: ManualValidation + dependsOn: [] + displayName: Manual Validation + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Validate Windows Packages + jobName: ValidateWinPkg + instructions: | + Validate zip package on windows + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Validate OSX Packages + jobName: ValidateOsxPkg + instructions: | + Validate tar.gz package on osx-arm64 + +- stage: ReleaseAutomation + dependsOn: [] + displayName: 'Release Automation' + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Start Release Automation + jobName: StartRA + instructions: | + Kick off Release automation build at: https://dev.azure.com/powershell-rel/Release-Automation/_build?definitionId=10&_a=summary + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Triage results + jobName: TriageRA + dependsOnJob: StartRA + instructions: | + Triage ReleaseAutomation results + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Signoff Tests + dependsOnJob: TriageRA + jobName: SignoffTests + instructions: | + Signoff ReleaseAutomation results + +- stage: UpdateChangeLog + displayName: Update the changelog + dependsOn: + - ManualValidation + - ReleaseAutomation + - fxdpackages + - gbltool + - validateSdk + + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Make sure the changelog is updated + jobName: MergeChangeLog + instructions: | + Update and merge the changelog for the release. + This step is required for creating GitHub draft release. + +- stage: PublishGitHubReleaseAndNuget + displayName: Publish GitHub and Nuget Release + dependsOn: + - setReleaseTagAndChangelog + - UpdateChangeLog + variables: + ob_release_environment: ${{ parameters.releaseEnvironment }} + jobs: + - template: /.pipelines/templates/release-githubNuget.yml@self + parameters: + skipPublish: ${{ parameters.SkipPublish }} + +- stage: PushGitTagAndMakeDraftPublic + displayName: Push Git Tag and Make Draft Public + dependsOn: PublishGitHubReleaseAndNuget + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Push Git Tag + jobName: PushGitTag + instructions: | + Push the git tag to upstream + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Make Draft Public + dependsOnJob: PushGitTag + jobName: DraftPublic + instructions: | + Make the GitHub Release Draft Public + +- stage: BlobPublic + displayName: Make Blob Public + dependsOn: + - UpdateChangeLog + - PushGitTagAndMakeDraftPublic + jobs: + - template: /.pipelines/templates/release-MakeBlobPublic.yml@self + parameters: + SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} + +- stage: PublishPMC + displayName: Publish PMC + dependsOn: PushGitTagAndMakeDraftPublic + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Publish to PMC + jobName: ReleaseToPMC + instructions: | + Run PowerShell-Release-Official-Azure.yml pipeline to publish to PMC + +- stage: UpdateDotnetDocker + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Update DotNet SDK Docker images + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Update .NET SDK docker images + jobName: DotnetDocker + instructions: | + Create PR for updating dotnet-docker images to use latest PowerShell version. + 1. Fork and clone https://github.com/dotnet/dotnet-docker.git + 2. git checkout upstream/nightly -b updatePS + 3. dotnet run --project .\eng\update-dependencies\ specific --product-version powershell= --compute-shas + 4. create PR targeting nightly branch + +- stage: UpdateWinGet + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Add manifest entry to winget + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Add manifest entry to winget + jobName: UpdateWinGet + instructions: | + This is typically done by the community 1-2 days after the release. + +- stage: PublishMsix + dependsOn: + - setReleaseTagAndChangelog + - PushGitTagAndMakeDraftPublic + displayName: Publish MSIX to store + variables: + ob_release_environment: ${{ parameters.releaseEnvironment }} + jobs: + - template: /.pipelines/templates/release-MSIX-Publish.yml@self + parameters: + skipMSIXPublish: ${{ parameters.skipMSIXPublish }} + +- stage: PublishVPack + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Release vPack + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Start 2 vPack Release pipelines + jobName: PublishVPack + instructions: | + 1. Kick off PowerShell-vPack-Official pipeline + 2. Kick off PowerShell-MSIXBundle-VPack pipeline + +# Need to verify if the Az PS / CLI team still uses this. Skipping for this release. +# - stage: ReleaseDeps +# dependsOn: GitHubTasks +# displayName: Update pwsh.deps.json links +# jobs: +# - template: templates/release-UpdateDepsJson.yml + +- stage: UploadBuildInfoJson + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Upload BuildInfo.json + jobs: + - template: /.pipelines/templates/release-upload-buildinfo.yml@self + +- stage: ReleaseSymbols + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Release Symbols + jobs: + - template: /.pipelines/templates/release-symbols.yml@self + +- stage: ChangesToMaster + displayName: Ensure changes are in GH master + dependsOn: + - PublishPMC + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Make sure changes are in master + jobName: MergeToMaster + instructions: | + Make sure that changes README.md and metadata.json are merged into master on GitHub. + +- stage: ReleaseToMU + displayName: Release to MU + dependsOn: PushGitTagAndMakeDraftPublic # This only needs the blob to be available + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Release to MU + instructions: | + Notify the PM team to start the process of releasing to MU. + +- stage: ReleaseClose + displayName: Finish Release + dependsOn: + - ReleaseToMU + - ReleaseSymbols + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Retain Build + jobName: RetainBuild + instructions: | + Retain the build + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Delete release branch + jobName: DeleteBranch + instructions: | + Delete release branch diff --git a/.pipelines/templates/stages/PowerShell-vPack-Stages.yml b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml new file mode 100644 index 00000000000..f0d49e8b489 --- /dev/null +++ b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml @@ -0,0 +1,236 @@ +parameters: + - name: createVPack + type: boolean + - name: vPackName + type: string + +stages: +- stage: BuildStage + jobs: + - job: BuildJob + pool: + type: windows + + strategy: + matrix: + x86: + architecture: x86 + + x64: + architecture: x64 + + arm64: + architecture: arm64 + + variables: + ArtifactPlatform: 'windows' + ob_artifactBaseName: drop_build_$(architecture) + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_createvpack_enabled: ${{ parameters.createVPack }} + ob_createvpack_owneralias: tplunk + ob_createvpack_versionAs: parts + ob_createvpack_propsFile: true + ob_createvpack_verbose: true + ob_createvpack_packagename: '${{ parameters.vPackName }}.$(architecture)' + ob_createvpack_description: PowerShell $(architecture) $(version) + # I think the variables reload after we transition back to the host so this works. 🤷‍♂️ + ob_createvpack_majorVer: $(pwshMajorVersion) + ob_createvpack_minorVer: $(pwshMinorVersion) + ob_createvpack_patchVer: $(pwshPatchVersion) + ${{ if ne(variables['pwshPrereleaseVersion'], '') }}: + ob_createvpack_prereleaseVer: $(pwshPrereleaseVersion) + ${{ else }}: + ob_createvpack_prereleaseVer: $(Build.SourceVersion) + + steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s + env: + ob_restore_phase: true + + - template: .pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: yes + + - pwsh: | + $version = '$(Version)' + Write-Verbose -Verbose "Version: $version" + if(!$version) { + throw "Version is not set." + } + + $mainVersionParts = $version -split '-' + + Write-Verbose -Verbose "mainVersionParts: $($mainVersionParts[0]) ; $($mainVersionParts[1])" + $versionParts = $mainVersionParts[0] -split '[.]'; + $major = $versionParts[0] + $minor = $versionParts[1] + $patch = $versionParts[2] + + $previewPart = $mainVersionParts[1] + Write-Verbose -Verbose "previewPart: $previewPart" + + Write-Host "major: $major; minor: $minor; patch: $patch;" + + $vstsCommandString = "vso[task.setvariable variable=pwshMajorVersion]$major" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $vstsCommandString = "vso[task.setvariable variable=pwshMinorVersion]$minor" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $vstsCommandString = "vso[task.setvariable variable=pwshPatchVersion]$patch" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + if($previewPart) { + $vstsCommandString = "vso[task.setvariable variable=pwshPrereleaseVersion]$previewPart" + } else { + Write-Verbose -Verbose "No prerelease part found in version string." + } + displayName: Set ob_createvpack_*Ver + env: + ob_restore_phase: true + + # Validate pwsh*Version variables + - pwsh: | + $variables = @("pwshMajorVersion", "pwshMinorVersion", "pwshPatchVersion") + foreach ($var in $variables) { + if (-not (get-item "Env:\$var" -ErrorAction SilentlyContinue).value) { + throw "Required variable '`$env:$var' is not set." + } + } + displayName: Validate pwsh*Version variables + env: + ob_restore_phase: true + + - pwsh: | + if($env:RELEASETAGVAR -match '-') { + throw "Don't release a preview build without coordinating with Windows Engineering Build Tools Team" + } + displayName: Stop any preview release + env: + ob_restore_phase: true + + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + packageType: sdk + version: 3.1.x + installationPath: $(Agent.ToolsDirectory)/dotnet + + ### BUILD ### + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(repoRoot) + + - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + inputs: + Enabled: true + AnalyzeInPipeline: false # Do not upload results + Language: csharp + + - task: UseDotNet@2 + displayName: 'Install .NET based on global.json' + inputs: + useGlobalJson: true + workingDirectory: $(repoRoot) + env: + ob_restore_phase: true + + - pwsh: | + # Need to set PowerShellRoot variable for obp-file-signing template + $vstsCommandString = "vso[task.setvariable variable=PowerShellRoot]$(repoRoot)" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $Architecture = '$(Architecture)' + $runtime = switch ($Architecture) + { + "x64" { "win7-x64" } + "x86" { "win7-x86" } + "arm64" { "win-arm64" } + } + + $params = @{} + if ($env:BuildConfiguration -eq 'minSize') { + $params['ForMinimalSize'] = $true + } + + $vstsCommandString = "vso[task.setvariable variable=Runtime]$runtime" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + Write-Verbose -Message "Building PowerShell with Runtime: $runtime for '$env:BuildConfiguration' configuration" + Import-Module -Name $(repoRoot)/build.psm1 -Force + $buildWithSymbolsPath = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/Symbols_$Architecture" -Force + + Start-PSBootstrap -Scenario Package + $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose + + $ReleaseTagParam = @{} + + if ($env:RELEASETAGVAR) { + $ReleaseTagParam['ReleaseTag'] = $env:RELEASETAGVAR + } + + Start-PSBuild -Runtime $runtime -Configuration Release -Output $buildWithSymbolsPath -Clean -PSModuleRestore @params @ReleaseTagParam + + $refFolderPath = Join-Path $buildWithSymbolsPath 'ref' + Write-Verbose -Verbose "refFolderPath: $refFolderPath" + $outputPath = Join-Path '$(ob_outputDirectory)' 'psoptions' + $null = New-Item -ItemType Directory -Path $outputPath -Force + $psOptPath = "$outputPath/psoptions.json" + Save-PSOptions -PSOptionsPath $psOptPath + + Write-Verbose -Verbose "Completed building PowerShell for '$env:BuildConfiguration' configuration" + displayName: Build Windows Universal - $(Architecture) -$(BuildConfiguration) Symbols folder + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: CodeQL3000Finalize@0 # Add CodeQL Finalize task right after your 'Build' step. + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + inputs: + sourceScanPath: '$(repoRoot)\src' + ob_restore_phase: true + + - template: /.pipelines/templates/obp-file-signing.yml@self + parameters: + binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' + SigningProfile: $(windows_build_tools_cert_id) + OfficialBuild: false + vPackScenario: true + + ### END OF BUILD ### + + - pwsh: | + Get-ChildItem env:/ob_createvpack_*Ver + Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse + Get-Content "$(Pipeline.Workspace)\PowerShell\preview.json" -ErrorAction SilentlyContinue | Write-Host + displayName: Debug Output Directory and Version + condition: succeededOrFailed() + + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture Environment + condition: succeededOrFailed() + + - pwsh: | + $vpackFiles = Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse + if($vpackFiles.Count -eq 0) { + throw "No files found in $(Pipeline.Workspace)\Symbols_$(Architecture)" + } + $vpackFiles + displayName: Debug Output Directory and Version + condition: succeededOrFailed() diff --git a/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml new file mode 100644 index 00000000000..de3ac0ba1b6 --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml @@ -0,0 +1,67 @@ +parameters: + - name: InternalSDKBlobURL + type: string + default: ' ' + - name: ReleaseTagVar + type: string + default: 'fromBranch' + - name: SKIP_SIGNING + type: string + default: 'NO' + - name: ENABLE_MSBUILD_BINLOGS + type: boolean + default: false + - name: FORCE_CODEQL + type: boolean + default: false + +variables: + - name: PS_RELEASE_BUILD + value: 1 + - name: DOTNET_CLI_TELEMETRY_OPTOUT + value: 1 + - name: POWERSHELL_TELEMETRY_OPTOUT + value: 1 + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: branchCounterKey + value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] + - name: branchCounter + value: $[counter(variables['branchCounterKey'], 1)] + - name: BUILDSECMON_OPT_IN + value: true + - name: __DOTNET_RUNTIME_FEED + value: ${{ parameters.InternalSDKBlobURL }} + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 + - name: WindowsContainerImage + value: onebranch.azurecr.io/windows/ltsc2019/vse2022:latest + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - name: SKIP_SIGNING + value: ${{ parameters.SKIP_SIGNING }} + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv + - name: ENABLE_MSBUILD_BINLOGS + value: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} + - ${{ if eq(parameters['FORCE_CODEQL'],'true') }}: + # Cadence is hours before CodeQL will allow a re-upload of the database + - name: CodeQL.Cadence + value: 1 + - name: CODEQL_ENABLED + ${{ if or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(parameters['FORCE_CODEQL'],'true')) }}: + value: true + ${{ else }}: + value: false + # Fix for BinSkim ICU package error in Linux containers + - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT + value: true + # Disable BinSkim at job level to override NonOfficial template defaults + - name: ob_sdl_binskim_enabled + value: false diff --git a/.pipelines/templates/variables/PowerShell-Packages-Variables.yml b/.pipelines/templates/variables/PowerShell-Packages-Variables.yml new file mode 100644 index 00000000000..7d1818909b5 --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-Packages-Variables.yml @@ -0,0 +1,50 @@ +parameters: + - name: debug + type: boolean + default: false + - name: ForceAzureBlobDelete + type: string + default: 'false' + - name: ReleaseTagVar + type: string + default: 'fromBranch' + - name: disableNetworkIsolation + type: boolean + default: false + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] # needed for onebranch.pipeline.version task + - name: system.debug + value: ${{ parameters.debug }} + - name: ENABLE_PRS_DELAYSIGN + value: 1 + - name: ROOT + value: $(Build.SourcesDirectory) + - name: ForceAzureBlobDelete + value: ${{ parameters.ForceAzureBlobDelete }} + - name: NUGET_XMLDOC_MODE + value: none + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' # Docker image which is used to build the project + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv + - name: branchCounterKey + value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] + - name: branchCounter + value: $[counter(variables['branchCounterKey'], 1)] + - group: MSIXSigningProfile + - name: disableNetworkIsolation + value: ${{ parameters.disableNetworkIsolation }} diff --git a/.pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml b/.pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml new file mode 100644 index 00000000000..3b47e5eff2b --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml @@ -0,0 +1,35 @@ +parameters: + - name: debug + type: boolean + default: false + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: ENABLE_PRS_DELAYSIGN + value: 1 + - name: ROOT + value: $(Build.SourcesDirectory) + - name: REPOROOT + value: $(Build.SourcesDirectory) + - name: OUTPUTROOT + value: $(REPOROOT)\out + - name: NUGET_XMLDOC_MODE + value: none + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\.config\tsaoptions.json + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 + - group: PoolNames diff --git a/.pipelines/templates/variables/PowerShell-Release-Variables.yml b/.pipelines/templates/variables/PowerShell-Release-Variables.yml new file mode 100644 index 00000000000..930c559eafe --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-Release-Variables.yml @@ -0,0 +1,41 @@ +parameters: + - name: debug + type: boolean + default: false + - name: ReleaseTagVar + type: string + default: 'fromBranch' + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: ENABLE_PRS_DELAYSIGN + value: 1 + - name: ROOT + value: $(Build.SourcesDirectory) + - name: REPOROOT + value: $(Build.SourcesDirectory) + - name: OUTPUTROOT + value: $(REPOROOT)\out + - name: NUGET_XMLDOC_MODE + value: none + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - group: PoolNames + # Fix for BinSkim ICU package error in Linux containers + - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT + value: true diff --git a/.pipelines/templates/variables/PowerShell-vPack-Variables.yml b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml new file mode 100644 index 00000000000..276911a35b3 --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml @@ -0,0 +1,39 @@ +parameters: + - name: debug + type: boolean + default: false + - name: ReleaseTagVar + type: string + default: 'fromBranch' + - name: netiso + type: string + default: 'R1' + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: BuildSolution + value: $(Build.SourcesDirectory)\dirs.proj + - name: BuildConfiguration + value: Release + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + - name: Codeql.Enabled + value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack + - name: DOTNET_CLI_TELEMETRY_OPTOUT + value: 1 + - name: POWERSHELL_TELEMETRY_OPTOUT + value: 1 + - name: nugetMultiFeedWarnLevel + value: none + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - group: Azure Blob variable group + - group: certificate_logical_to_actual # used within signing task + - group: DotNetPrivateBuildAccess + - name: netiso + value: ${{ parameters.netiso }} +# We shouldn't be using PATs anymore +# - group: mscodehub-feed-read-general diff --git a/.pipelines/templates/variable/release-shared.yml b/.pipelines/templates/variables/release-shared.yml similarity index 100% rename from .pipelines/templates/variable/release-shared.yml rename to .pipelines/templates/variables/release-shared.yml From 497fbce84a26064302257e842cf9875ad4b3954f Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 17:56:28 -0700 Subject: [PATCH 227/275] [release/v7.5.6] Bump actions/upload-artifact from 6 to 7 (#27157) --- .github/workflows/macos-ci.yml | 4 ++-- .github/workflows/scorecards.yml | 4 ++-- .github/workflows/windows-packaging-reusable.yml | 4 ++-- .github/workflows/xunit-tests.yml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 6633cd0467b..917ed633151 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -226,7 +226,7 @@ jobs: testResultsFolder: "${{ runner.workspace }}/testResults" - name: Upload package artifact if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: macos-package path: "*.pkg" @@ -242,4 +242,4 @@ jobs: if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: - needs_context: ${{ toJson(needs) }} + needs_context: ${{ toJson(needs) }} \ No newline at end of file diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 90ac8e0b762..23e47f8bda2 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: SARIF file path: results.sarif @@ -69,4 +69,4 @@ jobs: - name: "Upload to code-scanning" uses: github/codeql-action/upload-sarif@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0 with: - sarif_file: results.sarif + sarif_file: results.sarif \ No newline at end of file diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 6b42a8899ec..77a207217a0 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -81,9 +81,9 @@ jobs: - name: Upload Build Artifacts if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: windows-packaging-${{ matrix.architecture }}-${{ matrix.channel }} path: | ${{ github.workspace }}/artifacts/**/* - !${{ github.workspace }}/artifacts/**/*.pdb + !${{ github.workspace }}/artifacts/**/*.pdb \ No newline at end of file diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index 8bf5fd699d0..e16b9fa068f 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -46,8 +46,8 @@ jobs: Write-Host "Completed xUnit test run." - name: Upload xUnit results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: always() with: name: ${{ inputs.test_results_artifact_name }} - path: ${{ github.workspace }}/xUnitTestResults.xml + path: ${{ github.workspace }}/xUnitTestResults.xml \ No newline at end of file From 2e90a92705745bb16036598f749ed8e0ea86e39b Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 17:56:43 -0700 Subject: [PATCH 228/275] [release/v7.5.6] Bump actions/dependency-review-action from 4.8.3 to 4.9.0 (#27158) --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 24a0dd11f57..c9417c4aea3 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -19,4 +19,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: 'Dependency Review' - uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 + uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 \ No newline at end of file From b38c846cb0b4a1ffd54fdab6f8240ec774957122 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 17:56:58 -0700 Subject: [PATCH 229/275] [release/v7.5.6] Bump github/codeql-action from 4.32.4 to 4.32.6 (#27159) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 10b2f0893a3..201ffa9791d 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 + uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 + uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 \ No newline at end of file diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 23e47f8bda2..763249559f5 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0 + uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 with: sarif_file: results.sarif \ No newline at end of file From 67f95699707aaf6ba6ccabc72fe2ccfc2a7d2e8c Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 17:59:49 -0700 Subject: [PATCH 230/275] [release/v7.5.6] Create LTS pkg and non-LTS pkg for macOS for LTS releases (#27162) --- .pipelines/templates/mac-package-build.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index ec98c65cfcc..4326166cb0c 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -102,6 +102,10 @@ jobs: Restore-PSOptions -PSOptionsPath "$psoptionsPath" Get-PSOptions | Write-Verbose -Verbose + if (-not (Test-Path "$repoRoot/tools/metadata.json")) { + throw "metadata.json not found in $repoRoot/tools" + } + $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json Write-Verbose -Verbose "metadata:" @@ -120,14 +124,19 @@ jobs: Write-Verbose -Verbose "LTS: $LTS" if ($LTS) { - Write-Verbose -Message "LTS Release: $LTS" + Write-Verbose -Message "LTS Release: $LTS" -Verbose } Start-PSBootstrap -Scenario Package $macosRuntime = "osx-$buildArch" - Start-PSPackage -Type osxpkg -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS + Start-PSPackage -Type osxpkg -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath + + if ($LTS) { + Start-PSPackage -Type osxpkg -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS + } + $pkgNameFilter = "powershell-*$macosRuntime.pkg" Write-Verbose -Verbose "Looking for pkg packages with filter: $pkgNameFilter in '$(Pipeline.Workspace)' to upload..." $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgNameFilter -Recurse -File From 20a9166e3d0da7d98950914664401bd22342b8b4 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:03:39 -0700 Subject: [PATCH 231/275] [release/v7.5.6] Fix the container image for vPack, MSIX vPack and Package pipelines (#27161) --- .pipelines/MSIXBundle-vPack-Official.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 997b7c458be..876da9c2aff 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -22,7 +22,7 @@ variables: BuildSolution: $(Build.SourcesDirectory)\dirs.proj ReleaseTagVar: ${{ parameters.ReleaseTagVar }} BuildConfiguration: Release - WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' Codeql.Enabled: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack DOTNET_CLI_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1 @@ -46,6 +46,9 @@ resources: extends: template: v2/Microsoft.Official.yml@onebranchTemplates parameters: + featureFlags: + WindowsHostVersion: + Version: 2022 platform: name: 'windows_undocked' # windows undocked From 33e0b44d80753cc7346b17f39bf76704e7e67034 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:05:04 -0700 Subject: [PATCH 232/275] [release/v7.5.6] Create Linux LTS deb/rpm packages for LTS releases (#27163) Co-authored-by: Dongbo Wang --- .pipelines/templates/linux-package-build.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index 3e37d13c177..f0017c63d2e 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -155,10 +155,6 @@ jobs: Write-Verbose -Verbose "LTS: $LTS" - if ($LTS) { - Write-Verbose -Message "LTS Release: $LTS" - } - if (-not (Test-Path $(ob_outputDirectory))) { New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force } @@ -168,6 +164,11 @@ jobs: Start-PSPackage -Type $packageType -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath + if ($LTS) { + Write-Verbose -Message "LTS Release: $LTS" -Verbose + Start-PSPackage -Type $packageType -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS + } + $vstsCommandString = "vso[task.setvariable variable=PackageFilter]$pkgFilter" Write-Host ("sending " + $vstsCommandString) Write-Host "##$vstsCommandString" From b74f0c638dc012dcbc8559ad3fa8dc907939b41f Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:05:29 -0700 Subject: [PATCH 233/275] [release/v7.5.6] Move `_GetDependencies` MSBuild target from dynamic generation in `build.psm1` into `Microsoft.PowerShell.SDK.csproj` (#27164) --- build.psm1 | 25 ++----------------- .../Microsoft.PowerShell.SDK.csproj | 24 +++++++++++++++++- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/build.psm1 b/build.psm1 index d87833513b8..abe4547e740 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2681,38 +2681,17 @@ function Start-TypeGen # Add .NET CLI tools to PATH Find-Dotnet - # This custom target depends on 'ResolveAssemblyReferencesDesignTime', whose definition can be found in the sdk folder. - # To find the available properties of '_ReferencesFromRAR' when switching to a new dotnet sdk, follow the steps below: - # 1. create a dummy project using the new dotnet sdk. - # 2. build the dummy project with this command: - # dotnet msbuild .\dummy.csproj /t:ResolveAssemblyReferencesDesignTime /fileLogger /noconsolelogger /v:diag - # 3. search '_ReferencesFromRAR' in the produced 'msbuild.log' file. You will find the properties there. - $GetDependenciesTargetPath = "$PSScriptRoot/src/Microsoft.PowerShell.SDK/obj/Microsoft.PowerShell.SDK.csproj.TypeCatalog.targets" - $GetDependenciesTargetValue = @' - - - - <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' "/> - - - - -'@ - New-Item -ItemType Directory -Path (Split-Path -Path $GetDependenciesTargetPath -Parent) -Force > $null - Set-Content -Path $GetDependenciesTargetPath -Value $GetDependenciesTargetValue -Force -Encoding Ascii - Push-Location "$PSScriptRoot/src/Microsoft.PowerShell.SDK" try { $ps_inc_file = "$PSScriptRoot/src/TypeCatalogGen/$IncFileName" - dotnet msbuild .\Microsoft.PowerShell.SDK.csproj /t:_GetDependencies "/property:DesignTimeBuild=true;_DependencyFile=$ps_inc_file" /nologo + Start-NativeExecution { dotnet msbuild .\Microsoft.PowerShell.SDK.csproj /t:_GetDependencies "/property:DesignTimeBuild=true;_DependencyFile=$ps_inc_file" /nologo } } finally { Pop-Location } Push-Location "$PSScriptRoot/src/TypeCatalogGen" try { - dotnet run ../System.Management.Automation/CoreCLR/CorePsTypeCatalog.cs $IncFileName + Start-NativeExecution { dotnet run ../System.Management.Automation/CoreCLR/CorePsTypeCatalog.cs $IncFileName } } finally { Pop-Location } diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 13a377fd85b..591f855d79c 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -85,4 +85,26 @@ - + + + + + <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' "/> + + + + + \ No newline at end of file From 1c754028e894b77c824840f0bff0fc84fdfc03af Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:05:49 -0700 Subject: [PATCH 234/275] [release/v7.5.6] Create infrastructure to create two msixs and msixbundles for LTS and Stable (#27165) --- .pipelines/templates/package-create-msix.yml | 78 +++++++++++++++---- .../templates/packaging/windows/package.yml | 8 ++ tools/packaging/packaging.psm1 | 19 ++--- 3 files changed, 81 insertions(+), 24 deletions(-) diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index b6b0ec291de..4e68af42c5d 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -85,17 +85,44 @@ jobs: $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose } - $file = Get-ChildItem $sourceDir | Select-Object -First 1 - $prefix = ($file.BaseName -split "-win")[0] - $pkgName = "$prefix.msixbundle" - Write-Verbose -Verbose "Creating $pkgName" - $makeappx = '$(MakeAppxPath)' $outputDir = "$sourceDir\output" New-Item $outputDir -Type Directory -Force > $null - & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" - Get-ChildItem -Path $sourceDir -Recurse + # Separate LTS and Stable/Preview MSIX files by filename convention + $ltsMsix = @(Get-ChildItem $sourceDir -Filter '*.msix' | Where-Object { $_.BaseName -match '-LTS-' }) + $stableMsix = @(Get-ChildItem $sourceDir -Filter '*.msix' | Where-Object { $_.BaseName -notmatch '-LTS-' }) + + Write-Verbose -Verbose "Stable/Preview MSIX files: $($stableMsix.Name -join ', ')" + Write-Verbose -Verbose "LTS MSIX files: $($ltsMsix.Name -join ', ')" + + # Create Stable/Preview bundle + if ($stableMsix.Count -gt 0) { + $stableDir = "$sourceDir\stable" + New-Item $stableDir -Type Directory -Force > $null + $stableMsix | Copy-Item -Destination $stableDir -Force + $file = $stableMsix | Select-Object -First 1 + $prefix = ($file.BaseName -split "-win")[0] + $stableBundleName = "$prefix.msixbundle" + Write-Verbose -Verbose "Creating Stable/Preview bundle: $stableBundleName" + & $makeappx bundle /d $stableDir /p "$outputDir\$stableBundleName" + } + + # Create LTS bundle + if ($ltsMsix.Count -gt 0) { + $ltsDir = "$sourceDir\lts" + New-Item $ltsDir -Type Directory -Force > $null + $ltsMsix | Copy-Item -Destination $ltsDir -Force + $file = $ltsMsix | Select-Object -First 1 + $prefix = ($file.BaseName -split "-win")[0] + $ltsBundleName = "$prefix.msixbundle" + Write-Verbose -Verbose "Creating LTS bundle: $ltsBundleName" + & $makeappx bundle /d $ltsDir /p "$outputDir\$ltsBundleName" + } + + Write-Verbose -Verbose "Created bundles:" + Get-ChildItem -Path $outputDir -Recurse + $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" Write-Host "sending " + $vstsCommandString Write-Host "##$vstsCommandString" @@ -112,16 +139,18 @@ jobs: search_root: '$(BundleDir)' - pwsh: | - $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File - Write-Verbose -Verbose "Signed bundle: $signedBundle" + $signedBundles = @(Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File) + Write-Verbose -Verbose "Signed bundles: $($signedBundles.Name -join ', ')" if (-not (Test-Path $(ob_outputDirectory))) { New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force } - Copy-Item -Path $signedBundle.FullName -Destination "$(ob_outputDirectory)" -Verbose + foreach ($bundle in $signedBundles) { + Copy-Item -Path $bundle.FullName -Destination "$(ob_outputDirectory)" -Verbose + } - Write-Verbose -Verbose "Uploaded Bundle:" + Write-Verbose -Verbose "Uploaded Bundles:" Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose displayName: Upload msixbundle to Artifacts @@ -225,6 +254,29 @@ jobs: Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" + # Select the correct bundle based on channel + $bundleFiles = @(Get-ChildItem -Path '$(BundleDir)' -Filter '*.msixbundle') + Write-Verbose -Verbose "Available bundles: $($bundleFiles.Name -join ', ')" + + if ($IsLTS) { + $bundleFile = $bundleFiles | Where-Object { $_.Name -match '-LTS-' } + } else { + # Catches Stable or Preview + $bundleFile = $bundleFiles | Where-Object { $_.Name -notmatch '-LTS-' } + } + + if (-not $bundleFile) { + Write-Error "No matching bundle found for channel '$currentChannel'. Available bundles: $($bundleFiles.Name -join ', ')" + exit 1 + } + + # Copy the selected bundle to a dedicated directory for store packaging + $storeBundleDir = '$(Pipeline.Workspace)\releasePipeline\msix\store-bundle' + New-Item $storeBundleDir -Type Directory -Force > $null + Copy-Item -Path $bundleFile.FullName -Destination $storeBundleDir -Force -Verbose + Write-Host "##vso[task.setvariable variable=StoreBundleDir]$storeBundleDir" + Write-Verbose -Verbose "Selected bundle for store packaging: $($bundleFile.Name)" + # These variables are used in the next tasks to determine which ServiceEndpoint to use $ltsValue = $IsLTS.ToString().ToLower() $stableValue = $IsStable.ToString().ToLower() @@ -256,7 +308,7 @@ jobs: inputs: serviceEndpoint: 'StoreAppPublish-Preview' sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(BundleDir)' + sourceFolder: '$(StoreBundleDir)' contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' @@ -268,7 +320,7 @@ jobs: inputs: serviceEndpoint: 'StoreAppPublish-Private' sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(BundleDir)' + sourceFolder: '$(StoreBundleDir)' contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 1f03d65ab21..92926e6aa59 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -136,12 +136,14 @@ jobs: # Don't build LTS packages for rebuild branches $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + $Stable = [bool]$metadata.StableRelease.Package if ($isRebuildBranch) { Write-Verbose -Message "Rebuild branch detected, skipping LTS package build" -Verbose } Write-Verbose -Verbose "LTS: $LTS" + Write-Verbose -Verbose "Stable: $Stable" if ($LTS) { Write-Verbose -Message "LTS Release: $LTS" @@ -175,6 +177,12 @@ jobs: Start-PSPackage -Type $packageTypes -SkipReleaseChecks -WindowsRuntime $WindowsRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS + # When both LTS and Stable are requested, also build the Stable MSIX + if ($packageTypes -contains 'msix' -and $LTS -and $Stable) { + Write-Verbose -Verbose "Both LTS and Stable packages requested. Building additional Stable MSIX." + Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $WindowsRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath + } + displayName: 'Build Packages (Unsigned)' env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 65414612101..52e989c2463 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4257,18 +4257,8 @@ function New-MSIXPackage $makepri = Get-Item (Join-Path $makeappx.Directory "makepri.exe") -ErrorAction Stop + $displayName = $ProductName $ProductSemanticVersion = Get-PackageSemanticVersion -Version $ProductVersion - $productSemanticVersionWithName = $ProductName + '-' + $ProductSemanticVersion - $packageName = $productSemanticVersionWithName - if ($Private) { - $ProductNameSuffix = 'Private' - } - - if ($ProductNameSuffix) { - $packageName += "-$ProductNameSuffix" - } - - $displayName = $productName if ($Private) { $ProductName = 'PowerShell-Private' @@ -4284,6 +4274,13 @@ function New-MSIXPackage Write-Verbose -Verbose "ProductName: $productName" Write-Verbose -Verbose "DisplayName: $displayName" + $packageName = $ProductName + '-' + $ProductSemanticVersion + + # Appends Architecture to the package name + if ($ProductNameSuffix) { + $packageName += "-$ProductNameSuffix" + } + $ProductVersion = Get-WindowsVersion -PackageName $packageName # Any app that is submitted to the Store must have a PhoneIdentity in its appxmanifest. From c5c6ff4b5ccdb9f16e66c7be100e3797be6958cc Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:06:04 -0700 Subject: [PATCH 235/275] [release/v7.5.6] Fix the `PSNativeCommandArgumentPassing` test (#27166) --- .../NativeExecution/NativeCommandArguments.Tests.ps1 | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/test/powershell/Language/Scripting/NativeExecution/NativeCommandArguments.Tests.ps1 b/test/powershell/Language/Scripting/NativeExecution/NativeCommandArguments.Tests.ps1 index 8e09df9b699..ead0fb39efb 100644 --- a/test/powershell/Language/Scripting/NativeExecution/NativeCommandArguments.Tests.ps1 +++ b/test/powershell/Language/Scripting/NativeExecution/NativeCommandArguments.Tests.ps1 @@ -5,12 +5,7 @@ param() Describe "Behavior is specific for each platform" -tags "CI" { It "PSNativeCommandArgumentPassing is set to 'Windows' on Windows systems" -skip:(-not $IsWindows) { - if ([Version]::TryParse($PSVersiontable.PSVersion.ToString(), [ref]$null)) { - $PSNativeCommandArgumentPassing | Should -BeExactly "Legacy" - } - else { - $PSNativeCommandArgumentPassing | Should -BeExactly "Windows" - } + $PSNativeCommandArgumentPassing | Should -BeExactly "Windows" } It "PSNativeCommandArgumentPassing is set to 'Standard' on non-Windows systems" -skip:($IsWindows) { $PSNativeCommandArgumentPassing | Should -Be "Standard" From a62f9575e3dc20db9a8ddffa2b50998e45c05aa8 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:06:15 -0700 Subject: [PATCH 236/275] [release/v7.5.6] release-upload-buildinfo: replace version-comparison channel gating with metadata flags (#27167) --- .../templates/release-upload-buildinfo.yml | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index c470af1fd6e..9e3d6a6accb 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -51,14 +51,17 @@ jobs: Import-Module "$toolsDirectory/ci.psm1" $jsonFile = Get-Item "$ENV:PIPELINE_WORKSPACE/PSPackagesOfficial/BuildInfoJson/*.json" $fileName = Split-Path $jsonFile -Leaf + # The build itself has already determined if it is preview or stable/LTS, + # we just need to check via the file name + $isPreview = $fileName -eq "preview.json" + $isStable = $fileName -eq "stable.json" $dateTime = [datetime]::UtcNow $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) $metadata = Get-Content -LiteralPath "$toolsDirectory/metadata.json" -ErrorAction Stop | ConvertFrom-Json - $stableReleaseTag = $metadata.StableReleaseTag -Replace 'v','' - - $currentReleaseTag = $buildInfo.ReleaseTag -Replace 'v','' + # Note: version tags in metadata.json (e.g. StableReleaseTag) may not reflect the current release being + # published, so they must not be used to gate channel decisions. Use the explicit publish flags instead. $stableRelease = $metadata.StableRelease.PublishToChannels $ltsRelease = $metadata.LTSRelease.PublishToChannels @@ -73,7 +76,7 @@ jobs: $targetFile = "$ENV:PIPELINE_WORKSPACE/$fileName" ConvertTo-Json -InputObject $buildInfo | Out-File $targetFile -Encoding ascii - if ($fileName -eq "preview.json") { + if ($isPreview) { Set-BuildVariable -Name UploadPreview -Value YES } else { Set-BuildVariable -Name UploadPreview -Value NO @@ -82,9 +85,7 @@ jobs: Set-BuildVariable -Name PreviewBuildInfoFile -Value $targetFile ## Create 'lts.json' if marked as a LTS release. - if ($fileName -eq "stable.json") { - [System.Management.Automation.SemanticVersion] $stableVersion = $stableReleaseTag - [System.Management.Automation.SemanticVersion] $currentVersion = $currentReleaseTag + if ($isStable) { if ($ltsRelease) { $ltsFile = "$ENV:PIPELINE_WORKSPACE/lts.json" Copy-Item -Path $targetFile -Destination $ltsFile -Force @@ -94,18 +95,24 @@ jobs: Set-BuildVariable -Name UploadLTS -Value NO } - ## Only update the stable.json if the current version is greater than the stable version. - if ($currentVersion -gt $stableVersion) { - $versionFile = "$ENV:PIPELINE_WORKSPACE/$($currentVersion.Major)-$($currentVersion.Minor).json" - Copy-Item -Path $targetFile -Destination $versionFile -Force - Set-BuildVariable -Name StableBuildInfoFile -Value $versionFile + ## Gate stable.json upload on the metadata publish flag. + if ($stableRelease) { + Set-BuildVariable -Name StableBuildInfoFile -Value $targetFile Set-BuildVariable -Name UploadStable -Value YES } else { Set-BuildVariable -Name UploadStable -Value NO } + ## Always publish the version-specific {Major}-{Minor}.json for non-preview builds. + [System.Management.Automation.SemanticVersion] $currentVersion = $currentReleaseTag + $versionFile = "$ENV:PIPELINE_WORKSPACE/$($currentVersion.Major)-$($currentVersion.Minor).json" + Copy-Item -Path $targetFile -Destination $versionFile -Force + Set-BuildVariable -Name VersionSpecificBuildInfoFile -Value $versionFile + Set-BuildVariable -Name UploadVersionSpecific -Value YES + } else { Set-BuildVariable -Name UploadStable -Value NO + Set-BuildVariable -Name UploadVersionSpecific -Value NO } displayName: Create json files @@ -146,4 +153,12 @@ jobs: Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - condition: and(succeeded(), or(eq(variables['UploadPreview'], 'YES'), eq(variables['UploadLTS'], 'YES'), eq(variables['UploadStable'], 'YES'))) + + #version-specific + if ($env:UploadVersionSpecific -eq 'YES') { + $jsonFile = "$env:VersionSpecificBuildInfoFile" + $blobName = Get-Item $jsonFile | Split-Path -Leaf + Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" + Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force + } + condition: and(succeeded(), or(eq(variables['UploadPreview'], 'YES'), eq(variables['UploadLTS'], 'YES'), eq(variables['UploadStable'], 'YES'), eq(variables['UploadVersionSpecific'], 'YES'))) From 878cbe30376142351f5c4aad172356b49560ad8b Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:06:28 -0700 Subject: [PATCH 237/275] [release/v7.5.6] Update the PhoneProductId to be the official LTS id used by Store (#27168) --- tools/packaging/packaging.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 52e989c2463..494e2960e1b 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4297,7 +4297,7 @@ function New-MSIXPackage Write-Verbose "Using Preview assets" -Verbose } elseif ($LTS) { # This is the PhoneProductId for the "Microsoft.PowerShell-LTS" package. - $PhoneProductId = "a9af273a-c636-47ac-bc2a-775edf80b2b9" + $PhoneProductId = "b7a4b003-3704-47a9-b018-cfcc9801f4fc" Write-Verbose "Using LTS assets" -Verbose } From 1f594b8fd1991d26e36bb86270caf41fac572a3d Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:08:23 -0700 Subject: [PATCH 238/275] [release/v7.5.6] Select New MSIX Package Name (#27172) --- .pipelines/templates/packaging/windows/package.yml | 2 +- .pipelines/templates/packaging/windows/sign.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 92926e6aa59..1cc0e9d0e94 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -220,7 +220,7 @@ jobs: } if ($packageTypes -contains 'msix') { - $msixPkgNameFilter = "powershell-*.msix" + $msixPkgNameFilter = "PowerShell*.msix" $msixPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msixPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName Write-Verbose -Verbose "unsigned msixPkgPath: $msixPkgPath" Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose diff --git a/.pipelines/templates/packaging/windows/sign.yml b/.pipelines/templates/packaging/windows/sign.yml index 4a095ba7694..f7a2e5e03e8 100644 --- a/.pipelines/templates/packaging/windows/sign.yml +++ b/.pipelines/templates/packaging/windows/sign.yml @@ -202,7 +202,7 @@ jobs: } if ($packageTypes -contains 'msix') { - $msixPkgNameFilter = "powershell-*.msix" + $msixPkgNameFilter = "PowerShell*.msix" $msixPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msixPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName Write-Verbose -Verbose "signed msixPkgPath: $msixPkgPath" Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose From c2d774c74e4e6ca356d750e32ebcf255979518d8 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 3 Apr 2026 09:29:03 -0700 Subject: [PATCH 239/275] [release/v7.5.6] Bump github/codeql-action from 4.32.6 to 4.34.1 (#27170) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 201ffa9791d..0baa21fcb0b 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 + uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 \ No newline at end of file + uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 763249559f5..bb6031648c1 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 + uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 with: sarif_file: results.sarif \ No newline at end of file From fe43f752acefa28e694a394b2debcaa1d53b497a Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 3 Apr 2026 09:56:24 -0700 Subject: [PATCH 240/275] [release/v7.5.6] Bump github/codeql-action from 4.34.1 to 4.35.1 (#27174) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 0baa21fcb0b..75886342851 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 + uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 + uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index bb6031648c1..ff9f7b40b18 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 + uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5 with: sarif_file: results.sarif \ No newline at end of file From 87feb94d05dc241d75f7b70d136e63a3fe9cdb35 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 9 Apr 2026 09:59:32 -0700 Subject: [PATCH 241/275] [release/v7.5.6] Delay update notification for one week to ensure all packages become available (#27220) --- .../host/msh/UpdatesNotification.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs index 28cd31473dd..d0b1ed4572c 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs @@ -28,6 +28,9 @@ internal static class UpdatesNotification private const string StableBuildInfoURL = "https://aka.ms/pwsh-buildinfo-stable"; private const string PreviewBuildInfoURL = "https://aka.ms/pwsh-buildinfo-preview"; + private const int NotificationDelayDays = 7; + private const int UpdateCheckBackoffDays = 7; + ///
/// The version of new update is persisted using a file, not as the file content, but instead baked in the file name in the following template: /// `update{notification-type}_{version}_{publish-date}` -- held by 's_updateFileNameTemplate', @@ -89,9 +92,18 @@ internal static void ShowUpdateNotification(PSHostUserInterface hostUI) if (TryParseUpdateFile( updateFilePath: out _, out SemanticVersion lastUpdateVersion, - lastUpdateDate: out _) + out DateTime lastUpdateDate) && lastUpdateVersion != null) { + DateTime today = DateTime.UtcNow; + if ((today - lastUpdateDate).TotalDays < NotificationDelayDays) + { + // The update was out less than 1 week ago and it's possible the packages are still rolling out. + // We only show the notification when the update is at least 1 week old, to reduce the chance that + // users see the notification but cannot get the new update when they try to install it. + return; + } + string releaseTag = lastUpdateVersion.ToString(); string notificationMsgTemplate = s_notificationType == NotificationType.LTS ? ManagedEntranceStrings.LTSUpdateNotificationMessage @@ -169,7 +181,7 @@ internal static async Task CheckForUpdates() out DateTime lastUpdateDate); DateTime today = DateTime.UtcNow; - if (parseSuccess && updateFilePath != null && (today - lastUpdateDate).TotalDays < 7) + if (parseSuccess && updateFilePath != null && (today - lastUpdateDate).TotalDays < UpdateCheckBackoffDays) { // There is an existing update file, and the last update was less than 1 week ago. // It's unlikely a new version is released within 1 week, so we can skip this check. From 886273871935a2da9e12e48fa8ded7a5d3a48590 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 9 Apr 2026 10:00:12 -0700 Subject: [PATCH 242/275] [release/v7.5.6] Redo windows image fix to use latest image (#27222) --- .../variables/PowerShell-Coordinated_Packages-Variables.yml | 2 +- .pipelines/templates/variables/PowerShell-vPack-Variables.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml index de3ac0ba1b6..dd67d509a8a 100644 --- a/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml +++ b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml @@ -39,7 +39,7 @@ variables: - name: LinuxContainerImage value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - name: WindowsContainerImage - value: onebranch.azurecr.io/windows/ltsc2019/vse2022:latest + value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest - name: CDP_DEFINITION_BUILD_COUNT value: $[counter('', 0)] - name: ReleaseTagVar diff --git a/.pipelines/templates/variables/PowerShell-vPack-Variables.yml b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml index 276911a35b3..7f00a5e0e2a 100644 --- a/.pipelines/templates/variables/PowerShell-vPack-Variables.yml +++ b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml @@ -19,7 +19,7 @@ variables: - name: BuildConfiguration value: Release - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - name: Codeql.Enabled value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack - name: DOTNET_CLI_TELEMETRY_OPTOUT From 38dae92b0e831f093936bdb0ebc7dc395015a167 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 9 Apr 2026 10:00:31 -0700 Subject: [PATCH 243/275] [release/v7.5.6] Change the display name of PowerShell-LTS package to PowerShell LTS (#27223) --- tools/packaging/packaging.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 494e2960e1b..269715d3551 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4268,7 +4268,7 @@ function New-MSIXPackage $displayName += ' Preview' } elseif ($LTS) { $ProductName += '-LTS' - $displayName += '-LTS' + $displayName += ' LTS' } Write-Verbose -Verbose "ProductName: $productName" From 147da846d04819d9092f4b8f62f423db14ab537b Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 9 Apr 2026 10:00:54 -0700 Subject: [PATCH 244/275] [release/v7.5.6] [StepSecurity] ci: Harden GitHub Actions tokens (#27224) --- .github/workflows/copilot-setup-steps.yml | 3 +++ .github/workflows/windows-packaging-reusable.yml | 3 +++ .github/workflows/xunit-tests.yml | 3 +++ 3 files changed, 9 insertions(+) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index ac57bd87b5a..6b6f3a1f928 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -10,6 +10,9 @@ on: paths: - ".github/workflows/copilot-setup-steps.yml" +permissions: + contents: read + jobs: # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot. # See https://docs.github.com/en/copilot/customizing-copilot/customizing-the-development-environment-for-copilot-coding-agent diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 77a207217a0..436287e96f9 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -13,6 +13,9 @@ env: SYSTEM_ARTIFACTSDIRECTORY: ${{ github.workspace }}/artifacts BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts +permissions: + contents: read + jobs: package: name: ${{ matrix.architecture }} - ${{ matrix.channel }} diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index e16b9fa068f..1495f91b9a1 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -14,6 +14,9 @@ on: required: false default: testResults-xunit +permissions: + contents: read + jobs: xunit: name: Run xUnit Tests From 74f2550a5626cf39899748156d8c273abfeda55d Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 9 Apr 2026 10:01:22 -0700 Subject: [PATCH 245/275] [release/v7.5.6] Separate Store Package Creation, Skip Polling for Store Publish, Clean up PDP-Media (#27225) --- ...Shell-Coordinated_Packages-NonOfficial.yml | 4 +- .../PowerShell-Packages-NonOfficial.yml | 4 +- .../PowerShell-Release-Azure-NonOfficial.yml | 2 +- .../PowerShell-Release-NonOfficial.yml | 4 +- .../PowerShell-vPack-NonOfficial.yml | 4 +- .../store/PDP/PDP-Media/en-US/Error.png | Bin 120539 -> 0 bytes .../PDP-Media/en-US/Experimental_Features.png | Bin 161370 -> 0 bytes .../PDP/PDP-Media/en-US/Feedback_Provider.png | Bin 167038 -> 0 bytes .../PDP/PDP-Media/en-US/Predictor_Inline.png | Bin 110258 -> 0 bytes .../PDP-Media/en-US/Predictor_ListView.png | Bin 146469 -> 0 bytes .../store/PDP/PDP-Media/en-US/Prompt.png | Bin 132747 -> 0 bytes .../PDP/PDP-Media/en-US/Stable_Release.png | Bin 179123 -> 0 bytes .../store/PDP/PDP-Media/en-US/pwshLogo.png | Bin 13152 -> 0 bytes .pipelines/store/PDP/PDP/en-US/PDP.xml | 25 -- .pipelines/templates/package-create-msix.yml | 197 -------------- .../templates/package-store-package.yml | 242 ++++++++++++++++++ .pipelines/templates/release-MSIX-Publish.yml | 14 +- .../stages/PowerShell-Packages-Stages.yml | 6 + 18 files changed, 266 insertions(+), 236 deletions(-) delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Error.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Predictor_ListView.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Prompt.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Stable_Release.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png create mode 100644 .pipelines/templates/package-store-package.yml diff --git a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml index 55d4c4557d8..0b417df5c05 100644 --- a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml @@ -45,7 +45,7 @@ resources: ref: refs/heads/main variables: - - template: ../templates/variables/PowerShell-Coordinated_Packages-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml@self parameters: InternalSDKBlobURL: ${{ parameters.InternalSDKBlobURL }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -90,7 +90,7 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - template: ../templates/stages/PowerShell-Coordinated_Packages-Stages.yml + - template: ./pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml@self parameters: RUN_WINDOWS: ${{ parameters.RUN_WINDOWS }} RUN_TEST_AND_RELEASE: ${{ parameters.RUN_TEST_AND_RELEASE }} diff --git a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml index 81f343a04a0..9419d3f29b5 100644 --- a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml @@ -31,7 +31,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: pkgs-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ../templates/variables/PowerShell-Packages-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-Packages-Variables.yml@self parameters: debug: ${{ parameters.debug }} ForceAzureBlobDelete: ${{ parameters.ForceAzureBlobDelete }} @@ -92,6 +92,6 @@ extends: enabled: false tsaOptionsFile: .config\tsaoptions.json stages: - - template: ../templates/stages/PowerShell-Packages-Stages.yml + - template: ./pipelines/templates/stages/PowerShell-Packages-Stages.yml@self parameters: OfficialBuild: false diff --git a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml index 681babb2220..b524cb0ff81 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml @@ -17,7 +17,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: ev2-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ../templates/variables/PowerShell-Release-Azure-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml index ca5a6383f33..7864513fc2c 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml @@ -33,7 +33,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: release-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ../templates/variables/PowerShell-Release-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-Release-Variables.yml@self parameters: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -98,7 +98,7 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - template: ../templates/stages/PowerShell-Release-Stages.yml + - template: ./pipelines/templates/stages/PowerShell-Release-Stages.yml@self parameters: releaseEnvironment: Test SkipPublish: ${{ parameters.SkipPublish }} diff --git a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml index 642b169adaf..f1f4211ca8f 100644 --- a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml @@ -33,7 +33,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: vPack_$(Build.SourceBranchName)_NonOfficial_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - - template: ../templates/variables/PowerShell-vPack-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-vPack-Variables.yml@self parameters: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -82,7 +82,7 @@ extends: enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - - template: ../templates/stages/PowerShell-vPack-Stages.yml + - template: ./pipelines/templates/stages/PowerShell-vPack-Stages.yml@self parameters: createVPack: ${{ parameters.createVPack }} vPackName: ${{ parameters.vPackName }} diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Error.png b/.pipelines/store/PDP/PDP-Media/en-US/Error.png deleted file mode 100644 index 48e96378055b5d7fbb4d744007c1ebc073da2453..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120539 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

qKdpe4ED4mcn4J%^2KM0@o*9MuqiJ3p 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 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png b/.pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png deleted file mode 100644 index 90420254a8e4a4720601e3050567db719819efc6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161370 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 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png b/.pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png deleted file mode 100644 index f4084360d5c630119e469b721dde87920d5a8346..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167038 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 z 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 L$C>(5*M9y#()S`v diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png b/.pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png deleted file mode 100644 index 3b8d62284859c6ce60c96d643b3b2bdb994471d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 110258 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 W56C)9ct$q>0000&bOJEruf;N2sW%7_MGX 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৉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 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Prompt.png b/.pipelines/store/PDP/PDP-Media/en-US/Prompt.png deleted file mode 100644 index a40d6fddfdc44c9f7fb643ebc4e84eda527a395d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 132747 zcmbSzXIN9~wyxb}MMOlYiXsXEg3_Bx6A+MILli_x2nZM;K!`3~N-xr+B}#`tkP>== z1qdA}A&>x3LI@B7LP#Qna@qHswfBDRbMDz|?;n}@=A3!HGTt%XQNB47{lMJl#8Kg+ zd-m)(VSG>DYR{fy7x(Nrxc1wj-7Akz(ogMv?G3Ury1NJ6FFL<_qUPaX{KU*`kIZiS zw>^8`c<(vzx1a2Ogm*uC_UwDV@6Rj8F23LYXZzsV-)@e-`Pjc_&+R?N`gd$X_byIC z%P$il^!1c=*NSpC!Pw@jR+5+pdA{I^x*2ijA|tTs1=Ycy5{Jkg@3pmm-U7cryjlF{ zMN1Rtpw@#q>e61#P?d7qWejip`6WT+zIek8Z(k0`Fg`3^UL-4jF*Z2DR_~ryI|XN zpFX87yT+nSkjgc&=1D(7aOmO_Er0|-;XEDMbCcJN@5y5X_L#u1A4nTjZejX;w=AkR z&`Mjy)4{n}1si2xQoNT)kPHt$;oe{)q*r{A<O$woQX}mrgw~S^6Ge=-b767>uDvn^-CEzlun{|>i9sb;pIR>d z=$+H>ysV_#I=duMfN6v=3o7x{Seb&22#bFXZ=Vu-Vo8BXuX zS265`e5LeweO1=zIb?~*IB%JMt6p}%ZSx7v)#{n7{~vS2wtjaNW_E&8ek2Dp%zIC2 z8;A}C`c9V+o?gdvA;k`{d0yM6I>CuJPEK7m>jwXhm-Xq3hEu29&C zvo>Sl-dEWckbAju~RRAkh}uhY*C>b9N@1R&hETlk4eB!h`Uo&)8nSx_sT zt;`x^T-@okT%5&OYBtVEl3aTn*ks{8#HY0ltu63>Cw@ieLlsI`Md>i3l(b-oP zs0>(VBBL=BP=2%T(?Ab*D{5MM`Ua8SQCgW}9apOpPgB{J1ryBidLCwKwljS_Lu!_E zTB*fIIO;JVq?4JwE_6b$O2alTa2xt@HoO<*C%}5}8_+pCmLro`)uR$)U3ZOPB~eM# z&Yl7htRgpPLQ-tj#g`X0PWI&i993f07le(VkSf7T-BvAYHD$ExQ#d$nLk(iRPdxi>{v+I! zZR|6-TiB&G{jHi>?N|NoNA3Xol^4id%cfD=H=8$!_KS2&aeN=tDXc7U;ItwP6D`+q z-Zp*K3L^(EQg!#*j2c;FK%l#dG@FOy&kEXBFB|n}E($?}H0yM9!Gw3d#ce2=^BS^e zSfV6I0D|ge`IXuIOVPhV8ZI7-p+UVX26ae=5zKsZyk#Y2|0uUq#?X(}lz#`h*9M92 z4@U9ee)VfWkXK2EGFaK9wiB}2GHeJT8h|q4qD4(Y5Qlma+ zL1!<;FFH>uAQ!^RqM^6i*_MbzyqI8<>w`%xi8$HHEP~;7)<~s;k-UYylwR!@`EaL- z3JyxRxU_9zOP^SRKui$OOWDFRh_cv7nbM82kMq>3Grn!<9n~nw?p9V{I+{n|I zsqk{b-&0Pjd|gVnV;d81(*_-B%=Hpi8bRe5*4D0FLB#ur2Xd}?0(Y)1OD{+wV{7K^ z?Dv;#%b5^FOUsWE?w65Pm&YD19f05tCkuAwb*#d#X*Y3o&eMX~`>3)df8B17Z}%#6 zxCuOpwl~EX)7rCa#XaW3Y+ls%K6A)HfgxpITMRx&?X^8a7>ww``95fmdQcXlz?SWy zhF*0&6IR@S4glu^WVk6WA`^eWRm#kW(mE;nx=gB?+suG&sp%4(dK}PGREF?npIl%( zpyu5PM>99PgqhD=Ih6|#P?570(T4FL9EOrDdz~N5hB2803+pwd3Qd0k?-3+DHsAaY z=v~M;h0^AefC`!CVQ~(63sj2R_WJU%>E+iQt(CG1W1;L{rD?cAa0#q2wdsy)TG4p9 zlnhG;?{zjWXi_8)q;vBGchC`+xEeN%=;k{3p;lhc(%SgcTf`nrv?x`{)K4;#EY zNWG?Q+qiR9?nRM`#ct?G&yl`or&!+t2q>o{la{Gv;K5-^7pjuPP$SsVuNBl=!uzBb zte_e!wf3&t)=}!CY{HAOXXk>5Rf(BRa}Veha*1j#LLM}=Qh$Eg_(2`}#j@+KEz2G3 z(ekrYFoT#xT2~+xVRyu36qE;w@>`D)F)XXcvX?+tALZHc!XkG^Hr8dmhWPJ-JLFab^N(36WP^@m0 zQv`1F+Azx2N}nxL>)Y(X7%j&ylDYSwQwiC`Qw(3?NhDtDlB)(Wuk4`V`qRqAGagKp z1z~v~>wf7DSzda&hchNxLo7ov2;iE(q3_Zs1y|O^kEqmn3DId2?&asC`w4a)imGWw zBDygTyeX;lY0*ownegqxbz5v+$abbx9~RxiweI~2LS>y(4kNZ#yexug#N76w2>?n% zWF25-#K!BZ%Rt67sX+7!_Vv-!ndOx8PNpOE-PxUyBiE&bgi;bgC1X`(XLL8tfZw>u zhn$8Hp2Tk{O8^EoLxS`AbxqwHo-IlHs9Mh4XxB~}{qF7~0gA<`*AYW|*J_67=U4K~ z!WE`C%ZG;tTx^enV^C1q-SgbO&kZe%02u%j#zDGZ-Qi9E{22aC+fCvG3uEHn3U!!^%GU{(NIk1IBD<8|Qsk1> zv$}QT*$DQOQ{tK|^ZbyaPJ zhYtn3_UQFjdyNL`4=f4a?9RfOW%~+&{JMMUj*hQreSgvFKZB(okWll=jW#Bn$=wVx z+~P9S2kz9(!`htN>0D#%VBrghfUUri9B1=J21@TJqlRb+f6}cHdu)__*-%-?a7*$& zUGa^Lvx37h1);ppHfI~Ycmq?T3hEY63X{*xkP!iazL?SbtP{ns+E_JHDk$Ng)2;im zD2sH_tA2>YS;|6XSFMU;$EXj0P*UqNd@Ekw8z@w~f2U|?TJ3i`4~;(fFDnP{++1J8 ze)_q_>jziefEhB>+Nf;a8A?9-s&L4=<;01Lu3CCvtchL++n6y_zXn9axy|IeAU04y zW(8w%^NO}SXoOCAjnYtUv>&#zZx zw~)QDerK#ya-)cEZtB9M<~FWKt|MBd^dq~%8e`V3__@qXT-tCneDf(?$?xW}%)RD- zLFF&EU|A-8#Q;}?>Lcfrc=e2UY`HfjPBEfjyiM3PB{73D+~PL7zF*&m*%w4E8CJG5 zn=%wJ08gRd!_qtVEh=C7oK_TKhHLNS{D@}_L}JaS`5vr=S!(s&th{IhT*&Ns)0#o` zeEDPJYHTpA>DHU83QJ9+TGM*zs^-owY>pG!t{vUFkwM4(NYV|Ofe>{WHjeccM)NJ} zXQ`@EG|P?6BHdc{lYkT5+`MYAE90leYq>yBA2w_BDc2U679^ioW17IMjHn!PSSNY8 zTBa`xoe+Zjn7}3Uv19Ad>PDpfspAdBhV|THvX)crLhFuV1M4j!^5z%)}!$+*%+jffUVBfJ#nhxX5 z-V!T)llV@?$_2)XHk_EVOgOLChC7Ez$lSlsjJNKbd20l6GkP_u0~stAZWX?gIo>D$nz~eDfp2_c>7qXMyt-|xB9uvfiKc#*M1jT ziMgTfw=~*&X=CI>{(I3b;&gkNaTmunPU9YbP-w8h9}-2KM+*$+FE5}3)@_0Yz!5HK zg}Q2`Bp>^7h1`w$XM6<>P_zuuTPBf%OAId*$CC>{Gze3v-AkoUaW;dF`WRCjSyk}N z1)YB+DIrTSP^+TwT2GKS#5;GE-3|hzWf_IXLJL+mBEiB53n}h1Dju+=X4ngw*6=U3 z!S&vQKe9J8UoPuiNwcFV_0W~rc5LXjHqMCKZ;}uNZCl==Zj^>BW#hZ)8l%b_SXh^h zoy@t$v>*`ac!hP9+v#hDe#BQU3x!Yg0EY3o&GBW|y4}o8MP#?X(YHrT{TiERwX~Kc z7vFtt$iUn12^uZ_U?`4U2Ivv!pyKt}uJ(!Phz5Idv(^BEl~yQENc*YjRcbx|zN0ig z3u-_4R-@e9R=Xu_!l!nks7@BMa;4M}Vm#lxTXrk6eW>5S_*}T9$?5w` zk<+}qvW556i%$Ai7uKdy;FRRAk74Z2rlZ*hrKh;4r#bo_tue5E9CW+@w=iAPuWG#n z6r(H8Yh#?!67!X?&cw6%5E!Ni%dt;2d}e)SowzJmip3ceOhe99ozY5w=|=eL zw`%P_F+O!GGBUo-rv+Sw>hPt4;OB+IJMSI$N)%uVD_eU7HocC?sVtN!>nVKV z9jjcTl|ZmK5a8Oc2Z0W2K+e!@14zmqec?~7)16i5F#=Q~PiCS-@ikq5+F^hiU1+Zw z{V{;?k#ILc${3!pFK+a(J|`|yS(#BjRFG1gJ;Pa1m%*?%sw=zQdf+N=mrtb4LyF|K zX!B9#1fb%22{h-N1?-DC-pRe$ye5HyEM%bUgfDFoQCKUkB4tEpdNv%bZV!b@q+gtN zO7+l4&^7YSpkro~>ln|_0X8BmqU35LZ+&{YJ0b3djYH0vH{QMccZNc38-w)#F^shC zY=5)nYCV440oQ!P4++?+7U~0xj89%+m@TO1s}QD1ys>PKDzy!4f!h;~miz$_X_H@-XK^wWD6l@Z>oWWUb_%FA)3!|r=w4f6pOTno;x|Du+4f9yQ80+U{BFeB9fL3Lw!*@#%N+uiQkEN^~FWAZd`yO1>&qUVZ)Td!Z9C* zjFWiI^eW4F*r%lDtx6X*%8@f1U~MbrO>_z=J0Ad+wEH-NMGrrH49Igy?+I%5X=#|_ zzs}5;KdRhNSs-KA64*nx99z;H8L~)64SMRHzm@1P!{)KTpZ*4883%+U64T|~7CzJs79oHMX)#osXiO%)b8q1HiAxlV1)+;% ze-zt+5b@S{vLS}XI=8{f_zk`A<h*M9>i{=6Do$e~qo(uD!prWms#*TSKH#jSz9K zy-1TWvB*Fp zsB+D%V071Vy$1RyqbWkW#%!b%?mPI@CbK?zVfKPvILk)xVt(#2?LFA*geB6)iDF~V z_9om?Bnb)^H+}D8cY_?l#B(9Jx8Ci`HNV2YN=8V-M8B?lFz$IMMYv{SQ)}#K@3s)^P z&;h-dEb2-Vb^2VjS6#Ao%$Tc2&|XXMnVUX(cj+4DJRhu6%G=+j`OF~*(GhgRtmRqv zG>E0$5}Dc4WCc%V}M zif^n}-AJBjJ>c1UXAOX}Xd<~w#>t8kq%Vv}FO>vr;WI$}ij-M3x8@f_{8?u0K)V^B zcDx+c>oM}nk~krV$~7uCC93PVY{U^JQL9acc;PbEl_t$Emo`AmLHVtNFE!`sMQ(VY zSBY!uG)@eo(|*3b6y6qt?Bc%^PZPVuX*kDR4P~~qZV;fb95mZ2MajJF!Fa=p{cus- zdHkTi&4i6m2Bs;YNqkUcNe~lT9p$|AX1XLViXZZ$d?C1H#89w(R9s=Y?OBg*RAMM3 z$Lq`riM6sCgq*v+b&CI9X!#>vs?s6Lw6QQ)@8FMfyy}6sqaFhvs2|n~71?rTmoYu;K9D*o z!;El)G_O`!8l8gtn7>}y+Zyr0jQ0f1ui5@!I5d%fvHalQw`EzEuwuO?6HL$vF_B)G zdhhTRn_VZPfWJrG_%*-X+c$Ed;-a|`0#)5|ZJ{GFNi-%5Hk(jqY2WuTlkqby=w{!g zfr^trZl#G+K#*2qVPNhVas%4uG^ErSg8fAv^u`QPELmfXI6a}p)^lx*lvuN7M zE93;!Um2=)>k3#u@5uF^v?kuEK*c7Ho+5U}_8fTC;Oc{xD-s|YdO$=Dn!%xY)mlzY z&VyIu3w11K_qzL$il==fG~2BJn(0>rkjGZN2ETHrq|J)6p7u&3PNqkSmq4rDkLYyY z+Of+mt8Et^GRE{j6Q$%K`%zGR+m_@4KU|4Jc&`GY`plNw^{sV-2tR9pFTZp@12%k_ zFLU-xWov-0DNC@^-O$i`^jaXpp#AI>tYKxLsnG4u0UJ);P30dk2+_*Ur zQ4YVoY#dlxsngmax_UuIfqsf=uox&2^kDqwyS~P0jC(5BRPSMNIbm5>lb(;W&V?h`O z9R?BtXWJ6{Sa)t(^`d+qO!3M1hiAY@5RV+S1da!}`hLjo=%nr;5Jn>b>IJMjuUvc% zg-r|~(UdK12cP)WOF$63%RgVY_`E{{ziN$W$FP(~G3G{H>R3-eyO^abB2m^F+8Ccxtm=ig zLWV8+n9GO|%$Fa{?{JvRwM+x|f&h~m(Fc^25RDQXAxP#ZC`Bf{zo$CSJK&u(>9V@= zQlq7^f^Jt;U~d=>H+?Sux3basTeFTX{dt)rugx)%dpNl114}e0t`HpP-)9{(;#eC! z7XQ-c(i1<*NV^N+ia&JX10zKy5LzodrRrX$<(oCuxLmSYJM!Zp+mV_t*;X0u+5;bv{9i5B z0}JA|FC`6Y6}U0kb+;7QppG&!H072b;6}vz-=L21&aVh2f%nB|RkwO-@9M^{5Q-er zCBnDwm4SW_SJ;XxceAa=R9s_0O5Ik?1uH~ZfQ3qrir5$sGZWZ=Ys3N`Ke@QT0YjdyUN|wvM5N*2)Zzw z<=iBFMj9Z{&K=zrB;Hc4>=+#2*c6w{FOS{IJ#?kR7O8=*H=|GaU40^B`&IN3yU#2r z6J6?GYT<}hiz%&sGB=_Ei(MU4Ri0{D$ZoP*L9G+|Ml77$-y-F0u)<6=*0XWe{0%o zL4??5^usm+w5d+0%1b4A=pF;_&yBr&tQMQmav-xd4US76unyQrr?j%}Qem3s3x4Xz z#smH^6Dte9ieHJ*GXg)Ii$cx@3vACk2G4I@T@O1B@0-^lvQkig6y(dG70Nfhp2~I?=PZ(oiw{z^U7N_WqlPvBG^}-#+5{BXgc%YuN0y@L6YIO=P8z!6N^^KbhMP`Hs%LXxq>T+3*M_^WdFRzc?Xb zc2#tKo;^|GaZX?yp9JgG%%=X#5vhyec`NUiE$+$-B&9`Z$?S#BE~LV^*}xhiF!B-K z>J5*7QxN}mw&$e3Epr#={WsHc;mq1e-ZmfU10$jE@cEF<7ab<|mP9qO-lh=DyE;rv z`YrBqQfZ-*)qT*>z?B0t%euT;7?%vJnfmgjA>f+Pzm3H0JukH7e{Ps6jIG;SkjWIT z9_Mv^i*}_Uv>g$Xb2>RKXwl-1-PB4!b;_`N3gm{aznIiT5bHW^S(haiz5oLD(^GeVk2ky`JFOVAF0g+98zf8v=A=gYXP_56`eh}7YK zQ|bS&nLIW7O^d~>B=-`o!50D|R|7nQNgD*~q^-uz(F#GWy^YlP77v-QjclN@hf>YO zf8Vs8f5J$;*P8aku`#t?Qj*TCp1F;gsXh~fDM{K4HNjxIC-#Q)h1Rvn;zf1_u%WKN zLGItR-oH(1WM5_LW*%&3yqLjS`r_NIX}2AqDkUx}J1&t}4h~xg%*D8HzyAm5?>&H4 z->ZEB8tl_OoS?ljhJ3Cym~C-r@(u+V+49c9W_{Px{a|nxC6WJR+AidMTdo5L=(Nb_ z3h)|#W4%|{Z>t4tp{=UU$Y~vudk76Uhm`Kd{!gHNaO^%njS-E94JfN*e>7n94LGW5 z9~{4#l=fUp^`?8xus!3X=zl<#yNJr&2xph|g(Cud#o)r#(iiDQlBlHO3x`kqM`ZWg ziyonV$6_j$T>b|+;KoLkfysbQMbnTL3{Jp#K zrD}%%Nq0xC4yfrK8Tb9dcZG*N$Ovn{opw#nv2W}@AoX1;x&B^@iqqY6aQ1&R)dVQK z%;>3a%$%>K|3}Jm;ncqFo8rgU#;7@ATJxTeJGV$D!p#CBBd5@=Sf84j8t;VI*w`Wk zl|MQ6p~6v7wWpu1T)DDIfkPI5{`eX^2_cSuetCF!-PMIJ=&uT>q2oZ{$!aL4%B;gZ zIb{Ef(}_Z7&n^xXnyP4Pn|)dFYq;9G_rE=!irH;s&{`q*$&(IwmxhNaDJj>^ueU`D z%sU+E_WjFRy=b!60vug@(ZVp#H0@o>B^Kdv7#0C&2_2LN;#@5JjIMlr|7T~PRF2N= ztiFdoS5{W`AOhjoYv+`x~`x-U(0Hp5%kEzT}RjMntd| zY&GHA5hnTx>iU7ta%%og>m1Z`ot*g{^AGT(!pAe&eob8oqUvwoCUY5CjzWKt7Cwm! z-iyYIF-~gzFfdkF@tR>eC3Fm@?5wq3gm1Blj02CQBvPKY0PJ4`{I}{oRQ)X#318!@ zbq!}?)}B3v*^!n8yqZ71RR60+y=eYo?aa*DFX{{3BaYe9+kW(-0#B*29PRMYqT=G= zZ4Fch|F_u2;`gmUcjvhA#_8CxW5Ej}rEB^#e)Y{F#l1Oy)f&)uUfiLiB&97X z{cQIqT60pLmsj4qo$xpt^bIL>=}+%+>EJYLFiqCpYAarK>K*5@Wa3QTslOOPJCPbVt? zaXC7AV4|)t`K8VM^M8H7js5To0hOMU_q3-LUOklRTZ{NKKkwcAZ2m2n9ZH_*yzzJ4 zOg}nzGi7@(vA6gB#&rY9)$~9C(Z4#*`Muf))$9CB94hyCvtx-^nV_@+2sQ50QYbaa58k?>cdz> zS@DcJ>{`GRAD@`w3(Kq7FX#U|!1%Ou=9{OA)J2BGv-ujqzfO*1`6L81C+KDKHRI4@ zo~MjEO>Y15{9B*v*w5cg<80V_{B`c}ExwK4v@b?2k5(M!6f?l>XN^0Dhlic{5%2z7 z?I&fa8#iyJyiH=Ck3I1x68|dBegPJ|IuxIMc}DKtoy!*#u3s32wEeS5pX>Ey~%RKMF_3*BD;B)<>ziP*H(NgZ*tSakmfeq#-{@jJ_cyN==7DGR-+ z25J7kYPO?SzEy34dQy^<<+Q63|FOh}K?l~xWwsLqvIUZ_{waXles@y?$vPy+azuOFN6Qx0DNZ z{nIm{yemcp$m7k}y*HPfXCbkJWyX(7WAk~7-o0VVcB~=vv)U6jF%jfX#5II-KXxzU9 z^1?^^1Jm<$CbuJh{dl7aCLuRxq~%U0tIAz{kuDhZin`0}uv7(dqpkXGBB&kU^r(Kz zX1ycqX!YvLX2m9C$B!arPw_>6rw9A~ky!j(b6@(4CiGC`K6yPpm!s zi!l7XgZ~=(oYY5z{>;|9=jCrM;8hwW1d{m1UWrMFRvS|?V&e_`@iD;EXXXuNTo^7zbR@s{RBJ?Se;_sR0y zq>stHsc7ai?%OTieqgekW@mSirJYXZ2JH)s{I&8)<7NN0 z>0KP`DHhurQjCQ>eX}(`=&h+cSYrT}SqTQGAV@I!^u_Re`~H5|Ql^^ODt!?t?Ba>n#4l>5+(g`;s3C_P zUX0&`#vP|ElSWtxF%%j&xd) z7Jl*QCLd29uv0j7q$5#l_1?lWxyu(aG*afPIuXfQ=gPO{TRq-S21bB(8YY$0ye;nc z78iU+<}`ku(uLk`Pjl( z1unDt388tz9nJs_gekEymwuNE%T$47WFi709)825Y#*56hDJzTXkB!Vq<$CV;aPYl zq2EArICIr*HvsquJeXShE7~GLQf~Rf8}Vu`j*I0%O2Z=o7FsK>urxXUQeu^3GzxP2 zWU&72N?q92s>06d>$k~NOgY~RKAm6R6UzU%^Dm{cE3R(>*6cHc3KDLEQ0ZsuH7)tn z?ATTQ#;pU7w~+5I-GR3LIIfjamlDbRDt(cnr1m7_q~FKZnjX%#5pZz$@_RAP;~&wg z0RK1JesVFoO?6!$p7I?wr3@dL`T?}w zzBMz9aM|1}ke0W%&__ILNtxoD^bcushYt%R?reUejre_Gn45`L4P%9vamlY*D6U!z z$AJ->Ac=?{$ADv12kO&itE{%dMsXCL{=Vwb(gQ@@UoUmXsu<0b3e{>IK*p|1A;w>x ziH}-B;C2g?UlN|L@a2}Rq}8-P^Wi$hf7~Q(kX0B zm!T|IdTW1E1$UcFG00-OfC>cX?h@!niA+tz+vv2*E#JGoDwqN4Dz(@xeLR79O(SXM zShGJy6VA~NCbmYl!j|<1aEr!mK&`;f+m-pAOw~lJ&knunCI^{-sFyxzPOjy`S<{cg zdDHyi+3?BPE_{$Hr|kubGoDXhltsKM*QXs*1$Y+2e~AS%k_CdRG{JPun`D!+%R@BW z+T{nZYd>PZ%zc5@O73Je7u%2ue{ePj>cGqhe{dv;R!0#y2brACT5wuQtAGJWMDQiX zm=B*i{u~NAIR`6Q6oAR}wV?5nuJAEG_<+cw-p=Zq#mSw`$+}P;fB3jSG%`B})4IX| za@(dAB(kbof6mObu5A(d04vhsK#c!7QD9?rH=xq+FPV2fj=`FPYJ9gstUE0F-i{+UB0#9_u*viV)d&SR#C} zN@K5;MWgG0wF4f+#AV$Z9qCQoY_wMa2mvI(CJqD$x!f!oMSAA%&*7C#g`BY`2XZq` zdtX{{Sk@bqhLqzI?*`@xm+C;GK z6-mYieAr?Y?h5AH=l9E$XSMb9nunwpIopbwv&NlO*jwuUz?B2jmGWVMa}?mmdCL0E z;#_n-X9>Qlq8YXswOhAV&6aj2r^(iEnEpEc8FZlv_|qYD*z?$$V=6!BlkEq077Xr* zgudB+al~0`+CpC^5(~gG4{7rHRY{v7{#9gGVD0Bc+i=*^F8L5ohE6l{!s%I#mE;fe z^D>Y8ZB|!G*7ftKB^uqY4|2Y0m&}ZAAwos%EAD@cZzGqGkMRymL_9SuDrM|^)8i{_ z15OTywT{JArCtzO)-=fx7pl2m0ATLJw>yD%CdbTmd!8jO2=C5z|ns-!A&wh#BvU;J!{{Ulh$mWZaH;VO9PNEQZi-fWLqTK*T z*Sj7LYyDP4{1n)g%kw0lfX3^I>XHGWY^+heja!f}6*1v*WysJOfV8Z{h9a%DA}8&5 z`ZGiE2WGayR2LH=ub?4GHiv+oAEb z`musycXtO&ZjW-3kzq){N&%IQPdC9!?9d8mA(b5Ir$A-bz+uvDXFY|C<(4iiCX8m+Q^nIHTTE+#H|kKy>UccE2N z4NTYG+ek6_h{#3M_-~C<$n@0zoep&Z) zEvZjJ(>Dm8IAU?f+(HkxUD6jm{v}y&RP#pW>9@*r?BUqpWmD_mrrk|SO;+;|#N~IV z@M@F1;T@7I(AwIXozb1vrtD)4ZDy7P$5_^h5Q@Y=F4@7?`|Le>z_hVJJ6>SLVC(&% zsb1+Q9~dn(D`oaZzshVrmQ(_6Odymu$5o}^WhY`M>pzR3o-rYP9pnKfQ!kukBIhYnN5c&0r0OJ;MzZjpc8| zJ5$u8<8{&KoUbO#Zut8LIR8{dyKt8)Fx{=S;Y-bF;E~%$FtXS>!$UrTuR-2qpK68$ zUYp;M_)`G+OFv8ZNN4l5lF}WaU#l6dIijih<&WK@1S^AO1(FE#-S|nto}3o^mjJwB z_)zXhC%>DnF25savE#1h_G1dR$!tSuX^G-RBtO#aX3RmSSLUOk*~~Q~dB$Sld0vfB z|G0lk=x0QW8rc49crZD6KL1LhgBeP}fPiLGS8L68vl#)(o2b77~jTz4$%hFq7OY09=cmfX9UYbZ{>=q2-TZP~sL z03b&~If0Y`zP02-fs@_aci-4+N?*zEb0yUaBvX}3l#`yfWT0m-+C<7`AEkC6V)o{d zJJFqCN~_INY_y=|8sEi8nti0yZYeNcm)kf1{-y2Ke#iUo)sFwS2J=rhKIsTKSnLZ- zTI|uEk)b!3-%V&=YTuf9_+@Iab@!pP_q)+r66S=K5VS)eDVzXpM8DA8SzqXrUev5d zR`1+U_TO2d#d5lP@A~BF&%jqYL>7^hVC-a=7u&egXqFco=+l2Pbb6vEcnbL{hnhxR z;U>ofyx-@)O|S=Zh>RgzW%pxpoq_rr zj`pA*S%*@-9v{Z61-dhNdO_EKKpG=odmw=B(OWm(phMHv^10tW0=njc$DTFBPIX5L z!$&}^xes;x5SH6x?uqS>NcGDH$MG(N_mesr8C=78aW-l^W6N;-n&G%1oz|cMWYnc| zw=o@4T^tX|zzO{23(LKN>zj04|J|f?CI-0DD%!|EH{1D&tmv$FSuFMD)jb;7%gq-Yx2+&4<$h6jGfNBwZH>OAn#g^No4F}d5k4;^+=A%>)2ma_RX}qU`dZ=@Ofag zGVRx{=j-dPxNkKQ(2VmHsWPmvW!7%5MwdIK^edxBNt|o$i5hlrw(V*6a#PS-_xZx= z68oG!S8hoo*we9bbXDAU;87u?hF@qsy{mec>`r=oDV}Xg2jMbV)^5H~i(2}5Ix}3l z8$SW#pjnzF~TZn!ln76Qj~_nwF+WA zT*JxzRMFG|F-5yDAWFKW_j3b-kboU!*S)z;EN%)|e#49m|KYNXp=o1;W?Lw;C44_j zWTwiPi14NHvTx0jewQUdO1i9@y6zI&Ki`1AOMGYRtc_S(oajqFFmv&w`Tqjme-(3H z04~1IN$rdHls@epzS1r_;~(Er=qEpBq;VUrd_8yf6{eKR?dFD5pufvv@mBu zKh`E>7&m+5cEqaQky=fomddNJ&)27Q1;!}Ke0BiEj8#bpS6(QUHs*uo}Sq-Vl({tRn)kT-<%_DIRzwqJ!b# zLJnSk(qEZl6eqyt238hZZsqNm@K!M;igwLim=-v}qLQ$Rz2o7ruezUL#EpcSk(Mv| z6oV%sMzfR1k;_Av;fQW-N5HZ=)DXJ8qLBa+fS@Kbh#+MPggE^pX{DQ8IuKY{Pw1GC zV?JAMV<)AcjdSXk2PT#1TWWl;d#=pGv|r!Ql&ji5Kkerwy8}Qz(vmx4iCYda`8>7L z$?T~Q;Rxvqm9g*4|D|{QRCG*hV=f<(=RMO4p1shz!)tBL{1JtTyM6g6DjLo3VO{9> zBW|1Do_AG*=&70!!b3!q1H&QK`&O$yUko4qo(jl0Hx|OzJGSdQ2hdAn+Q;579pHJc zPRrl+hOc~Gt{#>M&BkuwG#4p2RxnQj{{2KSQu=~K?p#qYrBw~w%Bv7sgzrqLhew8e zSZW^nylcseMK^_*&678`ug^|$&pehYO6~eug}65+D?qUkq79-a>IJAI|F<4iF3s|9 zkEQjVXOgRyvuq3u@X-zBIZcg3L}HE0V^dYp->b%+y*KXEF0;K{BlrCD-Kpab#QJtd9)oXu{iSBp|+bA()Kr36NnSK+a} z&^%Sa6b>L&ez4?jHQ@L!ah&YEPtioiWv^+dv=f!DQ$$SZUiAXJ)hxefn}M(x41n8d zNXJ^i0nPW+Mj^JRBPQT75^N{nwJYr377L!APS)LCNhBjTyO0ImSNR?3yFse;#*lxY z<@R?vm*T#&wm*bywA45rxjD*UPBHk3L8>?Fz2Hm>rEThNs3g=1A4KFh)}EKT z5|W`~3>|65&9DBRs|N4F4a54*YGN(T>M-}aaLnR_I_U>jCek3uCAR5lcoWgM8FcmT zW0%tW8Atp)hU_m38!F|#J#uNiVo`u8$qD0_bc?1fmN>{(U_=!VP34U~35r~={2(bw zqvop$ToCN7-*`v`zNaF*qH1(F@)Gx9Tzxu2V0RBYL!KGlSZfTtDK?Ano?inh-gU%i(sbt`iC47n_UWHMyB{t~>EjcX91NdEJOrT$1^vJ&V^odt1-A_%U3u z%=6`N{rRCOgK2o6?dmw7l8veFm%X^FCTvF2yL-Jp6SRDzy{6PJwOC$s8~0VekLq6f zSeekU3)M~CIiG%f@7{ogMXj03=x#RYMg}@;y4$z)qZ-NJTsAupm2lcfV81JRwjY}u zQDLeN=Lu`Rem_2D8W-JbFrSHiTB5|%7Eb;dn0~2RU#S8h9=xjD{2vw1|0u`&=}!;T z*3S@hZa86a8(BXmHtJg7htcm=#s>N|9{stodKCAf{S(tw+b!`oq}vO^KaU2F=`@pO zoTuca5mjugbi{*^7;2C%%;VDp9HATHHMq9?!+y%XeQx`bF0tKH)zWg<$jZp=&C>1p zkTCiuyDZ0+ixl1d+#4;rB2DeHw^TEPms9ne_c1Cjl$2f3nYsKlWlWskqhR9fzSzrc z%?KM~XI;hGGcF_3^TZjZA5Q<}!_Yd~8@iOT$WinN&R5)5-_NX7pvx40azZ-I$Z0fQ zS7Uv#9M)*i$#?3-n`F7Jl@K-4Oe)uIOJTuA`P4sOm}G(93jU zW*SPsz6dne(N|twfcvhCvSwbrON}ju#5iN;d#3O;$!rD78Wn<>R5fGZ4Ckt5*xr$a#>W%<55`@(c$$26`E~DaI1xNvysWe*EgMogZ60)D(eZTV z{b;Gk?~fx}eSb9P);D_r&Eg1o#+Z4H*+9VC;|TdvZjAiO%bDMGRlbIP*6U2G2#;=x zf%?~|qVJk^*SeO=y4h!`tq1qy7z{pwjxcNALTFjb@NQN+03 zp!&>-;mR=ogNZed7;9-4r)=3*M3SM==B9&ngNygxjt{sHzhkA4IihFf=xD>WAov=S zGX3GP$r8Sujo0IX6{&6^aZ>RPOys+!$8_Mwbm`=NK4!n&bo7}O&GpA4iH0{zORo+s z*^BJDI+zz#Zee8-{qDj2yy)(y?6I4)hVb?0@N!n4P1wky**W%??juWRB7DSvwVg8c zz7fgpnBG6V{CK10N6DPK?8&Jci1DeNF`wqXdrP!`U2R#cbgACeOtD#QU9LFu+QnDc z6^O)q?H%7*Uvy?Z?Ne8LdDVU&LdjBB_Doz4fN`k3J$o_4_2u^Ml>?zw*A%t-pPd;? zG$pFbhJ4mC%yM+Zm-@*jIY3;3 zac1&n*kk;2W|Ha|XIy`2fZkQ~dUH5_ZZq-ne#6;Kx+={Xm{N_dbByDcod!|C4l{@lTb8xgctpWuL3zu5+rq|*iPlnm^pb`@4js`P zTE*-Pbv(@-Ty7SJxlpMM_hZ)xEOBNl0Qz4|H;NRl-E?~UvC&HF29NBlP3WnKSNyt1 zYCP<9^{IANAv2cOrZDdd!m#a8C|5>bmS14tYZbSaD^^id7z=17zS7R1SmE8XGi$|T zR^}wlwh!M4(DyftrY?r9XH>0EeztC=8R7OhZ#O^RH~;lk+em0w-_*VRvf&JW;b2|< z5Eu1__X%=b=hBbfZ#dyPTC0-#WY{v>7qus7c=|+|uT+8Xp)}J%*ksB3Jr)OSBot2g zW?S<|-*Y#}ah$)pfAJkbt5#LN9y+oolNz=(awc7U&}6&5t!hCFiu&44DpgG@c%%!i zHTMojBskrJ@^qy(8YZiFu_f~V7*`tEdtZ%0&PI;4EaA&n{-}3n&8oLyqh(7^z zcIbP_(Ss*G=IZ}yS@{zV^Y`+Ot2Hvz=Y@Hgm*m*)tNrm20}s^I(7w2TS_cjb9u*}i zV%m~cpHkWm^{5UL7FrfBiB6XUF#Az4RIBOnDm`DDb+V);6O}aVQWa3tx(2s-UjH3E zy_X~d`$11Y&;nSv8DG9MEy{_n$d!`NQ zudEi8P^S7hstw19)^W&t1uH%U+6BWUE^*=Jh4J;n2W$KZ5@~@r%UYZ4fve_Y@%xXU zSBLr0)7p>Fk!WAE61E{^Wc+0_JK~7zHEbGAcd%_3t~Z>{>dkh4n+P|YVIIImf8Kop zNCwKUm9ME4-gm4k%o$#Ir0gC)K727rt)Z?(K;D1h&;#^Nv$&F=0H3O*f^X^kSnz0DT*eobd~6@r;W0-=)3Pi{07`YaGH~mDN(1xBB%#MZf-pFrrMEC5PJm!Obi1(izAT9@^-$@&n$cY0|J1U&36hKC%&#bm#~ z)D!TTaGup9KHyJqF-r@0v0j`(J>+ZnPRorkoQ^MM)YP^iTsj9d0`@x{RC`J2TJnNr zF5_ox>YZmIKG(Tbw$4>$2Fh{b9)Bvq)q6$__+A)#O@=sAXi9i2V{Y8$7kD#gZZA3aH^W|7wEwHzmC2B$ zajW&T9F`Ta2A`KxZ_}R}I^8Sa`lx=RJ>?t#;CO4kbJcyH_Bk8_$L~HSK9&o2PF3| z7Np!Jzkd!beNdeF)tyZ|=Re)?AgFyIlj!RG^4Z7=yKOO2-==eZt7=R2i&y(nSMkj4 zc&pzGeAef_^TIC$cZ%vvAH86uEp=_W$lLM@V%}`p&?Q{6PB)yAxb&J$tF>SI=#10f z3iNDzUCm~z=0%U@B4!Nn>$(gL7Io%FD7ru%uyNJSyj`ZQ3bje*7e^{Wh?Ou!NA3GB z(ga&l_IfHDjrk^$S6oy{_R!=x!Qb-3B0wE6`Y0pgWM0FGy2n@Nc`dWGtv9z``*9A@ z!^N4w3_Qd~SU<9E;Z%4(c|Y`(x$&s4GjS#CC9x)4MWP0pd$r{y+3_9hxYnXT1lx3E zrt96QW=f-@E>6FFMnT$T3NJ~yG+lwssj2E~yHXWiRjw;43G|I1N0es)FnHip4Ny{} z`R7h1^;n#GlXAVB|LR^Y$co{@2b046D!w+WiJfPV%m40;Y%YgfX%RF?YisGjd}*EZW{yeV(6*|YwLKC)GHMGH|8<6NDK@cyR3T6(o>I<0Sf zar2Y?Kj|FLo4R4osT%Wy0h<`u?%cgZ=&9heqV*RC}Hzu?P7j45D5N7-*plP0Q4@IU*&}*LbX#(W*OM zdcfW5Q@bA5mj^!Y3tIQ77{r?bbRImIUo_t-5{cUbZC}Js7Ks=xkKJS?CMg|JnHU4;Sjs$_S_E&qsLVEck9UlRwIt!u>UV znYxU8<>A4OCLTcnO)MfKaW68W-M63kQ)@Rzg!_G#C$@h7iXPs#d2KIwGUD24b50t# z{`37~k9K`O@u|j82zCy2{JcSM5x#Ze0&ukVKM>;oKUV9{2VCEzrLKrv)YLM@fE%D z5ZEeknA|(MX`mnt-a2~e&OWJMdJ)*W^{scsko&w0o+t3fr)Pe<<1TQ<2;|7Yd{6S^ zV@#Ie`;&KN`C;>Zad&@FXI4BO{x?$dw-W2IpJ!o~loUg~5~%+|`~Gb$xcdD3e3s<> zh+l;1&`=f3tErznLeSX0?bi^0UF)w~|G3(5j!Qw(J_|^~^!7k3wY-Tm2KDJgW@ctD zzxj@Tw*(`dJR&1?Bo6}J@2#90^r0(U&t!^@daggrjm_Rn$UZ|>7dm0}J)S4C!fnUg zFAYcfo-)d-5fv5vbiX@hL)anl>hu2|_aBvF15#3OmWPa7pPY1#RuAqvJ^JCyPuz78 zzyw00W(bYHy(>8Ki-XrYe7F#UI>1gbcH=>Vn~DAwivPa!2Q~iw*PdMmq+!{)v4m3! zUUS2nKZ-1Ok<+`=Rq@}xeH-5R@sAF14?FIacFQvs7SHPEP_Gs;6F9aS$U`EtsidU! zM^llTYVV(a@oxPS{LszPfCc;Z_wP?N2Y$Vw$p0rBFz zXHDG7ous)|Go&rv)!<~*?(V?}$FpZwwKwLU3CzsOdX960|LiOqVcp35 zU86drb^xH*!orIjozN};DZQ7Q?K@I`@$a8`#Kp68+bH@#Zf;D=*S((l`i}1AQGj%P z*+cby_)8i)3`9Oq)Y#DK0yETbioDr5b#<%k5$|1@M)@e1HqNA9k(qc!#Z<$Je$%jO&q`SUx@ZXpBT zjd-+|TzenNp@H}dF^%#MefV+h+(%EFl&z0KlKuy30=a?U_l)4=%^TzQ%O2$Vg5}&4 z{@J7>Yq%i*Jy#->=|lCl9E$j#DRI3+L*?*nkqpCTCdk}a>U$=put@fQItE|^clXva zD()8l)9!v58RY5*sQw0sKEL=MuHvsW|7Y*!QOCVkw(9&n&N|QjBSJ{#ncPdZjMh&YWZF5dA0HGMu^qSa^n7b$ z_g>QtVR3x}7dOu)Bte~f zUr6!n9S+*SBsd%rm>;r&r>Q=XI$Y>_^{U3*c+MaE*C;O~kUNZ%HqghFhs^moTjnpC z47thB(IZRg&G&y&jq`Dlr-d=^P|a<$tc9u*VCegEv31-jhBHqjf-Uz}wHj{*Gb}Ji zmGd&(n2$~IJF5dhK3Ojuu|>AQ*>y?|vMR`6Et->d-+J+)Ae0R)oH8k6HJZl9GDl z-X5KU*bpi?tB}1;A3q&}Ky8{Dvkc58CMGUfHWVx|m*=4KU*FuZ z&tr!?@?G;EBz6}EQkjvTQQcWD9odk$QxtDjmP3bbhNmPCaYD7KW#gvPoal@;6nT6n zxyT%YLLnYqF-$cxNQamSDn&opLYkiT3keV3pAe-IV5x@UyU@uxBI?pT(vt4@np)2- z6th67MS0=DkScS+{uJ zTqeYcc3B<_tQDjee(jP-5FUn1Z{A1LSCYXU8tqpW_d35LS0&)GWv?xSR^kP1 zC5Pi=f(1@V!rNvTa)LA~_NXZ)Na^q%F0}fx7=l;IT~GCb?*OCKB}VdzerR>L-3G{J zIQGYLJqlcWz9NUj5`TOWi=+2PWa8(ofzU(wHAO}UgC+4fZ86;0Z#VXgi`g@!on zY$4aoiYhF1po=6lv z>t>hUgc(M!`a}apW+_HX+U|I_Zvp-Cm&tjd?+4czlc75Y?Cef;2g%#NMczx(BW=*@$BX3bnKwEC`p0^kBNzqZjf?fXZO%dn5}uN5xsXI zfjG)3HeCL!CX+DWTdBXRt1QNhY`_eCz@qqe;an{yH6*FwL5;Uv8>rs+?Dm(>slY*o zoH(5^F>cqkQ~1KYbX^}IhkG8bv4dS>PHs-Ntc3ZG0S`1q>CU0-!kt-A1EJ1%X2qlM zg)i4s#`U@n+Y*2^2d&$kKnt85_ZU@5w;*Dnu=J&R`>mg8v>HS2@u|s1)7izLuY_O& zYCV z_!yCy+E>&11Kt+rj;KOR<7lT>j~__n$gIN!Ps);uwqUGxF%uj3^an2Fl_(r<|86)i zc&lNORlZfHVt2p;7&=N`rscBW!Kx!z-BO#0>8Q%+L}1yj@n^^C=N+}evQdkbz9E#| zB#D0bNDGn5sd>JPplz9-0=_O=UE?Vig91N*jAz?ZrzIeb4I$bg5C64pu=r zmk6}gdhF}fDLgtPkcfT2*OGoHw<^Sm-I(ZWx!5>T^u7t}6RrCEqe^@Hyx5&+SB9S6 z0y~i-wt2X7+pC?G<{}^Im8sgg!|QIz2b;aogLa5vrRB` zC^Q5s+gfwDe`Lfp1P*6Kb=Ocsst-kVCEFY1swS~@Frs!6)M&N5h^ompShk;gcW7$J zZ^TGfwW17s#;LY-*_QbsH+LRQw&egZeYF)KJ{RG<=+Z?q>ydk%>y;N3P0VAHDwfAB z$D7=eq{7R#^*5HPo6SXX-)%O_%42pS>uLk8qIg>-WgK{}hVYe_uk2yOsSWbxTx@B2 zr# zonS9>B&u^loI3n=FT*f4JfUKG-`RFm$WSw|*UlA?jF^X1nzfWZ1BG3~Rk^3P!5guU z-RC9fh)Ie?6on+dvl6ENu_3x|oNC3~oivw&%D>8#h=;r*P#Lm=ZiWRTl9YM;x21kbm>BMFYTM&ZF|ll zxWTQ;+!#eKZWJo~M2g17H7Jg=YN)38> zIvXBhDY%#6BaIU4}i+7rAAJ+iyEp z`XHK1x$i>NaC~~{6>G|=6w7hfzE?}WNQrx@*wkZR=*y2AiVUhkXG5<@2}$MbhE6^* zkw(!jM(rnwr?qFG<)fJfY__{rbOPd z$uUAxvX$g)X;l>sQYS4-X!_OU z)p@}TxKTn~5?e88?DKwAyA3PL*uMS2Q!9j;mTt&U^r5qN7ACPo>Op~U&#C89dBoK( zagAw)&?Ar{8T#k&fGkSqkkj@c+VXUAoh_3z7qQiK+_o`l=-L8l@-p!#;7|2 zm+$AG-AG4lvc{tqv*~lt)1L&f?rusnCQtyQZ%15!(!LXLt$Z3VF4RW z1O3bCK0Jw&nxeIPwkoCL5^r6fJnJTT z@k#IjD$s1bH7FhNMn~x=?r{h30kk%!s>Z31@6#)z=mmp?;n9`l(31fVutc>%DI#OJ z~3ErV3ZTm6Jn9J#(RZY$p8s@r>V@^=T@ zZmn3yO{=BroUt?R;XmKYFMgcwz>Ir6-?-myfqT`2A&2poHuzA!K+9SGE9D4jl*e3? zOgIdC_--EGrp~6q(y-gGY@+8BBK9|EC1uLh$!&N^GbV0q$BD9B{h-RV(;{<{L*$U? zVvTnU?_57y3t{_IMzPACMaD+Q}PUKZ9pL=4({-ooWK+6pOEJ#o5M8;?c zqU_?)= z<=w)i4Em!O^g}8vzCE7Q+OwW>w(=Q4g^1ObYS#@22)Ls{ zaY}2+ZujG4-ra&eHWM#tS(k*2Ep^d-GG@035@$#D!z9Ntcf$Y8Vm5H=(?dJ`e*OVjrv}vi>*Rsdm)Sp z;!QC#yvx{G?1PA~hcQU`+{a#L+Xd)({jBf<41yh~{??<3 zE8o)(<6!Ds-1sdE7Q`2R>E|$z*p}&&-hr;JiotlrM7wt`8e!rYE&~Bq3>Gzn)FZbd zzm+UrjcgGx^p9j0vQcV@*&ob75&Yn;1V+YDGIP6FD{HQ6$T=Krfq4D7`wyR509d^3*9Prgh4N*>@ zBII+yyXu&d)u4NF4JJFu7uJ<8)wA{v-in!=ObJ3aa@FcA*kLtiT$dC#p7SEsuqv{` zVQgojLD<;Br&jFry!w))p4au@G;B6)+##<9ODJVc1^Z9AK|_>iYD-cHi8gK_3Db51 z6Z35JL@rj66xwq+hfzOYdh_cuEAh9vE3VI{5n8P?8T-^4=!~f$7ZUpbO9EdMmDf2z z5#wkD4a$N-WFN&?JzLWxWqQ_C=&K@njJsidaj~#dedE`s>bADGeb5tUlML%5cdB%Y z&KuY!SF~U&@%WyaZ8xVQ*Zryt>%-ZNN`{8`N?G@COwGK$0MjW(YI1QZm_{SEYt22k zI2$_E90i9rhv|go`3*krZh_u_=F#j#49W27$u?@=yLs5ikqLkM~akN~- zmZyTjUGipoA?W)I$Vy7*y=2P~Ic?j`uP+)V;ihM1Dh-ZK1&H|E3$%62soi#RK&#}S zODB_04%OS*wv@_JLjyRLEZK1ns`uca%_Gx18{1ZWVEv<2TkZR5dfM(t=n_fERg09z zZrFN8UtXP8moi5!}JAApBp$7fD8*t2gX z)HDW6wxZr8!lWmet}**aj@FxNtme*CNN)E6&ZBs@s6&rlE1#yf_CR3@oaD~4qddd5 ztIJBF1MTBH!H;5iQlAK4=D8IdKg}2W&Z<(`As5U3M%c$yq<2EH{$3EhQE#aU7e&l~ ze(7pN&*`lb_7nHN#=!unsuVi-^##F@5yu)xbC$pBib`XpS9zV)G|ruSkVuvB=qYFm zPq3>hl2}j1!w{?mHx1%)Laf!7Z=+uhN@Gt59qkF}p%l7phb(>8XN0y?j_oGR$Qy~1 zE_LhShEUik7u-w#9?j0UF@*Rg*G1;2r#|aZczMti#Gwy9kp28iiTfLEL;J3K4P_H< z@So|(3FeW|1R$x-EGJSda!YJpEtD|y2kqC}?zTbOk0f2b-%hi6uqDjky#!Nr_ zN^Ven}>UXwYo1jhf0Efo11Z zWtDmwE=hLd$hamff#T5?J>adtD50gG0_eLLig}KU8H?^495uoa)1_@p!jOi|`8(=y z*vq+Q%tj2OJ7i=jJg9B-ASa5##a+fbyl*XTP|I~y$k1ApS<%2Z*8AI0se=*ro1bPk(h!;#JdH2t0Tox-bJ`*8CKHG{nx+pubT!?(>A>sb6c3xGDYINqIZU9=kQFY;EO zJk%U@;=Jn~flxfoTVC(U_`RA7x^@Z;xo?J|mwJisYiQvFC=SbLqe%KXG9(D0eNZ=+ z-b0JRToOfdedT%WOs3fREQ9u;}`Md^c~fu=Q6`vzvZeVrJ9SRX2K!XW1J)>qMueP3FBhHhh$TL?s=YQ>~P=^j-J zi~wgc!^5Yybrm18ij|Eegu3?YOV=IaggJk@2dTkbB0#s{Yjo}Jzs%8U{s^O0obz2{ zlURlBvB~(Njp-E^7yr2S-@?&sC+3$H| zH@C?T(t_EJV>83Wcfij*&1j1>Wopij_*5N}VsidB*v`xl9yk6~;CPu{X`r2Q^5sSz zzMfq#8yho;j#iv5N_!7d1-rKkJSW6Jwj>Njf3R$}_XXkbic367eJYRHq;Ya@`Sy{4zfG&uIAsGh+Z=qN~ z8KF+4D!3+#(IOmiXm%Rk@a(40NuWGP`lJTtbzIyu_k7>1B2&7J5|gd^WlOja@DB8+ zacP4nhv5d3KiP!;YI|mrc%SSJzG9CE$=;1&Fc@!sqpZ#WrOS!0Umr6UsrK_gfCWic zUS$4W43uEaV-3^$rgfG+d2AkrP?%`A@Xq9r_~|C&U;_%L1)3RcdyHA<=EYHmNpBH12(5POZ>SwbV)jiiWZPBSxrTck_K_hx& z^(O*LnPw-Ow#k`=l231wTmM~Of{IZ$gE)#;ewPJrg<1D?*81*={=zF5*QY3`JUa;Z z@Z^IyqdE5&_JC|PhzD?@7~SMGW?&eke;fB?<) z8X(&ts6mWIX_~vhZAxfDt5z1_$SB&UIqCU({Y8!<>|d%otmW}|xx zO6Y1^dwW2br0)Y3XMxQxJ*mz#!i52!BlYVq%nR`qx|W#l_hqspD7(3>O{Mwh_U+qG zv!J?=?|OEJU{j9}()g#5Aqbk@`pU8zBW88E=2~+N<5J0+O}dZ-3A-}h`&!rg!RSFC z53=${Rw0d57!#%UdRnvn9e^r*IvzR}@q@f)I4;m{BuVIQl2L%IN79uy&F3YO?tSuN z0cL1);~TY0Jolk}uQAW+IRQC-*@BKAJWV?crDmd&(vm5)Jta|k;pNc9vNxYY?Y^4y z%5%4R@lFg8pAF29KHE*Na&O;PBpjkrCT|sX?Zz+Z`9-;34E#GEJto6#@|AQnIBV_4 zHvy9kjegsMpWAGUynC;O-dNQV_W*>!<>Eg5(<2+C8Ce>-?oF9TK6CS~JyKNbFBzLyVm3f1 z`7m9Q9#%RwmC;`*DkM=^CQF-iyPZO<>1Lh~gV>uHq+Nzc<3S9FJT3J7+$NY$%E{<5 zKV`l>zKRDYa{GrTJr;p99;MzISW4T;3W`cUeVcu@dXo*vZBQR=0u0 zwLfx*O)PQ}7_!X4at#zegj@P4IUtH5w=XzU)Djj(0mE`S-BfT{u%a?a;@B0A3Yfp< zGZw*(P`chy9Gg7@Nj+gO+G;!KYtJHpol3 zG?>`S_c5~P8;dEI@_xOE6M^-BBg>{$N2a@qQ{h0J@Jg~ygiF}n$<`33SQ`=rs9^Qp z*)IL4_`2TUMS-B`yq!q&%=4L{#l^)Ym4I(iwhAg0BzEtyuLxC{8tqr~FdEvop4?ef*FlOZB@Dbi9>OJUfC)#wb}U;54g4aUxLkH{rO6@Lwv)-rwu zbUNtXF_)LwLrS=nSs+JObB@jJu2-^kUV?AMTmRO0)%tQ|x~S~LPlO5x8B980T}lS~ zgJ{JM5tChm&E>c{Fq-px=gG9>I}fi&yXWBd%AeVNsPv1J+?hvZ^ubpo#QCX_&V|nm z;-x+)&a|Vc{I&!h-+~G$l|lo-rSK~#IB}ZgR*cDZifIxIw%yx@9DAc0&J+kD7JqQQ z?FC(Tn2%$9mi-PLjd6sw!=d#;2XaMBlVpHT0s0-Wo7To2y@9^7rGx^H0Oi_>c~*8D zi!QxQ(5QJZ{0&=5;+=MLcb5*W1G+67n%u?jy6Mbq3I{^4FB6rAZVZ(H?Ii|Dvyrw2 zxgu9oC>~%`)5t>$xuzH{!6ePVilb(k9bSH>UL(+Yo#H)=wKX4#50;+tLq} zN(A&@%;vjFBoMZJB|+`VMlV%X%Kno%{|^mn@kUA*``c)cfmW71ZgZMkIH=^l_*=iJ%{w#NJbcr@I^RRP;TGjq=2{%oittmxQpJsF3y~4vM;r_GdQq#hG zZ~K5K7w#vDXsf$FS%QnexB3u>q65Zftm~=y{)D3wJAE^sC-Dhkf7q++tJ0sD2hJh7 zc`FyKB#O=SbzEHDK|6KX3lvSqj^|UG3N6-6n8g=fliVtY z=9wrbot6FO%5~8X_yDMQ#As+`B^X)@I>>)0+7O(jBwK{@|ENL71Uv^EhA%ZPPv?5} zeyIy1Sy@>VXp}Vb!-*=JV^fjIie(b9l`I;x-L0R{I71rk{JU7-KZNI($>S5$PUsl8 za9e-0SSUX+uXt1T#!4IxS74Vce@$ZgX9lt~ji1{GnYUCcT7K{ASeN8r^1@;;`agHXj(_Qs{6wm7;8zUK2OT}8jCi8GF*$Wr=`97WB&hrv4uQq(}rti{b8>Cg#shC z`_cSUr)7So4CM(fQVpCH{C;22tSHa$aX#3ATiHsozB~f5vp{S<0c1j_O@J^o=rR!$ zYSF>m`oelMgk2^~XSUnZF5U(lwTU3)HD>N-lZ?usmk<~uep)zUN;(T2!!B!VdV1WM z`hy2BX{$aUUctp3V4LrkrNUmA(@}m*BYrnO14>bWzTpDCr#(S=(ZkoCr<-FGQ^4ae z<}$_@>$PPioRR3U+$X`=U?d3`f8S31zD$zJfayNte+w9AKad05*1V8fv|<8bJogF4 z@%2F@j2i%c&@D-kV34rU6eFIL=9AzdpA31yA0$g2m_Qn5eG`8~HnB!o_hj6?wp<`9 ze+85F0KNuk&#f3Gkx4ROUsH^i2qN1fB>uZT{W0=SEi@ASE*G+zs%t6h2`Uu$$(AzS z6@x1>s*ePNAI_R{#;0E)Rmal~!DE)k$eQd2#+b_uCl##R#(92SVLM^VWTQVOCI_3MgIY;d6OnRC!aP%C$>o`=QsE-5`m_bAIbnI@(X^X0{S| zVRukXHkS==v{#MGRs`jS0rDPJNZuk7j_B7a5vv8gvB8lWo0gn)LKyZi!x9|1R9wa; zU*iIp;GW{^5yU8N-_=1?+IMjz=U{!evJk5Hg&r;rGY}W1ZAoduM5&OuYd|D z1!V$Xak~;3@#BWAF4ec5fgJL%EFj5qD=z$v0Z)_nw@7f(;{QvHfQ9A@MhM96LSF?F zl>JmT4@a2+Jib*w2~}J7;+LEmyHxZX!?n)pAa#2 z(_Vh?-;MI0voNF`w~*0He>D3M z19Df-*4Xj_`I?a!Y)elNxV7(6O;$&LY)aKl%KMy~^tKSR?{OL{nFz8ql>!nw9Zcvh z7Fack5cSzLfV#t$jcpm)Wg0D73$i@jao>o@z_LcVm%3k3o`a554)ZC~JFQoim6qIZ zVBR>!{0#oUsFH_iet=Z}NB^Kgt7D#N$!4h%a^PMd!*h}e=^l>`F_L4 z709wF<%0A`HGOc;yHp$D>)%Y;8MlpXM}l;V8HbYTXp=coVL%g~{PsBV@dL0WF&&VG zI}pMhzahB1!OzyXEt@d{atrCzLqO@1RD?3e#9NDQu9y0F3#8<^TsP7!w^kr;jVL>m z0*2+lDMdUh`_c^i(vlfRo?3&Wx?n^*Hv(XGi5MNI{z`lR`LxX8eIHJ&XxH7942Mce zaI`P%PvU5FsG3iXVT{p8K!CFnJZ@VTthpg|mDFH9SkPFgy&2efR}0>i2;Pfo&OW&b zR2>uU;3&3^SrjkxdG3>n&X=tcKt8joM?`C z1v*hr1IizSs;RNPU{^T&WHRUuC~WHI0<-w^?j*C^j*~6M7C_<7GJz#OXX-XNTmcqF zN#v1(1Dil}J(GD;v}*e^!RZ|D)@z8oT8uho*Q!wUHE`lP&kKy)OREISPo7+33?kKJ z5Uj8tmaWD}Ff2?_RZmcY^w?Ce!L;7i7k>D+R_St>H^7#w=ZU|8TQ1KD9ss;p9x~%= z6gS4CoCH1pYNz~w$|pCKFlCw9Af@96xAlVdE(1$ha`AP7dsEyZ$b75XJfC*wbI=Z> znJ4a7O?QBA)zJZVXIR=L?=*I!kinXZQ~7>)z@ILZg2Bdq3WvuznMo-I`^iesE&yXr zTzz2(OA!I-j|BOU{;%?P)S@e?y6w< zdLEGI3)3V0)OW@pj|So5rt-=~uSyu7=ZEQMNP#4A3*R-1{-RdRXZQQTrxc1vTP}!_ zocr+&Fd@_2$)5*NfE!*eyu}AQj$);ngExJa`M&Pl@2M*~;4-=E9k;fct}QnT({DLD z7=WDcLEe>Xn$hR@fNmoJ-8GOI$n}m4qxBtnNjTtKi;{id!9#IwS6woSb>cW#+^Gp< z`jdQ6_5tYW>ilG{-LW>OYXEG+ZaN66W(!Pk>>Teo!b?=o9Q1i{ETQly_$AwML&6A$ zbV_ctZ0Ux8ldWB17??;j-lT^|KqmEx+1a#tUeNmaIja@WJfd!9p%FK-$%7 zqed<~on<9gD$DW#$*;o-)fmYJ#kg!^%xkpGnIw?TIhofj80|_#TUOrA)&&g9DK?+r0p4>P8uxI&7se>WgK19t8Eh&ckI#|Xe#iq* zm1&Yd{L$cn0Tqy%%JYyHP}5VFJ;ljhqHvItKf}LGmaN@)0Hrt33lgT`QE`&tO$wQa z0N^^mZx}Nbr_OI+I#Gd{W(bP~qkoV?6v!n>U>R?eANLw)oX!1XY?YIQZ#(*72jvP-)N^ zcQU;b5==OxX?tv`1e}pF^2qHt%MWw2Zv`3Ty!1rYCk`+Y1?dVgTgr35C3r4KAn0cu zr^v?YP3cKy=-!S7NpzRO>p=X- zv1AS_CZ9uNDYpfKMK;@-M4zYuiF_I2mxHu;lFR19Kw5*J1xI6yxs26UZA(yq z=XIk)AGBQYC-@-jr*!aDmlM3_$Pss?iXNEoL1+nKVacF`WCJpOmrud$oDFpajV_Ft ziZ@}Va(E`kAKX#qkz%Fl&af^N#T(*nx4>$ezmHjgH4drViow~z=y-XoEV=e3SWm>4 z%I!CwYGgT%x+542`=kj#-@i+74-bz8 z$%NCp4$OA~3qNgE6AhAZ=lP!Q2xg_4N*QB5*13NqDuR3-$W$eP6KO;sWQri&>w$wl zNYYVxa)Fa275)!Pq+$c$6Tz5XJ7q&-O#Ddq+v+PIS1`eEI`a}f zvyy5aJ=y?L6EgmvYpNEEh?CJu6s)!41vzD3-r*;JQX?;bt;q5t>-~loL@KDP+Qam>yaFJj zoxqRWR!q_>BL#B&+5rb}$QRHQ<~21s$#348rFeb{y}i?1h6d&*a})G z{J*rM0a;tpV9`AcVDO8Rz&Ag-cnE1H9j1ry!CDFm{xGDRY2@84n60;p?+Vj_TH^=-zvRe;4+cO95bHMTq$BOvRZe?tMJIv%#kw*t0X)Rh2`FpNAD zp`)2SyBU;r05=!%R7%;bXcyft(t&`C(l#KKKaBrY1(x0!@*nE_@K0kjK1S@k(H> z;qWPkTEJ|F`59;j@G0wmLX#p}gGPnG%paIy(t)$SaWNq;m?fK-cMUhv&VUNs$E5j{ zHAt94wU`^2b-oYjoGIY1%u&L^!_Qd7gpcX7PH9yIMK5H`fx{*k#~Tvs+dwXuuVse= z-LztUe*6Mx4<6`ioD1;;i(3m035h{dm$lH_WGUsq*94nDCk6zb+J%>HSt#dy_o-1$ zo%aLKXTVV!Xmi|Bo=Mv6hbidUN7hJ=N>s1`*;8`8Lj);qJd=51v?(P|qW(B2Il11U z#=G*}Yr(+XpccJ58O1y@I|$BqfVW&6oH0d-zOqaKi}9}>dQNxodc-BO;iWXZj! z!41tv;F$rspEun?#Zx~_>XFjoBAcBV z1POl(@zfK75_QO5Vq5%Pf^_Xh9`-V?(Nr<7_ooU|z=nQ&dcs3;XlQC3Kcp-bD4G5$3*_u)k8o>jH{*kSX|rvJCi}ethtdHK%pRGr2dhpl zHucXuksC*Dd<{Aw)a4d3s1!GmYCZaeBq;+{!>6`<2F7lDzA5EhN_d(w*sSoB$L(ap ziilr+jZ<0g*oC}mG@Z1AQ|1X#RrR5YWJgpu+!j?U^i1}+FQ6LrW!%^!J`4BFDQ z$RF;y3pK{j93bFY{>Hv@%ahQ)dxFcT?E1iKduZTt-Rm7mM&zU;@N6zm3yiM8Ly$p0 zgmQJyd2(akB6w#O#v|w7qL5U;4@(s{9X%h`=L|Y<+b1YXrWWJhf;P)2Ub$G8(>sl# zl|4b`Qb;RqX$wr=Lw!zd;V-ak%u?nas)0^w7Od4F>&n@H6D%GnKEkbJ>FjEd%CG@h znB`NoOu@ zD;~Mn>>nhd5>GpfRW?X-uKmJjB9U6RygV4|;w{GfpyHPMixHf~_sDeax)&OWQHguo zS8r?tY1AcLJv3#pGPM%)k1<n$E^jAfpGVp-c5)1XAQr+_V62Sy-M zWXUz^E&+G6xcx8tXh9!w z1F3@b>I+D4GRej5&RfgVIN(rGhZva$Z3(QnoHwY8@g&J$1(S<4gau`V?q{UMh z#!fE*pMbEqLoX%!Ue@q7PiCZ*gA7Egw-CGlPXW1?LK77O8Q2+(ZAMy~uV#HAJ?u}h z0<9fxTM~pVFjTSom_4_^!dK1Q1q*KGM`dx2aT0mWXt3e8kw>bU(3Q7I^08MzdmDY^ zZbdSmY*n1+aSZJ-1RSa{hT(>8v%r|GaYclKQw+m{fqur7R7T}3j3G-p2&~a1@qHdX zDl1KiY0v`KN z#U`WQSnL65X9bs)s;_RX`|LLfGOOAEL@f*$$;Y@)#nTUy7pn(SoMs)zD(7GR#w202 zb2+haf4XP+7~l%sZ(_RZ%YK7B2n3sRly&s%G2;pjlWB;wk6&HP_Xf+MGe~ixqyu!Z zXXCHSflqaFG{YiflE=}R`bqo9d@|lj5Y_(ywyDe{ z0bYtXxLyWGNKCyzhPucsqocAYwXT+@$pOmyK+0Q`DCYm;?91b!UfcgQXB24}i71U3 zlS;ObqAZhbI#f!FjI|`ygp5;+eNGBlX69sxgp;IBmdG~Q<~f!5MA1s&pk^c~%ZM@7 z->2W}`+UF8>siioF8}osGoR0WU-xyrulM!7uKVf8Y7=~3@49112HRo{1BlRjm}D)Z z^XeDi?u$c40hCB!{M_yq+b}jW4ScBAGO4sDv~T;Vouo*#TU2m7?*Df6uLNx79?wVX zievE<1=05OAT{91eP_mVDGM1-w+c1HM#Q0w&d`;!%CVKEC&>FEmFtDOHNb}VR^hh1 zWwX`+geJonN(L9G&R||JOiLG<{EYs+v#iKg0CYIKB;H2aC*vlzj|{`*tqBdd_zN)E z*w*zz2YdWKc#^+FLJd3Tq~0bc>EFOP%Si4gZUDNAajg1<8fi{iZ8*5Ex@r|7MK3gr zb47U>`*q!F20&LA#oL44@@dkrG4GiaUDtJ0UlO$QK_*OISz`qfP(HmGyllHYk4w|1 z@0Q!jIR79r)CvXK`);NTo+4#(A9*nksKO-+S#7g|T|_yeMP=z~ig5)()VD;k}Ti(li1Q((JJlz-UVD;gT=00?~r%n!qfz zfe)P{!0(n~?qHTIWVPW$e>~9qE6(g6f9JgP4Jk&Fe#oiS?4U#_BE3gqUqs|ByBdr# zYRn!06FssggSCC zTO17i&a-;^>~%8OLpD!=3~w-Dv)_Qu8g}JYVaIQ>|7fOv#e?C|(K_@&S#=9sDKHsE zD~NgJhs%hO1|v|?Ac?0OUQ}`23|fi7O=xcxm84Q>&gMhGKr|4=V`0V~tkf6Ykd;u> zw1Cdp6o+g^m0v%oLV2AqnS_BYLrwfrFvXE2ld#_)xG0)zR#<;Vtw@VBjhjLe)JFaCdL?fAvQ9Su1C;$b8VQfWAYpRin;#7?-)PewKHor z$q?0M+RzE?ASW?>6P@ei@H0^3)WgP%<;qFWcAf^JPR*8oc=f+xO~uj;pDL|e~oU= zl`JF4?vShpStRqJOhWZGMa#N}n_)Z=xrf7}ERiT#;(NVDUbGbeA7EE0wzR zLgu5soklg#W`tsFL+nbryT0EZq(t;NbR2f{Q30`<|hyU>-OnaP*AFS4uW#S7?y`*PZ;ue*|lzBFlmC;IKx}xZdv+QV}MI zcpMx6gLUpD$S*~8odq(I@>Jloi)EY6#;>8w9#IhOjKsRbG9aFX;>q&Y6MpXC<#m@s z6_uMVOj8?WVGwSS5-Qp<`kikWov9@81RjF#4m#D?FE?Qqp|7M0&U+~$H6tN9i`hXJ zp}FnZ4V$%Cf?Qi1x6laTmZgxouWtbcmnib$1o^qivLnZ+wk#Z7d-Y#5$NzOd!5a6@ zEV`sFO#B_n^Xg&Biu?A75 zC{_K1oV8pXQ6rxKzIm9^TMWW&w;Rg)xb7D?JCG%NoFpoj<)+C;!tGqP>;NsV_3+>T z$0Pg+O!=3p@=hKV2X?`$v5Q|}sK&6yi8G#ocogT_H`+Y0!JLGOenj+9l( z`@>uZHrn6f(C%tHgv+4ZWvypMVx>eI)0%qUI8Oo34Q`{((hw~B{_1!C>qGwHKX@dx zLUQKKOM|e^z4<4t23gHiFkw_UQT1#KeIchq+r}1LTFb{2CY+mF7d^eQ5eEJjU^H>k zh#>apW?!%BJ2GD#B0Jhc8ZBH$pf20O1Cora(_2!zqik%>Aidl>XYZ*=B|h z&_s=Il54fh-BUeM9dE4QZnQENvi@cdOOAtGJQs3kr_#*_NeAF=a9rB7aB?r5 z`zS2AN(Jf&gEgO@_RYJVy3x8wZ~2b@V{-nlRP^^#@o#>@E0MmjoNGN9Txe6o*aloX z!my=h`V88paAm!4)xip2O23g~=2t6rRF8AL$evLLes!>w=M%%iifu{TfipCD`=w9x z2dq@gOi!mR+6J`Wb%g@Uq8I!a+1M zUHi?#);ZM!f4v-9>i?UxK~#+qQLo;5Vq!`hXyT!}$Y*2{czkO}&r?0>{{JG{4-I7o zUHX&5`fvV=c|opBUg~REa^ze~{qnu<$AE`0c;jZ3s&Pqmnv9vyMs0bBuG)#9?J>e=mgGFw({g#K-?=65T)%ob$iA$s*a|7L~$Gw#~uT*N>LZN)**iBi<+O5Fwqq?6U;4^wDQ{w~0y+2Xy zh64Lz@m;u)MAJs`sN^jHTzL3? z6NcZr$WBTF8?Cl01p;S5GxI983ix9`-2ju9Zp_tpNfzqiHD%uEG0lCWHB&%09K~~D z%D)$^jx?dtUPQUlPGzv`w=;nEEA(vI9MZt19A}|rvbGzmxUJ{xz{;f-EY(aW?}Qw^ zj0k716mE02HP>rfxz|O`x!dk;_!R0>2$nlv;fdNjBGcMWtDr&UO2Q&wWrTRtFy{uNN7z#zhP;P+vI9+ODYLZLLC2L@$>TTFtGf0nP{7hBXN4Y>eF`>=H~ASVstGNzhF* zWKLi@9dD5`Yzbx!5J9Qw>5g5A%3ax0-Y zH!)V7B}3@*2EIDk(}6%jjLb#U=Dt8Ql}(*T!-kADT71_*W*+bCfbP6YPU^cD*VNY2 zDkINBZ^HZ4Yj7vcsA!i<-kbTP0t6gKuzM{=Y%Y@04p}i_9miXGp zf(-D+-6dPI48uFoewFOK`BmN|=;bm}%y8yy^Q6T6Xz_#65{DC+ryK&lfn!dCN7B}Y zjomHX_ACPY0b($moy`P#b%Oie{8tYH!ER%-^bN7`T~lF|D-i|>F#aVXYZCqimFLAXq1F$rZssF6@Yc;$*Wa_8EW#jetn}R$B+)pTA=;N zOm9S~VSV)|)t$oDw)`;gTMS!!S}zc7{QA@OXH*oeSeTrN|Fg*cuUQq7B!_;0>N{o) zT0JF3g$dQ7gJ8V+upQwc->6uIR5>bfr4wi2OxPwiS8!N8F08*+yI$L2c?Yx-_!dLz zVCBvRpZa=mZ$6^lcK(dKKeVgdin+R%kNROX`<5-DytJ;C<@KJxe2D2Kcl=B63HE(i zu6X~f`P^Ex4ew>isT$}M%VKP5D;2%OxXr*I0~!ob&9dityw6a8>sPeG)HPMUn$cIL z0kul&55{wLKdI@}&rS|3A<`_ztN&_t!<_T#8_eivEzyp`N3p*M&xe@L&P9H?lU^66 z^9xTZ`TCKP<0dVx`_^%I0l!t*v8w+^kTk5qq?_U^x!ze8hW=18<@(|>_Y0Yhm+8jI zUq1vJe@Xt`3rOsp^~f3HlqL2arWG{3^l!KYYd=J9F=9zKZrKyAZc{kGzp@udN4za0 z4_xQFET_+H%zvdxZ|1z@u4Ytj!ow6qXwRIi@UY7_8T#u(3Znc+OJMQz?XSGsrufHv zK}xPzy^R_w!yRP*P696Da6ZP{E$zs_YHt27P#vv|tD-VP;2zaEc~m#XO3yl}aH-@o zoE@#fvKLw7mm+y9!KBngGTHq4UQP&(k#WmmhDijTnsH6GJHC1qG5=)lYHmIF^~2U} z7V$OuRLfggA2VTlM<5eyzXlAv6Vwz9wEo=r!xLx`2U{ffjW-gj%33cp{RQcGHqHp| zg4VBgtU6h{NRlTpX4wfjwh@24HA&>d0tvY%m51J7mf})>yLPFG`&Pea9l#HW;^8)$ z^c`tyH$?gl8YlrbP^NRmE=?QVyldM%8F~ejpq2F%md$8FD}*G0D_??9v@>C z?Rt9dcH#Kn#z*c!$8C&jJ#S)F8riW2s9xsJW@gWcd!MiR*J%IeKXI3~?HjQl3c&9{ z3g=BL*zDD8Jm@YC13Ei$&n>bFQ&`>_+v>N>b*ebYZ@z;lH?NE`{1d5S4_V~YE7Uj3ko=mm>zk2Z@0GKhz!AzXm;`bcR=-g zk7G_k$53P>D}QJ%i18r_wi4*9Qt6PP06Wb_D$Ud)`$lt%Kg$hlhL$-#?8+3@a#nz8 zM4VEw%c?-Xe?8lO{*!yMWwYs%TKQWZA57A3QC#}>1M*j2r)Y746y4u^aE_YHxHIy# zBhuRKaqS@Km_56_| zv0y)3LEgSft?y2x!=1-zF%Q2U-2hy`FD^Zq7F|p1ie~)o1Wb;I>-L*M^QKB^YW%0U z8+_I%ovJ>Tm_LNh=y{w8e3Ri#Y=@>5LX zE4c1UxL_>c!j!kh7t=HPZqte_vo5l`F!Ypi;%o!8m%HFB&?x`Xv(VEq1z+H8fSN25#k=;5LE9n8 ztCUfG_d3Zc0>LbCjq?EoXk_0LE7y<^7;ov|Sk!3FJC z5bl@^{jO2#xj(js15JtC^BeEB<)9XeEK;(r+wKj#&SL>44db10>tyZ%4^}@hONskQz(1Yh}3&C#@^Mn8AUd*A%jBUAEN| z@yF}Hb9~R9`8s?17)BU7{W4ZH@1$i{um9hyU>`DJ#mpQv;bfv$gs8Qvz%u=NYnWS( z@%6OwlXF{@Xobb0bwDE~oIT_j&1pJmnRRPLzwZ{w=PIZUZ+z49cFB_iH<1Bq?wFFW z9iA|EDj@Q{p>NLBZX1A7eJJBO?ii98qCo%VF5KER;|(Q@(A<@!T1h22X!sI^F)9d%VFMo5JHZ!4@ z3CzgIIdaJ{e8J)P8eJ_M?CY^8>$ppEtTW)Vk0!m)-qgb4@s`A;z!D1T(NN@hQb0m8 zkSsxezh>i>+UzoLgx`}hh7)ZxA0!GR=cdq+JS}o-pfA&@w9D*5<|IWj)g378T-3qp zc(oVk7v6GtCwH0`o9YHS5G}Gl&Ibc)?rS{SzKKK8f%6NY7>0A|?Sb|S$k(m{Xit}n zb^qN+;gL3J@Kr2>i-nQXW6B=&rnb%fgZH2*s7x}S?SIzPm5v@%T`tT?pgi=`EaryauYe-NrIDs9p zLa1cYnq@URHT7yM^DAQwnBQ(PL~f{{;SNv z-%rLWOuZxGoleWl%08BHD_(vZ&=caS*6%x=c)NBDx4Ef2FckdPIK(Vc)ugvBU3Xb0 z7{}C-FV_^&ZobwN$*8-4zj{5pqI1OfN$+M~h4MGFE8~A(lE3;vD0$O585CctJ5a&d zum_1)^H=}ye@wY^)kYSJC4Xnk6u$9O7{;boO606Q$!r<0;}?5gll`)ouWON&bUuWzhOOh)h_AqMRqX}%-*GuKc^tx)+{wO{D)xE+3f*fGPWCQE5#^q zZCqJcpL$N>`$z|R^t6Zy%0bhVM+Xa|?WMRBmcU0;RWwlUJfFy8;_!mT7L;kP zS_CHU&+f@7Yd_{jyO}+Mv^9JIW+3-`m|O96<-2CID%*cRX4HMN1&^S#8gB?gy42Zi z7M2-^S0g3Y%$oNCCl`GuBkcBSey;X~MlKwB=+g3>)GIaV+g-Eo0jEIn2BjTu`fcu# zm+VW@&rUu0wWj3jB$xP@bbuODmy62RNBpvRLeSRIt4}#^A3Gi{7mh zczul>SXL3S#?(x&2aD5>d&J<(xYWd#rguYHIq<90I zj&dPXp41=1(cK2VYQk%0Ih6#Kx{zbhTv!ooetmrDJnWE=x3b?`T`egFPw^``ya!SH z%>-7(ycfjGvc&Hf{&FCR&*x`Z;d{YT4Y6Hv2{j|F7dtN?y+37m9V8Vui6UNtM;^Ij zQ8`o#fr4Kkd~qpr6brt}rBXU%jpzus_(c#Z<}I4)uCztHLAo@SIf>o=BZXYM}* zTS#&gZw)g|O7!-L!0WRw!f4m!7lM-mIp#JMA%Y%=3MCU+qQ^#P5wge96U*UOt0u+l z(tIpKf~S@n*!ia}JK7b@gWg<#;m`_SP~-2+qhN@Vs^O1Ii#U!Cz^v*5%zi56NUDv@ zI~MSw6I6Pcd{XC@CVDyKW z!agNoS1jE5W{^KGMLJfaqOTYh-`1^-b|1_G;O^8{ys2h2l_cLTtR$w%&O^mf_NiYm zqF0W19lQBUV8mBS-Q+efCb%anJhgf$qO-SU!#W@sz*Xry4`rcOH>fC>#i=g$uCAF` z1m;eQ$)SvIXev=&zDtv}3r=ZV!xVD_rL9JElmu=&E_!AW00m|4((XSX0!ig!;e*3O zVeRZ{Q&?q**&=h(Ltp56tABcf|5l69$g4o{f@e0yWNdgOxU#*24c5SR%5OZNsXw+= z=^;p@u|=N1_?WPyDq3+uRCy$?@Gdiegi1^nT0!KZfm)y^2R zh6A$bsx1DRS717I*gj_)k@9qOn#P|8k$bZ%*0sU;u1@NMPUZXX^1kDulX^1Tv8GcQ zH!9i+Ye$14fRQg^Rq(Z~x}+rZMuNcE@MbWpql=~LSu}^+6pnr1fjx+yZ1QV|#x0L` zt%JuZ-LuVW@{`rm?mVix8bX4fTNc)KrHNjXYLh8tKo6Y9i?NOG&weq?Kaw^EFM6Cu ziLBAIWXIikk8a8^`YaX!g@`?Y7;ooPUxVIhZvAH9iQ)N4+lm9yZ)sBNLza?;4nMpA zs{j**HJPro_)Zr#zXJ^SjhOqx(4LPMQJDuC^?!y#O>@$7E5s~ORp-{J$)`0cKvO@z z>ACG%x(CXD&c4y&1a@r=gK}OyB&Mrf+=JGueZ9FRKEP=8g_`rYWxen{+wo;|&45~T z46J;9*27bn#BUrZwQfYO9jQwP(&yEyPU_s){i^JZdfVZkF=`u{%t5_TF7s#U1(B4pch7p zf=&Rl_qTV*PY%RA++w3(+12mB19lxv7&1j;#q}X7^vma*XTRv}0iGUIgyHBipo8e3 z*;@7Vg5Z-d8_t&hREtv2r#R{kCXNyJr$*m`m36w(^v@h&tJpC^*P#=PTN8N*UfdHP zOh#v*6Bt&{QhT9!)NO)(#Y`NAcpx@h3G!@6X0sX_hq0!KHJ!PYZ-~s0y*| z+}9Mu#BTX~($amWmlG=w4m~r0xlA-EU(Y^ZS1W5`Q}{Cy0i1~Zy|t)gCks!(JC#>_ z+Anl@H4b$(T%J9at929qonk3Lug6gNeFN~g3}Hh$gRNOEG!8{hL~TPDA=`X_Ew10Y z25fOA4zJK+yHS=yi+_tN)C7C-$$I22Dx0#F?)T!u`}ev!VB?cXts8k)D~+x z2=*ne3ZGPjTjH9TJ3;ecuOUhxUA zAn^dR%uFn~zl~UFoV=p&y4){8r$3Yc&)CGSoIcj8)SZ6&o6*TkF?agrp|f78{FtxV z*e|(LNyxt%GLIIkP)zSxV_RRH&(xu3+krmHa|ok(0zBN`nI6lS8HVPu92o~N*c z`AszF!7W$He|4vls3$=HABtmanTM!G)C&k2g)rTgoR{$@AB2(T3?E`giusD{5 zcGQkFCW8r)Zx|tS^Ka~_>i_TA?kxJnh&Tmp@H}hfX-~{l zXKi{^EzH$~RF|ju5~JiWZ}5b5EGoy;^Qe2YWe=*2+Inr8#sgD%FCBhX;=Wm}*_-VG z21dhsdz==VG(OPP-_AaOrgejQ&>154XiS}-!jv|K+kEv!yjsAngOAY^l@`@5be0qG z_W_4tplyJ@{Q=G&O>T8vQvLdMyp9QO15CsC(^#WvdLAD(Tf%7}KiQjjtFB)V9nsYv z!*gZSyFZiyqbRvdd9I*Ghnz5GnK)9BxV`X}gJBgOUpo{C+W zQwj@*;ifq|&u^_ae3q8#3L|@affeoimA5|#Dw4#XyuQ5^n_XkK9XK}e5}2G%uVO0Z z`nx2=ONkGsKBA-Kb^9!rhCt!0Hswl>TRwgp1v=`vx94^B*6 zT}Ww3ugSti@*8Cr~D{vtE45YI29h> z5^~%cXbHH9_4i6;8EaH5n!k*ElC*}l928BTe+m}64`M3A8@}HVM#lTM(Og?&xu|R$ z>T-h#ǟ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િI>b zIL(nX*w6!9B2ADp2phZXN-UAXV-$wfk<>QM#Bsotr%Fx!sOPxNW{ zk<_A__ z7N-^CgL^9KFZ=^Zzw@T&weTEa0SxPX)Yro6hiqb+(Aqt$9OrJl2EEC$`{5zoy-TmYmrmMT> z!|ECwN$ z3?3qLPjPxQ70Vg)Ng^Y)4^MF5zj%FcEN+VjhZe7}6ED9Nw#;=@@>q+sU*vh!F9*4auDDs(j5+5V-5mec-suDW5$}c_!V_;U1dJ_qcOVpPU8_*8Ll#)Oy#w)} zvcWz-5J>_BmYg!|c65G|IgT4LKAbWBhA>U=UDbYETaE~GZJr`{=6k`03X4-HzCDzW z!Vw;*32!?LJeBlqcfsO(Q-4)0*QDjP@CwEiuVW*I!QHEuz29NWK3`zEwE9_{u%uiM zpZETJiqjkt`uJ7d#0D~GFwPz+j|T#fbSkOG2j@>31XtF$k7t?azt3rg+MRm1XQPrVuO8ojppfh~cvmyEAW>x7KQmW-qP z#}k!E?*6PcF8TFV`}W~dxEzf3-6Er29A)fbY&RO3d!6?N`l@;5t!^r2X=$ancPTKf zltyrck+>+>gNWE1ho`<1=0~qg-GH@^JE61GFp?}6;*t{WkmSmKMVh0XVJdQpLWG5_ zj4Q-|vZrgP7gUvO-wdpDT*qNt2Q1`db92L*LoFJLNLJ&{CJXHf;zxF5R4N^rRCoM*gGr`sMpOG7a~sj@!Nrv0G(ZntY)*5Qo@ zeHg%+ruuhMtVoH?I{w-zdP*+mpyGkfq85Q!dld1o^Rs%~vO7^dX8Q_8$IpXh1!U;9 zG>fa*(}y|}F~PMdh32OS{yzWQ=0v$@(xceZo$C3=DAS;}F=NvN}=Lr;eAmFw2J4!EX~!ucGS84Qi;Dnd{Bs$VZ`t3sCt z&AT)f$Z*ue`6UMCdl`CN!o{0gH&Y%i(Tf&%2hrTB9<HxUqm(Q`(@f%C=BEyP_8+)b zkZ};uGbAjFep1>X$}uXdZrrP^x~r<{!jV#Uk1H_QY1wI!s3pfIC~$G5e@0tCFgJ99#L^BIVo}Kw9@%#6g}}q#=HFk7hFu%!&l)+-d1k3sWy8pm zQi7_=dQmzO)9xgR7q%YJmZ(d7m5G`sJ`pl}7##b&WZ~4AC-9C@?5qj6%CFzVOQnG- z{#gQ?Kis=_aj9$(vX|mMCWll{-iJw~gF(1p5Pn{vJ=$co-2b&he>`yHB0rN?5{@?P zUhNv?1BF>k1V?*0;ijXV#$4%p-y5&K#b2{)tU?l4wdr=#E~;2Vh&$XV1dy0Art#|` ziNAtt_{7eTrT#9c@JN-dT|WJ=RTEQ#?1#qbN9Du(uh*6JPgfbzMp7d#hhEp#eIyRs z{$yA8%IK3Lm|B~CTw1bm<}&Ba-K%P!NNOPNjAWf@fY*4Am0%FG{^t4N)Tx(8`g&?B z2c3)c=b9;@p$``(7J#<4dQ}FXV12sPLbKv<pIj7MhN?oHKTM$%cq(A7^;wdg zq#8Q85_V1o9csNVKNF&?izCu1dB&)XBL1Bzi6`B46995_p-kjgh0gQ(HA#b8l~85g z;5{uXT_;@KFhK)Yl0#XST#3^FX10B!=g#_v{c)jSW=|0wNz{<`edm!aL_eIF(e&mS z?99kAf#Gb}XMu@P-!jjF42d6V5l)K4_;dysvL0DJKuI# z^l3?VPl~9=iZ5f4Dg|a?#W2tel~n)r<6dDJ8U?=)(UluJj{}W#rO<|jg(;KJYs)Wfrcnwc2b_!7xy3!UtX=q6)&qFPIW*5A5_r3 zGnAsFwR!^U6Ok?Gt->o_l>nBhU z=gP^9n=s+sXQIEubNlE0=O)(4P{ludC9jZjtx#?nPS64K9XZy6764Vi{iCh9(OB4SnYQru>@IW!AJ#1ZZ z7K-KZS(+|R*{B7wa_Jqq6Vq-~n$3`&f|DXW+K6EWBG+;1#M%wO z@MuwgF+*FC~$eCTfm^2s1;(Adh^GkXx=Zhgoo1u5 zKyH!kOQ3_6Ri1V9WS-?)m^F`my@*Od9tI*b)je|@EADM_Ov4Nul zoh0fkCWjv~0n8X*!ot~0DYLYt$^7(+QaIl)hqhRF!?ldEllKgXmse@EprcP2Ra2ve zbkA^hW;RzT>g~%qjcZ5sRLCFHNdb?ThNMP-Up~CI6o9$#MX1TAU z27PPGfn;RTWPTX7=fc~2@Rx1=E4E-guupTf!#o=%_r8#^?!ITWx>s47lUj07M(0Tk zX{bQ$oISrlP1CxQUE-9=3#h3rXOfqekb%`hu<=@e{;b z?-R4NKl|r9i0LS`r;QoPjoBS6Z`P%!xh;O)IZ*mzb|iX=WZ_Ore{f+l$U}1e@|N-a z)bmtOQRiYMo|H^(VjBjBC0q<@U%0z0jC>%n7P_M%M~a*Q$NM0gIbb4SHjgA1fF5)b zDGY@fPP?}c?mOoylX|Gj>$`=ua|vmERU`Sb$^8{}9q}a*Mg~d# zKweeM-G0L&C^9c*-(ctv5D>vQIglh<(OpJnqNc4%`+zMEl)EIYwD&@cn~R#Vi)RD2 zuw4c`0&lQJ98YQfgCDn&b#rAVAY@W0loFBE%>OZQ#~FiD4qo-sF=q)-Lp9qXgJ+AA zXT{S$*g>2Bbjo7gM^m0POa9f4T_oF9Px#363boI&#IT*%6)Z|*=H13aaWVObRc+J6 zi`zQeYhfT0hBB|r>>M<+?|{lVM6Y)Uoe(+WJ2TE$GWI2eMH_BHG}k5Ltm!Mo#dosY zN2c)ltTt{)br->lh|bhPsgUO&C@O1dIN5h~?(^B@zOiR&cgKe?tyS4&L%<)-p{T+9 zG`cOj*F_E}OpBuCszKsHq$eU_wta4X#d}=SE!Q}RkWWlbNE$%+WJP5*BkZDqzXZKp z^O}ao#P3QB3G7CDpT@&J%8lPfjxZ0OCpM=qNNg3w{(}3X3=6oT=f~9ZU4QOS0Ns!q zie3%VXJOOnYA~Dhm-4LLBCd&(-EwyC(X&H{5J&ww%xt0JewRzk6ezx8JH0q6`6w-M zIJ>{f8f&Z(A{+5hC%qKnj%t3F2TPn}fFgJ`!!W>3OETrurblArWtiVg$Zxi-5bgFR zYWiDptgJm@|g&(Sarjjxe6n3 z#ITtfm>fy-uA_W~E7pEW8CUPa&ZD{@HrD|ggT8ia>WKFMh@NFYLHTv?@?1R1P`LwL zJR0Bu+tTp_dh#IkR-~QJb{Zrp7R7n&a5*5H-`Q_4e2xl@SzLR0qDfVuRE}N@j_}_r zz-*)2HL_WiTvvfxIOpSc+L2$@rG>9_Vu28XBu#^N{^TS4ar$MOQogT01^yGZ_GhQ*_os;U zcd1CIEl!L7{ZIe&O@#sQGv36G{~_xQSd6P2rL>eeJW5~j2|rG~PbzwSPXCv)R99rl|5g)vLd8!q{)}qB~|p|=YT(~l_8V3XHJ*C4|{K?UeAAz27sTz(tqsbYSVyT*z+&MoS2yNDv#E3(*?UZ zCjPa$`BnkTT83#ED?n=8rqpPg`Q6t&ENUJcqbf7g(2zOv@ZA;Me!Mru{mTIPg4_83 zsJ+LzCtq&RNBIkK>7SJgcp+`vREw><-KBdbdWdH*&>v8jMuEqcfBMhkF^zg zY)e;8p=tZoqvcY!p+u7Ix_#Sy@!AuE%*;yXH|4{l+mu8b0>Qbc)4kaUrULOb)rz#_ z*kuQ#9P@>djcU^To~^}(?-AZJ>%1A;ZIOA(-(%6znO}6>s*k1z8cAX8)}XC-?P?w- zC9@Xaj4K~iRgw^r(X~w)KO=69SWuASimuvLey*5X@vB7rk#C#YHbjM`S>9Q34>y&( zB(?OW-+7$y_J#kwuniS7bP8@-h2e7ASUO_JHe`3b1 zE%sqx5d5URha!O!OswJ zpM$@6c2W`LY^|b#^IW!3n<*~iq}fXq69y6X$W3p|o9vT`p;D*na&A42II?fLqIhqJ z`mELAc?SIhaES(L{uKteCb?IKJc>BrE=>_EquTmHxO`nIS($4-r){^72`MTxDv9fZ z$juAk?+QxZtT|RER?Ti*P^Fa`JN?RGY1Xvo6|+3uGn+j_Kb~;@q1m6{@wTUTgG5Q9 z{#-DXL;tWqd4hSm%NOCuc7lX|?zrb_so5lkr%A9peM!L1j}n-4WF-6v9sS!2eU+|s z%l>%KJ@CQl&FhR;85>s19h0HTj+DJ@%nqwJVR_BXh6CUd(}5-6#?emfzx8mhO2gU( z68%Wlmpf9x?%p!kF4*Q=%=74<+*GS_-y<{v=TY{pV8y30h$6gWX1Fdq8C_AU>*2YV zM+)YECj2t^4Alq1UKSYbioEawh|?J*)Tq3rQ*h=F;4W8_zQ)Y0vg|NS8_)tG@On}A za3*Vzfvp#?9hAPoewAm`N_a-S#`^S}vO+D7- zAr&UL>vH$l$QOG#k0I!5ej~IE_EuSzw35<5bJh&KT-tw%d&Yks*9}HjfqB~DNxI8R z+zh+0eN(2~iGrxHf#$^V$}$dMh;TleBMB zE+uGttA`9`=T;Iof&;;voRePofd@n85NvdQ?b%?5p;mrl72`ZFAZ`++QEVbKA%H|i zek0B;q~zW|;)KyPC*;94r(NkubIcrbBo|JMk}cdV z!Ky)YT$^8{ov!Ac)`eoD+0Ci8eCEx2&fDLF&>rg?&0Ab8_6_cMN}gmjKE9SuH2q0? zX=!$S$_{k~osriIKGLFY%YqO9+HKXg%}X%mJF1n*s7)vk=|X^d_~0J7XOk3;LKm1MnS z^f|eO2f0C+uLG_IO{D@u`_5r7DW6__mnS)Ac_HT@hsl<@(&ybR3!*|ROj($2i-Jf= zj~n%0{YBN1sm`3Gg)fq6z{CemNSV2fyzbGy_X@)!C1_|8%{nmQ<4^Q#3O!>S$vTpLy>?89$R;GQ7(WlFc?#h`Smt?$yS+^>VOdRi2o#+71j zmIv?b8x!^?N8*hxTl=8yF!~Do%=EkO_&=^vo_JieO;b4qe#~+-ei;5s4sW%`EAFwk zAlK~l=f$ntAYiS|BHbEoqez!ImohkdFb`Jh^y&)V-nuK%E~cfnSk(DC%i($UUOrT$ zLM+b%g_uE!7K2}%KIWKUK6iRm3hGmIiF`Az4YjchlL-<`)Jq@7JOnod0$+-okOU%5 zYe2$s-s_bI9e6diJNzVQ`m56qtrt$pv}Z@6PTy~2Koj95o;lEV63cDG$u8~%xPBT} zi>3t%BAGcRjz5Ij=s35$<^=&*?V#bMa(O7DN76s?k@?0PKE(PKI}~)cakzNFEmM2a zI<1QDml{<;W>zP?(5$RTJZb(u$N#EPtc@@k>RDE`;e5u4AEGY2aEamlxVqt|BOd1* z>ia`)kp^yWtUl}m!4)>X%8p1CIf1FJr-R603l3rPuQMr+&fjyYD(8Y{)oW}>R)d)G zC9934&?}`yfH)amOz48Z1_*eQkK}hRQL?|G5G$fjUGcdamUQGgO!murn;Se-;xMS-OHWTZeCO!l(?kk5B@fpWCT);~22liOmMnby7rUuHj@@S1PwFJs71~>nD?&d)qxv0;eU*4&c)tqT=YE ziV$r*m>1Hcr|9VoLtVEv;}Fc$wD;-ZtHDZUcE>+wc44P2) zGKZ;+nJwB2OvF%b@Z}M6FttFaK+tnG2iqM_f~6IEK$E8Rbl>-qADtR)%05ogOP@&4 zW{&Xopj4GX(aTq_E6wVEMsRq2*REQ{O4pTM$8d%^%^+PjOhn<^D||s}%fc9v#f6|* z4$r8yS=4@8t~N((Ha!i%!olT_@5HPsP)G|&`@tBsS2y2do7WG;HoQnnNe@h=c|LGj zm?wv8So(dMHqp(gEbHsLsBTR()-*JHzHii%dfoJmwg$Yw{U6lnz=CJ!E=mgz75XA# zm7M(2Jg%o4^e2|q-&>qfrVSxQRuHY>u`X{rPa)CGRe0tZd7TkxQj5BP!40_F+*{!=w3W z`zZuy+n+$}wH^1SvasvOPSl>K*~$~M`a_%@a*d&`IK^2}?&cd| zuVHl3mWSN0!G|>+Y*)ud_D^}xbE?WhbT%D@?s-XEU zXs}lK=6L?L@+iNm?!0MUNic_6{`fr28?wr4tMGi}-Zy1ykmg^K#(M3z+`3gLECHHN zUfi*sp*@y8YVA6?JKUxsu0b;P!W-E3FU`JIwtIcv7aR`7H>5ipuduPBECpTRembO+ zz8<|Y-_oR=fw*WLHtf7`)nVje7|u}c(ozJSGJk#SX+O!MYW_&xm(g)h14b+a%4e@e!w(@UUFz-CDM5QBt-QDuBX#<59jVgd%+rQ3cqJ z?LG&JNxBHelZSEDVUcNCX(yhqHiqh(h-;mU{U_6g>b6`sgzRh?(x`BpiAglY+k$t` zjZjKUk*_aG#1ar*!BNJ6)+AJ$tNE=m?j496&K;F6fLcjdEcbwo1)eT}tES+M%+;tr zRlV04+M&epE=cvLPJJ+v{cXyFkrh##%B;W#tSQ)Ry-+{$!Yth0j+}XTNZ`U6oZ&lQ zA>pbT?mgcy`Rr*g<5dx#1s(njz6DWgnT%9;UekiEMsI;h-F@Ihd9Bfo?Gs7YOy`R# zuu>m}6L@S}9}6@8+KIlpQ3>eNb#N*Q#OQK>NxCsl0mj;`B zO$*kw6IVZ#7L8+qbNUFuc#zG$@65RsGdX{P8UJFY-$X}4b!(EKsnbS$vO`CUq1>P0 z@I$b}7vKCEVrLN~BD6UFaAJ_h&au1e@aqXUzHgY-JvC_*_Z$(n4Fq!%U@ zyQZHo#ym12cx#30BT5xwqsZ5A>Ctn$xVCbM12SI%fgCa+)OSKXD(=w7ujF~;2kYcJ z+oL+@!?`C^b2MjG(?4*W@L{PjSO-fl>zY!3ZCJtdX4 z7Re-_tH?UfyL4iz8^?w|s2C~Nm(qO`imQQ&EH^AF~3u7n%n zS57R<-+5yC8fE$K|NL*hxq2>E?E>7v=Y6mDKhAlG^1b#%oz`)Uzj@@}s`TGCan%bz z_E;k3j(6Ifd;#Ey;+yBq{;NJwHCbz*xE{s_%tqP__Mud<9`c8b`ka0})=g=o##movEAikaZ0FRhBhump2 zue$51p^}}-vlze&pjb^z3ZQQBy((IY;teQnRO8A7Z5E=#^JJ?^hZnmr(DM`Df^1;>9|yGTj!O^cT)k9Yeu z*2gUQ79rs(@4mDRI?5H9H|ur!J)=9J2AUKAQhov8Wu*=Z;UHO`g=3M@@oR z)5Mj5*mZnvBTVA|M~AwgImJ6b~uU4aZ(Ar~W z?s!7wmeng>!u+3(39g>QX)`%dr;Uefrn#On;a}Kg@<0HgwLio~% z$5>~M*;C!L(NM+#6<4|94l1hMrCr=|OJB5Kc5?I~TZ~!%+nCT;6-sS zJBF=7w0;60&15O$LX2~8#Y^}tD4(VJ?7HRPb$p)!0>=r&cJi`G?vkvqR&RCBw=%`W z7i&Z|1DzCMivo2Be4d+c_n<5KgMD)`wu&C-Pi0iDXgaz!AA$4inos{%M8!FtMcY@W zAMK3P9!Ul31!vU+=+Oef0|tEV5V^9WrjLFfb98HT+!eNokA!fc`Jtou>PlprPZp}} zHR$p;vUk-wR*eMg<|%4w@g!_2$F{IxV0or^Qy2$H(c zY1}THE!3h6`&rTmr*PT$vOLlb)RG__=55!nyAxL#Sgm(~`6W)8m zZUACnK{&zfJ}G6QHCaQu9~yFOg5irofEGMz6`TFDk%exV|C6Q})8FSb1C+H>t-r!( z5xp0?G-9EYs4%nE7JWgKg0h(JMXQN${PlYLiz~^Jjx@x*MN_O%W>FN?#l}#-Jf?WE zIaDuezJp4>toK+;>pSC2+igF#H@;#tS1tK1Dk8U=6aGsfzm4=0l&Kn>Rz3AV1%$O! zWf10l3?J^8*nYNW!TdT{uaz#mT%y*K_RXUuT%ioh>WU(-$50z9`q)#ra%PZ6W+X!8 zbCevcI_EIxbw^rDY|JNa=I@Vupz~ngCg1XtJpOnmzdK_sH&6xMdN;dAOyxi(jbpmP zgD7Y>jb374X}HJSj%3Ww=02R{bNP7kbI)WA7}H-D^D{C?HZ5+cHV-gl$0Xf?rJV~H zinJ!dD~gc@3Z^&G%1;*5QsCU-L7GK#=915qCk9jz6im)ie=~dw@=$t<=?E%vEoJmv zd7&vsf9^wo;&LQNe%I$(UgpT-Uiw-}t~;QZt0`N3xOuWE?Q3X#zM-hSLNw&+eM-tO z9P%m>(E^Mzd$UC*%{>_1B3Nx#8tzD@`Kkby>zDKP1pn)BD-KlL`Wxl@nR8Ap@0V6&zL+sH!+M zFRsKFKPGm2lWILs{&TrfcZzuV?(DrJf4;2{oK>)_oteNo+W~7{WZb+@EI)!XO~xc3 zD<}$A6H{VbOsCNeyD}y6pdVm5YS z{;g3^90nu1(-~3XuV_H4)4RfT-|uw_`;@oMp~<_wFRF;iMk+QfB~xS%(eKuA-RtsC zsD_?&+%uq)X2@UHq#v$TYSc+_JnIREl|;7{t_&WS$Afzx;;*0JSZ!aQ-ZjnJ<@02CfC@`Uh>{a zZyd;{-zk^-`;LD>E3|NzDCW1S=%aw5xL%rm%M)sz>5&5_zC)}q`UuKqjlAEGs?3WV z9TejTlSvGgwa-APChdZH^Fs7ME^Lu&V18?uZ!+Uq-5l!3ov(t>4ohk><=)nW%9rBg zhZ@!@(X`Za@174cdR>V#QZW;zk0*Z*l9FF&kNFNm40{Z8Oe^BiWQNO_mt9(!THjfp zDPIb}tJE`lm8=RLOn?Zk53;gOOptwHE7D7p#^HUj4-^(UKat}f0|*Q9+65+P#QlP| zU*yHRw+U`be5Qr1uXF*H&#IAy1t8^B<#fYY3PG+vi6PE0OsiTIIsQSG63Sz`yAZ9}TVq%AvQXn}AIxrJP)Gv_SNB8iUP zU63>EPl;NNwseqZ1DxhSj=$w;zpXoln&WuiFiqO?%Cp6oyD~d;*e6w(sgGSvGDf4+ z0i`OV`@$2X3eY6iR-?U;{-aZ*{o=caKU_T&Ym=U0Gh8woPsq`(^bF(~_7pADcR|wv zZB>wn4<1m_0j&Y@dIXkx-`4@X)63KG_%#R3uBa><%r4fL-Px<0RZvL9;9~or)Gpb` zaR_|2Z2rM;_O~@#ki3VY>TNyT;!1(6AE3}(tE4u&BuYgr5H?=+^wvgLshb|F-d1kW zgsgnBdBdeLW+0~+Uw^f_>F5&235<7Zb- z;&CNCNqyxpksDv)YP2Qg`E`AW8|Xala=q^Qk&A4jOdLECzH?4)5a}3x+6ATO#z9Bk z9y4M_2KZ#f(5LAygjQ_7Rr8r`3-|xV{QeQaS)Ge@+Gv=Re`5%GrtPr3*DUc6YJcIFe-q{ZDK3=f zFLL`zFF+H+o5f`Ny}eAaUa9QY;*s($h$er@oPfd!5@4!d%Zdduc~$qxNiwRA*6$6M zMhTV8vQGfBPi@;$ARXwL=eNY@regjHMi^@K@GIeu1X zG~;!4k4mOw$Ru2_T3E!k;`^Y3WWLrHa;2o(?1YY`^K&73w%k{eh0D^=>X_95&>rTy z4-Np~vEpOs?q99OUpuXKD$1WmyFe~Q*iC#Dn7x*3l$Y`DC{ZXf^zcvnZc<(VZcXt%^YbMW0=B&=7K+SERbYzKYSTlnBfaX(v%12G%9 zQTs|Dd~0b`!R)KMR3QG3j`e`cObk6IZjIv}o(5q#R_Jf*82|F{2RC$hJk+t)J@pGDxj& z*1b!HmVbJVb_r28J>`L}@G%#YO)u)FhF%-_$}p;~kRGN76iEl0?cfrk4Sll2t@VCW z!Twkar^dm*fJ1*pL(Yw|EymsP2;1yGGHq8z)LfAt*Lbe9L(@J(bnB@F*+MQpTQH5& zFij0{;g}1V+WtjOab&FOYPsR{E}bxq-PW7-7pwt89v=f~C zAH+K906VGytu(tWe{1NcSmefj!`tHwD+_^cEmv^X_92?;E=_}Yt?s}lPWntL)bXfD zJ??`7VQsXomn>^J{bM{a03Qi@@X)OtEOB#dthbUVvVzOGtA62WMzX83 z?-4zBwGAhd9KqG?P=l9K_gyF{IZ|UowV|Z!j0>{d_#BTRo|F_#(OK%wdjxw~Fkj|d z5Blj?GjGQ@A)}vaYCh^7;+N6ozzAx2Bt7{faor+nCOwTERX${G6=a_IvJX48q+TyJ zb}{@w399U_I_9Eu(efv5bd5#~wM=f6Pe6-XhRO7gJvc(_4`b6Sl5bQ>JNsRa#NoAa z95ijQ-wDkRV_}b9u7||4(2+O0j~f1j)NEgAJC`>&oRVCHX8?-#uW$NKLSUs6o1?oM zA8W7lM8_as+^Qiz+0&T9n!WE4Up%5R?Y%k1BStW3)M^$MEzr3h;tk!UhLKH74VhMO zFno=+E{8=5dLxO@F9p>iy~~Srswb1;BtTj-NS`aJK4vm*4Zj3{5Nzea5S?W6@N#gW z2o>ZpD|U_&#OsFmpCXu5Ms`7l&tEjcJV1SR$S0B-n)IQ>b1(+fWMA} zV8$EdXGN&&sKjG?Xm%?yXDIG9+ve{O4x!R5yW?Fa3+%~1lUkbkGHaegpE)4y!q0el z=uX<>RO|r*0Ke!`I`JyCEyA0<)M7V>2$EMFn?339dH?v`vurC-m^3u5Sm#P1egK!L zdg<{-!uSiw&?$rOEG~RJXRgr>=yHJm@KjEAL_sY{3Z(0*xwbdf@^gsFGg~CoEEAV_ zt+_IUvJ+p0Ciw^m^*%Z3I<63Fs08**>&3z(NTo*)m$yU z#`j!RGX6!z5`r{b-g|bze%Ohh_d+V4+;W35Hp06aAX%QkJALEmC9lNy`j>dc$&-cDezL>4cTd7>5N@q;Q(frphm9Q{L#`_11pqx@ zG{R9UQ!rXf6d-G#oi}{MyxD?|G^pnAg3iEZlRbl~t)V6(wJ5(pegyPjel3=0`E)Xb zf335I)O@ne*i%?b~&O&@XA*Q+Nwx>Xp4^7fI>940%n!8{=9`YFpDFUKV^w#<%YDirw z!}#yy?RPx$sFGpQ<~I1=?Zf);jQW(i#932)ua2^Cl7l)@=X%hLkHMn8LqR{_%yMkU zyD@ZOp#@B$5M@hc3*tqqOw&!=jJhwdz1;5WZY|5XQdt-uJxFX>>Tj#qE`&7?kJa{# zKg9RF+*+v*-&Y_FAlB6W=DiX0ra-`UlGGl~abY9vL0Y27O$or5Y!T&!OL4Sj zvC1=v5+_wPrPs_SlD9sF;%&W^A>`m$H80hDB>lpC`ip!i&}CqLa(+7Uj{&Lw6&S9e zR{pX3Qg7C0+&z5U1K~&Zyw|=?j&55wYNx#?*+9{E=?Cht6<&=I5J*@dc<-wyG-j1ld+yCdD)_cs>!bv`|Y{zGaD%5})pXXO+u<)0eZ# zt2_WzzapxxWm##4=?STK`a{chP;U7u1}9XnQeiyVrnN4 zgGnt6H^XH*0a0GVy?8WifZ@uJx+@*avk6l#n>3I}^OJ9gr%|ny5Va4KWS^|@g`Ge2 z7-`omkC;@ORo9<;YJTe(zr1&v5>b-R^yZvW4JA2726sqMt0Y2_bvq7QARMnx&hO!v zRvz*2A)kVwvT|+8tZ!ZMdCo$&Ro?6K(L=V%qS1`Xjw5;W`|zEm*z(QcN#DURxRt?T zMNUI8^u8B6KlD$Q=08O$c^wtCvY_x5sa-`lABrK5-id!~nq?dgZa;~)==6F9S4k?E z=<4w3J%2Gkv9|NhWSn&fVH{9X6J+vew?bz9H zyA%FlxN`fjp|OnkJMf{$BN^S#Kw;-)9qo+fU2&QP79>w?2b4cfSIrl#`jf55&n+iS zyVnWQb-?7yU>X{wNxD3gndq4fZoaYwk#nKNluwYJUA>}i5@YugzOy4Lix*K1AHx?4 zS2=qH32qcSA0ezeff#4X{@TL^UM+vrSxU@;vhxnHGtbeF#PC8Gm<$ckz7cVR`cN;j ztuIbrjA6vofb{_1A1CAr8H?w|vGFsqG9xTw+Tu~WFei!vorlLsvD9(ERQ z;DRm6n~Q@>y1LiNEVja57L7feC4@qjW{>+HVrk;qNRtIE-4+m$nC}$1=(`YYry5KP z>TnM|VPiwLHDXN+qVuL~Cauo-L0hu9@*_t}5d4$V)?=Cjebhc<81dHmmMiK3sPdQ7 zAptb|0e#>O+w$#2T+QSg$SAX~0cwy{aBP(Nu+)1i#l0nWIELhvtz15b`ET7Pi=z=jnN*>uNXqv%zC1}Q6{@S$y3_nV@}c#L)AGKjYR|B z*=e-BJ5#j&<-S)l^b(pxIM;;HHRdadw6*dr;9!?;&W-`Oeh?>1oUs)80X(2>T|;Bl zR?3yDK<~1ua9SedFFNFBh>dyx{y*OIa%-cT#yLj%Wf5rN!kX7wHI`15|0rylW^alb&+rh_Qki8aO_6)dx|TMnx2rI-7a+YY0r znoYup8wz23+6nRzMFHGGlj|3hyagv@#EW-!b-yoqFHb} zbAab9i%6_tHCMS9_@vSfu!(4!>#!sTI0a@k(i`&XKm^pso&dxWlggn%8REjdPWsfP z4eKN6S#`aNY^ol`Y$75$PW-r7SY~PjYBFvPr8#$EcH!sA1W^OvZp&h<7F>zrS7lb2 z<1smE67_br;W2{vCni>pjt=1=ZQ0nf$^Sr!8I>w=R@!NbWctiAtfJ$z!e(`Tj+J~Y zK71cASooH$5q)@g+4)JHw|1o|BxVx=SLE_~W?s$hV|Gm5&UUpR9_Cu^>f&*n4W3IP z^UG#H>k=kWN$mXrKIUhQ@F+!cBhXiZCRK_`%S~VWr^=yzr%~F9Fh=GnG26(o8j=G^ zexI{K%KC4pWK62+>xRJRcZGiu6#io%f8z7>S%Y+-PWTe{-wrLmRZ3cg#dfP*3&7GT zAI6l^VebS={}me4bNGHH`bd zvYsBY^CVo)_TZGh%8>LzcIMdQ*PNyQ4rE?!SvRC2IgnHWdZWpPD97sB=cl<-z2rF{ z(=Cui-26OxRW7z&|MjP8UmVUEc%AqS#?STMns(g8V9Q0+Wh^N%Nz?-Nuy`mRhKqKDK8JbpeSYTm+NC(t{NLM>v)9$D1(`j5SCa`~ zW>au1Ej@)6xqNw!$oMlIIreLn`e@05vlR`<=@+oPhmwKg#a6oCX1E%tytC|dZ5aT{ zi=xiQvw!@>_ua4dZ@pol2xHE2H^=AI#XrZL4dzM!ts(juc18intUUQUer#o+>OYbg z)jdXYVkE59`Qjg!v8(g6LCAXi=f&BZYzb2c#Uh|{l0Quz;?UQeW;Q#hvdC#j^sFMvUYkUnr`@j9> z4}6fSdd0kjV^yYh`@uWhW-ald_%(prZhwU1~8e zq}%*Pj45q9c+LKUmVTe4_=o?eZRhS?>uO18y*$&g#yfd6Ki+a{Z9e>i#>Z=iNyH~=KZ4uo|x2s7VDZ~vrP*k8+0ms>q< z(nv(c%d7T2d~b{3SJA(5HGcdmZiB>5>D5~2ARu8vIw<+7)$agwvzC80qHJ5^#2t z8#c%@Zj$tSnF}5~bcL^m50?LoFWwPbkD1Dy&p`BhP&Z;#!>tx{o@yKXQzr9wfryo< z)ePjN-~@W+cfRiy1e%ALwFA1|(SID6C=^3SOBN;%KiS**MOLPu?Z}r1pyz>Qh(lAZ z$iC%^D?SWj0rx6~le)q<0wMtI|1bqdI`%$SE)s0TUaChFtw|0d&7*X0i$Wiw&!Hs; z7TXRODkW7y^{nSXtx+_UG>}oI-vX(G9RSi>>SAKB}r|$E>81C2b={vF=rS zoqt!0(i&51Awk7~9)6uZ@pYNy^L>-vn`=IfC8F@dhI79-U5w6FDtJKbMz%Z@OVUo; zOj`d6&@X_#h@p;yT7C4K{ONAYcJr|+3En6nnIBFNm!t-LPpTB=X&gi2x zL&gC=vrRanvO%BxOOx5@>W4r{fX{pnL-n9-tGXTEKpzjzmV03^OhRr$_d2EkV>@?i zIiGmU;rdQWc-babA-bwabFJ;vVVx92xBBBy#a(fKVX-EM7x}73it)_v2Y3&JgMu}o zNOLHCTUPm>O8&L}JoEoZjJ96_k_JU-}L)X3Iqo`kgByaGO_OCLompJ|kPBUX_ zey_maF99`l$ z6>Ky;?lcx{7o;^%B+wtvT7Z{~_fG-63?t57?t0KyISIrIxd;J?Qf8I z71zo}dgSgl_O-Yg53hoj%Q?P%I?domUP#XwKF3l(EeD!eL*?^(=mBJIp<= zv(B9*e|$&F+8fCMf2uFA!dC)4T9_{}h1b@6yRXHEn)}8gGCq-EunaZE^!-iorLAn(#p@$xL0~TGxyCM%b0^(EppbJp+Oq1*cmM~)KAex8?JVXLDmx)HIyhzld~e%bl-BVnQ$biZzPRQ3A%x7&Z}hw z8FpHCk$1lA3Gt=Zc<5oGJ2ZZl`4`88K|8!cFh%;h#r#}U^{gRRVCj)`fUrt(+%Yt! zfzPn<4PYYpMfSs&r`kMDjhtV)i{uzpoSaTUWGS| zdxmH)TFD#}u&)^Tc{6toZz9hHL#fvE@rU-b=uV(N{0QpEwmTY4RtHI!y&a-qmC1w8 zwp|J=YBu&cl6}_CZoU2e$Wmk{$fP8=y}s~B2_n8cc(1&RA>NB;uUOGDSOv4Myh%^& zTI84>=qlFE5zhYhbW-zPAy*Ju=Qrdp+W{f6i{*N=EW^NRIqV=&C%w$9D&G zCQJK*_sJKWZKRX4k%_cU`uL!QG)&618!3>Q81fTG!lkt`EMg;$Uo#e)#%)Cx1n!^?F8Q zO_j8>DPRxVWu2(v>H)Jmce@3i11v(u8CIKaYQg2gc*#8&Q+aBdq4^+X*Gm| z?3;294Ve`)m*xsr_Q&d1CKLMt2BofCCpX;6m7V?~PibWk5@>4bQa8hLf%YU9`j@wN z6Q5X*YtCL6_z1VO+7EOr<;{&>PP=0(gEe0S)Jn57cd`KPFR;F+gDvU|#3CS~{K0&P z?buP#vX{@%a1KzN+T_(fvLGS=f~igmo++Hg=|9&h?ddHZUm<)Mnx7{e%|&nxxu57W z>suzQ{dlOU!ODR5kMXEUX!s>PCH>hM9Qj1N_7UyY?*dL6pAekN(vE`^m0|A|DF6hO zcty1D2`pnhW|Hvo?8Q^OVtJ0;Lzoe;(Pm1<_wGIwe5eI=FT>1C5Qo<-a>`;z?3e?m zdY1BgnexyrcG7d7Nka)6$*@2hc$j$`(D81FAXtp#_4j&A)tF$)a;pe}!r52*N8%{W zX^{oRR6{*cWws}OIqy1sAp8^xn6mJOA0Uk`9v6G=%-nSJ+&${YEO9%8Pic%o^@Nlg zwl67+zlHby1M={PQu;O~_G{hUB+KHy2fqNC2YlA?xR=8*-huS>sg~7wX$?8RuBAs7 ztmYkciu#DGMg1_Qr5bCZBVzzj5*OtUOb@kchjnCKkYOX8{M}EdSQ7Ad%;Io75oo3d zi+N0;>pbfcy#Q2*^*E?dfVQ7%9?PgruBNkq>a;A8V_g_!q*Rku5xD~LfD@lQKZH@O&^HYiom{t z&_?)GdJT&)j0}#X776x7vRtcz6Nu%~5tHy}i-mclKWDp!*2Og1%T@56z!tpu4SjY; zVY`6x8BqZR>b^D|y>Ktz%ny3B2R*12GiYv~gc0Rxp1b?WvO1mv^ z`y7(ThQx=pAI+b?!P@RRiY`R{0m%XTgNeYOM+EW*Hc7ADneM!ZD(Ovd;WgCe+sREu=!%p zi%pq2annEs>amIsY|K9GYuvYPXYOtx3LRQK55V=DDuvHbN3swuYI z$E>)i>hqzR-agl<(bq9Gg+k2PaeI5atXEi=+~PHl|a9KsS2zeKN}tuIuo=9pcI<*ZQzp)_6GIFM2^O zU0a!Gc~U&*U;dIQCK5+9G2)}Y zs*T#$Q9eH@$T0oxP^%{d{3{_^)wrlFDAAX`U@CyHYZ=2e|hNDMGkKcw*(X;<$oCn zc-Iq5rvl|PVsysU=+nlYrE{6db|EyBY^n6sDLMYfE{$||4uzt*UEd9t%++N8y$#2_ zLd|(cB8qEl*=+!35x%p{u8HFD{f*l&r2so-a5DUkX-i(JI1OC7I-+TdD!)vc?oAUH z%U1NI_x~SzZy(R}-v5D@qZ^fU=t||TPDx4>C%IRgt2?)myD%J$#0W9WETwdETW&^f zmI}$u+-~kRsuMD-#D=jcw3uz~wz1jv`{-Qfy3RS*>A24Czu)ii?Jtk@**@?0>-~Da z?qAQBl?3i2E5?ne63QDbesIH$ebX(a8+ZG!sy=?v`>nGpWw~>9+PznHa?kcDs@iqE z);)hI|FG#)dmTMVw)bkaWl{-sufdz|i!Dp&pG}Gv`~&l@)}=e|Mm-$WaS|JAHjyFM z*!7Ir{ghJ=27B^=0=DfQBP`z8C}bN{q!P?QvS*QSZx%>ncV2A z1b+!@f%wL>j1(>R>5&?dK<au!ba0X(dw3$1!9;>|J%$P}7V%~gZ z;z_w@6we&fA=9DicVk05%)8({oTOxnC*ecQF(}J2PP5?ze?AQZf(;LWT#3I$yZm$4 z?V4+>c+Nvid38eS15pfzQEYpHgg{rKisOUJ#TQ=MA2CAOIuI%%^TzvDP!+Bko@+Vo zSJ&VFiTBeBhzrc^eTpOZQp&mOlW8{m@ZyiguMOT@vDdX{Ue38v;s0@p&_{owTQr4c zfTqG8TtB`3_`CW#q+zY~5q~f@MzNt^*FU?wf>$ry=1Hulgqse59sJOExMI9={PX>p(qAKDCLMZ=Oxy4foJ*+&FD9nVQ*tOJUkWpo@; zQrv&+lJ9d<^6+}sXl1EkJI`9guy%d}(D#uUp}L3Ycj@%6vG}iWsU+*n=xbq|LGt(K zz{S?Z`(Ic1`KLe4FjTX)I(OMZ`}D^_ZPg2mOncdvBp?vODbdAVZ@5nB_O!wcCg;Du z4ou3)55_XVOnd_v1_06SK9l^!Ur?z#dqfwRZ_UATW?`k~Z67zDy9F!}yIb966eL;H zlZRE_M^=Wxkct)|^qF!9CoE!h`K@?nR0V1#x}JMi_wYu?8v_Q66T7p>xQW#zU+ucu}Ds^Z%<1MrkI4dx#=)>L1{6JS3pB+{A^HC zQ@;?1M1RP8=?X6&&TQY|Z@9xck_Q={(#r_$pJI05sBwp z#A6T2pCzn`RoJ-Suf}GhO~{1@+|?sb|F(?Q#D+?W2nZoPKFIFH37S!}Uh#Jfpt02` zcKAaribVZ@@c1-$}MiR9+RZv;ewf!7UU@TaUjU5vhU=D z-`K8ywvYc12xy)>4G4EZ@k1m2>w4KS?)@& zyW1&-T>Z_~hfl{$68GgA58sW%;20+#dj-(XseyfuU7WI`^z==%m83soBJMry$SEP zbo`ekGa(6bt2lIgb?@(YB%D!{1Qs2Cf%LU8Fke}|JdlHqK4t0f_g)vV6(BO|)j`JU z>g2cYjorNI3uyJt{*r&ANd9kBjV(ShGYLQvptu_uN~@mW@7|dpRZCGpz^ZmTTn~=* zKnOV>nt<{EH@1MsRspUJG65SL^bhR@*4MAh;Cbsa$oJ^Je%l2xlXGhtFyUWyeKZnfx zw6!eof1~@%{*|KiWdN))9sufzIUN8MKpwC3)xQGxTO|f4a!63C#^@%CoULSo<_)5z zVXxcAwFX!E(!ZT8OvAZO5Z@RU0ZB@G2A|&kYo5}o*R(MCIMWEJP4rWU*7SaklH6D( zcZL3jqZhHj%P8IfjrnQ319gVg4;ukJ+P(_ehi|p^10kkq9x#n9{^7-U-e4C|2#=Ny z=dng=tWLAsjnr(}TXM#;Z~*J1g>Uhf4M}!z4e$?%z*~C#f^Fcxu1NMgxdKrd0$}tv zPenQ$@AAFB3AQLI{>Yb)c$jVr`F{Ti`GZV z3bHn-voAeREio_cgx=~TV}BLBH7 zFIfO3{@$%E-ggaxGFPujN?w;r5j_of8N0NBS6Vv^K&19wlWQ|sc;E?USEa;s_g_}= zHvK`tsoOA?6?Ja(N(Q)puCx#CKmgVG&pglf9XoKXf8CtY37tu`>BdgzxOtP3e@gyI?w?I;ym8|z6+g&U4_#mfV#zE{b--B}1;$>&iLA9N|nP|3uY2TCS zlywzD#}~)$yRKl9#JX?VvM!Y&)+}j}d#WXMS8ZdogUIzVQnVVVN9_A=BX*j_eEe`l zIakcqjL&dMr3{YD$q3C0NXz>W!W6MOtY7rbbZxWjOUgupeolf% z`dLndXcAm_$m15{p?>n3*s&c4PYpyTPmi4eQF;xEVz8(|ocO>`2nEL;M9%mbi_pcG z7)vUpv8~U171=Yt?d;UzySbl#4AR+aI^U&J*gsFFnsUkO=48YGjJ&qojIDEnNt*#c ze9}M8KKeX?^uS+>h%q{*dL>=Os?UNIwBw6uPPCPvNKP0L$s^*}7T za%*%c=%G4IdP*155EDS9C^j|zszZJ!+y5iZJYytaoA&}|H}>)~o7RHxYQo+}jGB&{ z&hhw{fk|q`hpz!mm78@c(F)%`3_%#W|8w7$!*P(Dd(z~cYby*8 z>I@g`OHgl5_lEJ3n{}};hsmHwO<_+s!@YBS=`HU?qt*n!1CJq=M$i}C-EWmp%x<*y z%Q{aqjpSZVuA(g|UO|FUgS+UB2=xMpe;U(!fqJ<)c@;A(c5K^#>qh-pvhG6N=EvaJ zPT3*LEYE)1pb?tEb-g~Hww!R;<}OrdKEbZXJb$dJc>NSoR|Ihf6=E##jbd2&?haHY3;xEDm>%r&#d*VNjDWhDer5B*K3ReS z+{w6rEn$PEQr|~>-9$xlsCq-%gW=NL zi_>53UBjkYlrWT89J895j~&@$w zgn)d`vv{*Rlc7o%176(%ukQo7O6g+?aJBAaq)9ELPZ%|pbYiMIgWNu4?Qy54y^-!U zv30BBQ4-tAGK&1_q=_WvXXI>MO4T?%BRAIt>KO3W>C@PlY0}hGpoj#U@Xz&)}wC2oe zrt#%xG^Tz4I?amhFae;78Od;(GKf>#KTh>jOI-I{idc$PUcJB7S^>XK(F(X*r)@;6xJ>vkuVIk00N)d)$kRUS! zQP~Ks8@b+5ygW=$*a(it8Za)|`n~iB?Yxkgb;r`qM3}|ET`i-5%R(apiSxEC-p0lL z*S3c9SN2nSAXU8e4MJ`_6t@h0lX^-xXnL{j>-YixGWf6kLz27OZ0nVqplnXWl{cn* zUoO$%W+i0XBl!cR6pPU^<}2rpN)rsorpfz5pKfZFizU52G07`gI08mRtsO78#%L7Q zAEGh^+BKV!k1%1?#xc_a&E%*LA3`ks@ntNGR$)H30cUeW!JAS6b2!{M!X&{4m;8t@ z*s?Pl1D8&&n>fCrodzmS3L-&QJ?JemomKg(OafQ{{BUe?u^4N?rLbJiC?iu$Tbiv;M!0+qa2YLU5%-cQGd_l}&wB+JB8Kbz@Cj8 z2I+XiAv8q$b@aU;SV~X0vc7L5Iz9BLk1dJHWq9h zX&C!KcllxKM}rq~)Esy9;GkQ$oc?;;lhC}xky}M^ZVam8d))KHCO9g6w$Ho7{LMtY z9cyPkJz84%7Rm%@Y8c(Qu9NN{)JL`qY1fwVvrR9i2>(sSulzAOu&$!pZ;ce3+8i1B zPH;wSu>EMU39(K~$`U`@rcfh&z2`OL;EiYjmzmMn0aLAbaxixg&M3@#qi6c?8Pa?4 zg4qbofh_m76W0(n*`H<`!WxvCpyRxLsnZSJwsW%#JycVyWT&i}l^cVlt^IU#2mFto z*MC_`q1*HpEjx_k=2AqE89gt|+$DBBoK2YS3U!NmF|-h>5pj$>=nG|1K;FkLsofYR zy@HW_19==7p&z$*E=l1;=hV`?fsU`oGtYPhN~6<+DCbPuLxH84i?>b*9dAcf2yKM2 zQ!n+ekmcGB0BrvJ()AzIES*-lGoIlRHCy(cQIEZ$JF2UCFm>A`U?O$CE#7{zK8!)S zJ!>OH@*$0vVlHQr!d;Hv$Q_Hs-a}%G?+h1bHVwbz^2YORC2C8Iy(k7(+<0Lcqo#c| z-YrhA)lv*n-ExPHwa>og4e+Dugr(Tx%+i#qFI?8XH?`$bWe*%L{P3Oe*GG|qP+6&U)(g0ABlp~=y(ISrR}A1zhVI#Q@znl#CI2# zOQ!l4FE9W*(mxDc5zpKAk_&IxG5zWm=J+jkBa;TGjF*-zU|p^ey0P{^@pbf}*zv4% z+YqJE9?_3T4qT(0*9cMO?{>q|lE3Imf&|moT=2~k!Wp9>djy%FjFL9DqXpdtU~F-%*=#Bc_^ zH>FEt2o6R+d|aEST^uDHc;?IzU~$eGb9o0-s4_=CP1pFfz)-Kf#~`NjWMNFTUrRgx z^A}0~S2w8ACU!i@;?ts0oSSa=;7^j zLzp4M@fA(d;TWNM4`k1iBiMkZJgIOOJ?=KTDg;Bmcym9l@?-VvRvg}+UEnX=mT$fu zECw=EgsCw)6{Za*io*2`4gH}^coR;ylVhL%zQEz-S#vs?Ud?-<>341Fc;-=8cJ$Vf z7UcI$?+C@$qyr^KJpm1{W#hO>9k8vV&PNHl#*)=b0~^Tpve@6TKc+R+!s8=AT5qfq)yOrg2D zAvZ;24oM%IAHK8B!cgjYo!2YL$)RlG`K2lYx!eH8a{`%R9vg4xa~=k?9%WZToAzIJ zGm{5rew58RLN5rQ4^(S0^aBU8+Lrx!+C>Y+^5=&$&b7S@EfHjD6EdmC2TGwxs%l3s z!{0Ff<499m=&~lxLRcsRL0EXe(Db_eu#zXoRd#!*)0#|zsLd`QWq1$n5j?05KrzpZ zKg8q|9&rum6!n6Fas~BHb?YacDDBgSgsnzPh;jfh%y4T?x&~^rI(BBJ253#Ybz1tBrgzV$&q1;i>lO+tO0iUB%Hj7c z1^}m(z3m($bsJdeX&D1@Yc%o*vk!7a!5-AIA{xEVD})(?Jrrg%1u!td-<*i^zLe&W ztaQk*7D1y*?XII^7s`F_lkXVa=|u9Qfd9TTWs@3l@bmjpHKtW$3y)t{3YYpoX6IpO zxT8X6k4~81XT?tgn4~IxQDzWB(ZCmniDHv6cxo`%qhhcCoDp?i3HX(^&`o5|U07cU zNo)H@P#cBalZU|ZQv)QC1HbzGAcPZCmR~@;!=J|+i{8>~9FMsb1{hj@@zTB`Tfb;h z&ws@Fmu?4P1F~bGd1FpX8^mz}*^S-DN;Ra=dA+jn+G&*P;Ma%tc3SmZ@Y{FlRSCCv zd-4F5*GP`kw-LlxzxAC8yC0%%TC7T?fJnyi?cwOoCATo2ZUDIu4_HZ1ugBIBk`)!L zZ=rbiXez`$k|Ly%eP3Y&I4k?GRXq@^b<`Zd11sVrDx+-8m5Ii@;ibefbtA5C@_dvJ z-97BiJ4G_4t}IVcXZzL;|Mtdo&tS6zW?7)r`U-~Orwh~bzQr(>>fNE7$jCCPcLan+ zecjkx97PR2{3#yaCbystXS%0MG7cfmn@sQ;_V>}ahD>={7{7W--%=soASIIc>DcwW zj9K{<_hFCo3Jen!!SQ-ly%NxQ73;VMW$MzIxZD6u>2{_mBc3tc7hr?FuXIg_;qTby zdEYSqqC@kG!5Di+LN#>x=a0W!`3(tY4Dq5Ck$k~njnvdDnX;MnFSo;X8L)9j{Z~b_ z|BnGW@Ss&qyku&Mp7fH8oTXZJxIT9|e&)!Y=w{mcc38{bg6+kq%^Zw#^Epig;jVra z>h-^@o-dp=nl5?%)8bFBKMtuU5uE@0ncwO9FW>stCj+<}+vZqFb$`XW|NZ6Br;>50 zHdEJk|B9dg-;ey+C$S@&Hv-7&&YOR`g1=HszpTpo{K<_=Ppykz{D<_be+lqy{%>o) zr}O{&Qv+fXrUUT9m;M*B|K^#|A0(AEy5ge0EABn|_xN(!Vw8{H-TNgGleoE=JLI2G zoF6sS{1ynJ@9ms-O_lz3lJT#>LJfta!8YfYmR4$thxzTtsPXwc_l zehuX;jWUa3)xKHOL#+@ zB^Hh$Dnb2sLh%ou3{hgnoUJ9AS2DjJYQ?QVE>hoVF9J)!za$z<> zeH`9EG-(hrPxB4Egx!eN7AsoiuTa{DVs-4AV=x9=u7xOLX^iS;Eo_c9Vz=Y zR`~wfki?R8MvG=;Cv@QM{=S?Ub^#K+cDxZ0IvF~m#`yi!_!DW>%9kLk7&(ha;Y#|d zGg&T46jhxAK-674%ZiJGtxb{qt~$UV#|_PDPeKiJDmL3BUPr%rBO}=vhPvY<{T4gH z;0=N{gqS5|WIrRo{PSFfZ0^3YU0Il_WG8?LeGAgkPC`)%qw%n!Z@1JNX|86kez`V!C3x0=jbXp%lmhegC}o6uoj^$?$4t$?>( z>l$-0zS6l?N0leBjiV=bryiKK6>0mU%OHQ{FJo$%dDmdJXQ<0m2$-gB%q9rZyFTe= zf;3-lS(08?Aziod5JRJC?$J z5ijfKdkVyb?^(-;@lR09ja6FxNh(5#%?b0d`kCYN0k#;j&_@N z+DM-W>^KP8_@poGWV->Pf}eDP8Zmr(=zA&?CA5AaX-D>>2k%p;=o2bEKV)rOiitKe zGAC3t!|l5|P8e#$?nXO?xKl9h6&sNbagB1_D)Lx?bFup!EKrDgaw(vH}O3Y9-py?VE> z;t!s5oxNH)|0tKXtM$Uodb_T>OzIhR_xqjy|&su3fENNbSx-^))p=>d3ec}&36e8 zFba{DPs2o44U8Muv6&9 z{3+d`keogm37oUSb()*{P+^f1+h~L#cI#4XXL{igGD)X!>q<-EU)x);OB<(+;)b_| zj{y?2 zeoA5~`Z>F0NfD&`&8%iuQ4H}4#bm+vGDT%ohv-JDj|5C+FLnfCz9kZ_absY!F{wrl z$(P%sxM^pmHp2w_qC08}ut|XLcI>i`)L^`CEWqnt(IZi-ZD%!`Ef7<5(&HFN0M59A zN-g9$&(yJkMo>}k9G%akwS|pIUK zQ9`JbSvCT5ixFNF{8@BU3sYsr5#T=FZLBC=U8R`EGMXIEdWIeR?1arr9Ze7690MEI$f+3( zDx;W2cD&~wM(udjbc3ULM?0Qd@Ik~1KovK}x7AHWoIl7}QEx*Q&kE}-n#_emx1m}; zykCDvF2X%*xXzaZoyZIA-(7?&@YkAP?77ex=s$Uz9X~w8^KCnN5kqdNs@~<@!0N0r zk1fe>e|vl&{}tCjeT-d~F^ggOHQ`Bw*+OC@tKXpo-x);_^9Q=_;#d!2Y-W2R;V%id$W z{})ET2&C5sEYL%{h(p`V4erl)xyUBwRPW!Cee!hBxk~L1c**aINaWJu>C#&}AX(`2 z!M4zs_jZwirgyERa`|*Ol8@HWEbpjrX5>`{OUb@7fYQ|0#GqR>!)kW68(QO3A^r5@ zUK5~gP0;CTII}?^%HwJN!V~v4>OPJjtc=<>_%Lx@QEy5_zlBzxdy7eJ{;W)0zXIFV z7%aARpWrkY@p@qFhxbkeAz=8-B>x;<8W<9}BE+4}?V-)ieUlRn?cRrqpO`;Elb;h7 zKvhr)7e?rFdDor=f!)l}l+`q&$GlJ{D1TMbW0w#zK zG|sFWiJCA_oY&;MzNS&;)@cRrsT<*f2c6rfI$=#rfzKd^%Jp{fJOqMxv`M@RqfK#Y z4Rt>?%TE=G-kIaX10+{Am|k2Ln4+Q})?}%91C5Sf_WWq85_YV|f5`|$pRX$Sm!~kH zw|m>%1g?B~_Nuzp*~XK;cO2sy_O@JlfBH2~<0tgzYhQF3<=FZvRF(=Z_<;Q>Xo7|- zyWjMC2D7@csF}L{lK&I+cCF3(txKLb`FK!q7-&P#KiHsApA3H>dp{C95!F-Yu0?qH zSe+tT6xQ08H-boT5v9g5U) z|EUQK7j&)SNLu6E*}=ZS^*RGp2N%P zQV{vIenD}ScX6DXg?nTVrwQ#J@xC>57gVWBdAEhqdCm5IFdZNB3^qUPzOYj35c=&w z)R9OQ9M#Rc5#63=(ScpSinern9NcxuQD}1Pe@I~6XcetfHVT*?H$|Di zgT1qd!Yf7$EL${Eb8RE2?*(|IrBccl_`YkqCBmLz6Far!yab{}_Fuwuyx4q2x?gX>u0n^uht9BI53(S`}oo#=WP zok(z)uRssNbJ1>wkQ|^Qzm2&rBMN@L!C*UTjPWSgU2MR9r5G9>PV$esPU{n;I9A`5 zf1hIXC{{aIh8R--m$jEyY&PN>$ zF}4Vypu@U`3>*goaZdUe&8G6GDTDHrG*>HY-5tCu`}qWS{xR=KE{MY6(VD5G_l9jI zE6MM_G#EYc5-_Q~ygMx#PqFOODHGox{o73nnLuEoq&=cmP?Q*XK3jcF6PI>p&_CkU5w`!l?C&SBqVu~Zxi!oLqGjGfBjDxVr9wK?tNL-%}rrv(OXS@97i>9YbIP6L0KL8IM&(=z$yhgBy6Dbz0slxV6VNFW@~EOg3aD9pj9@6I|%5 z_MVSohsI3Ta|Ln4ykkeutH#2CLNAMr4TV?CH-=sN@!*wV(uE*3pu9*SC^!CKQJkV& z{T1KToZV$*lo3*t!ukNl5h3K2GNb_xVH29R79*=5`#Ksovq2uANfX0X4F`(T)z^Cy z0mK5_!d&0A3qli1)d^#}{F5+a@HuL;3=Jr2QHO*-u&HXdL`TINUz zF{VErq~jLUnRUEm$p8z)`Gx{|?FH7pLQ5F6x&;C)3y3V|Xb9o~7CkpejnKw(g?1hY zz(kLs*Oi!-}VKz+4z0=sQf#oOGANja8$i^?f~DJ-E_GyuB(NrqnsS zvROM(0=BSQ{6H5M!jFa}p2^?GDq!@z?v$`X}rm$$3sf4A1SDw2pB)phQ zD!aWql|G)?X)df*7*)upcAXWLN*c@k@#8e#tiR zf*J9SglcG;5_#1kgFi$(wthGBbL6MRWyB8h*4}TDR!iXh!7RO2D`5tpu1{V6I!5Fl z-uFd?wt4}1E19v1RaMvTzkKHKp1A1RV(a!*ihce=?=L!0@idUPI?B4VN@4N;ZSAkE zn;XEXQ8({3)w5*$O;Vm5y(_6ak=z{@{X_Apm0Eu|yslHDUK15WW5x9&ujfXhUo$rCQ`T9?93|m-XE5u7!Rbkf^*ey|J@t&S1RqO!rHy#gSnfO z{vJZ+HAUd+wFl=fJor0AxzQQ`Ts_~=L)ZUCf_=p-4&LZy%Kmg~>~k6D@5+chu@CfP zeylnwHy7Iz>+|=HLa`K}X;r?ya8=#&JJES<4?xpzUifGJJ=#=la&t9`0J3NK$zh88 zRdE-8&mOH?*D2GJR4THhBIDma|C{T*2OMT`gk#cQU>N^_+g2_s@XEMU=-tw*t63Aj zzbC~90Xcflw?FIm8(582)3%Q`0Wm@^oxi!clcV+PVscMZ0PJeKAGd0e`R@+$q^BuB z89^{<)8DxHK!7Ff+ihllQ#Y?{pSy2QT(gRA`6`m|50ui|1#nxMe#UyUKRKg6Jo_6- z@PAwT1ONU1`_$_3&PICKFLrMHTb#UBqG@|Xy0Na@oMux0-;+qAl7MuunR&Wf_HVrr zXd(ovgY5q9Xl`rUQT{DC#q_ueL}_5gx5gqE>Ga=$i?!6LqE>On!*<9Maz~3g$k<^FqQ`x8}6I_^==H&$& z@xo)HKx%UXopk))XzqV?VxFO~j2x$eJEh;v^jc`S@4V_094+LKwWe!+%~NO9ob-9z zGY5?L*1`*!K`3+!&;XI3g;*lc8KPeYSzptTz>^gT*}XPj(UsR4S5z=85UO2GN3|?s zTW_aAUzXYZ^0X(AY@EI5gQ`GQ3(;au%MP;&ud;tt#h=-m%03D%X(2bybskPY$8bs$ z?JZO&!*s)G-cYcAJS1f2v!>7fZmZhAi_bctMfHbZACbl?67%=;j z6V(V2Jzj&JessIkX<`7HC7C|2)bVxwG*Afesb-i>B@3tlao^dmLo^EYq5z=xP8NIC zj*ID&s3@b)9{krfM+-z~S*i++aPR<=CYeC|F_ zQ{g@L;n(Udx(=op0D((OIlRszYO?Tkl0u3om{C%kf2fIwI#Dh#0~-!yg^K0u2wOV9 zZ=wv%Ln6E9KN=-2RmHFEHhAjdCSo82rStt1@ds0+`v!#Q1WLGY+hiGO${)JTYzW-H zu$!(?&JizhX_|P>%&a_OiS*IAO~;82YPrNtSEoOAqT-h}EtoxAfg6uDEc1oQ?QClQ zR1?7Bk@>`Q`C3CLO9Q_=p@r;rF>Ya#cO>|$!21g4a?5#euc~^{=7iTN`1zUH^4A~Z z{d|8kPPc(Q`Ko}A zO1-Z1L(g=_%??xiA=z;uPt5hzy6uH<`#5*W%q@QFKCI4APk{}xP?P1-ZxB096W=nG zKaKCGe@CK;nQV6hlOAA@0Ij~3mK?dcdA`RGX^?ddwTrD)70|pdw$otCTt7M{?A`ja zx`CHB|DzVQnecr1Wu9s7gs={Wp-;huAA*`?wJUD5dw-JJC!VpfHcZUj)1RP)*NZ&B z7_I@qIsI?E#>3YyHh>hEVb{upf$d&7t=h3x<_~dW$T}C0&7P%lTBC!manPwzIdpSm zNoMIZKvA;PUJo;P{S)~gM57x_2M%BTlK1#i+tKq#tc|FPn5%-^Ggnu4bztn2)b^FJ z5DAir?U_L1ul+Y2C8d3Nw#>cA1$h6OkP$Ihm!j-?Q-))=;Q>SF6bw}N&>|8PPT+DTkwcC~wZTMc%JJ`;OV)PXE> zthxm7+XaI%aK2N~b|;^ktu*1AAkZNWLOeCyYhw5Z>+QE{Ga1N36*T6!M8gQSclFke zX_)JL=evG9{G0-SY=dYPv?VEwq=rbnQ~ptxCYv8K{N`#Q69GB|FTa;Z6d8@%At|J& zp{u^RJ$l^1ct{dBhm+X7GdtU>g)?&@GcFm}96HWh#&{o)#%T!j#Y~3#<(YEd*2+IV zEGlz-(T^1qRN&0zMGBHh5*fL`RbTMVWjuIfr zXfe%<$zl|%=Rt0Eo7@liV_U{j41;d3iOpE2?aw+u7?_n(;$@;1`^sPQTEdskKylUF zq|MvgvwY62X_!_pox9p>5Du?6bPdRGI>=ne|Eix*iD`Xd*5T{xd#j*d@)9N0|8&-# z5UtM-=O7XKYpDRx6Vyw4K3M6K)u6d#Dj{pgI+>-BYcS_bqltIx4--#!02CZ10o)l%K8ATZ_8TAYU9UTtafDQSXiS zzUYtA9gz(EbUn{^$GEOrZtH9l3h_N5IFcEUsCHhSp+14DM&!%8gr% zsAJ0lMtU%0xdVYnb)mYheJ6$!oUeWRlvQ~^A%_L(xV87i8w z^DNa&yFs!M^`Z0GyEnfjwL2sB&uEEX+shx!TvF9T&fgCqbb_7@06Mg0$Jv>gJSa7C zxdQ{%iCxax$9q#fPR)ix*65?@p&B(PBD}=6$I63IIi<*tVS3BME=Y99^F$GcW5-mM zd!Ee9R#%&vOx2Tyb}0hYxVu~=+M%preVIdAhhc8AQ5K_DH!qJtTdJIH#Cg;B)~$iZ3A%B*yUZ#&@HI!iW78Voq8 z&UCwet!vQf;jUUkWMS8JH-4JuY_%#NI*P`Ptb<+Dj4}qx=iRU8(9YPrBLUG1XU!QX zVlGF1lQ7L!)PEbIAo)r2t>`#VJyOt+a_XyNJ!8kdtvBIS>R6kL)8Z2*4^PSD^dsO^bVsdg*SP z8Qi*xPzs}EApzBB3%==!vnAa&>u);*CU{AisNKymg?VWC3A99W<%LYKkR}4bouS5K zSKCR4oqa-CxbQ;)T~6{VvPghvypF$T)8lGPxPr!YSw7r#hQgSjMRVULgdbq3zj)Cb zPC*xBKc<9CEK=tWF?q>aV?=-E@qCf$b(0ALmC~ki=oGBjiH_k;h+HWA54a>oqu*PbbNMLX7YVQ0D>4 zloS0)5Vd6@f*21BwmcWl?&iW$v%}qC6lh*(636)JGgP)J?0f@P&*mxyh(2KtXO2q=(!wuw2a%f8%5BQ$=K)LH|Be=X(jslDW$L!c+@RBrFukP_ zEF0>3p&~DzGWKrPS8Jd+FWnI_;S0PVaK0d?oan+OjltO(!DoTsCv%}d1zU1f$B zX=9zr71PzM+V{ydflclzI#&p+Mp_{*m%>9VKCwt*08_7nh9iqE2EV0qwQi*oQMba+ zkA2P0X+5{OE9$^_$(+59N&Y1=zO&A2D%|mdJ7=HH7UY_cp$_f=3kpym1-UAe`hLri z$xvg%Iok#}+s3)tJ$%>j`EB2?{TO$PvJK3?FO+&(WcjkBxY06uDMG=UhJ+f|gbq#T z(Q?_jlxC0?UrD4V+wkGrO{FjpGW8+u$5>}=Tj;1njVX3DZ$%Ap6W zUQj(umP^#6go$Mz68yb+qQ>QPj-)_C@Q(o=eYEk3#b+Go{F-Vi^chE8M@8j%Q2bTi zc5y&7>sDks%;V+jQYu|0%mni;5NN%Iw<+EFc+3&nIetc?xOsU_OFZ}8-qGPSS+hXo zw7ARHBoy>%Ohp_am>UhBa(AR3;z;XWf2?IGHOC75tXiLYjcqEtEsjuE%)#&9mPfYp z$p9n6(7h=R1lD7kR7AU0W}&Fj`c0I z;F@KdGgT|2I!}#94NDaU!pZ~-nm}bDz8aK*1`!#M&ssH$BnzV=4T!P64{|TR%H*{n zdAfR*9QJfNy;W#J1dp^hkdf;oW!s)3!3ASrPJbBlDvlY7&P(_64e%!bxXI2z=RfPU zbCMyHN?iU)Sj*r9eKgA02>+zQba@jDE=1e6pBR-gw!Xq~rnW;C{R1K>qP=a-uJO@F z=z*U%s1x|dKXhB>LU?Caqtr_b0CMs$$D8*p z%e{ZX_QhcS`{(c=f|{NpeaQ5~sMWB&uX6BJMg_$tCvx0Ptv=VAi|f-FC}O&Ie`mP; zaoH;nZpOz9=&cwGVT|=`Hd;n;7eU!}+_yx;EHWsMc*m8u&%1j|D`n%mK#HMoS!lXA z|GGttH5Jqo%AufxUibkr*>2EdYfrdwPyQLRL1v^@JCe@jD;d%uVhg26R#IUMe30+F z*vNWsYZ$Dwo1xh=Q9Y|T#VL7#UG@_cWUEr%zC7UVhj?ly+I}6KBztrju=$1|+GzUy zZInDi=nnIVsatYx$>;onI*)N?N$u-GQq)n$!rlxY)+m)){_HA4IMI>^qsgy0Y_8?` z_J{IXFH+|@4|s@}=-HQ>wfdUW&`6jq{A7b^Ivl4xQCC7_8eHnB(79fKWpQ zFz`_L)`q;$6SZ47IHj?-v+a$Dg9n#|Y@l5wHEQjItfJ`CiI$~$H=MR(kUMm#=csC* z8yVq1qHJR~1<_0w-%@rZTcD!$4tEU*QfR`qAEy#~C=~*+sDJRInn_rxKZy~99gUlL z-sSKs7C;_lnrDj`TW0a_q12oeL6+isR@8dN zJM2ecrv?u;?eH9)`i^thv8{LS1W@Hm!}q-M=|E#Mj>5(g3)#Nj_FP#V>0=3!+5G8 z0C(h%E;U#j&V&d&TJi_)lHIkFxkg151)&2?ZSh0Y{szUXLGOi-&lOv@^y%CSf zQEHoXo#FQk7qgA#r{VzP%lBDh1`oN$MeFoy>}U4ajC%+o*w6AGo+!~-HZq}Br?`x83vB-LAcOm=hUjW0*j3ypZRBvAtUB^ zb=Qjf<}J`(B=y1DOD?hxEUr{+?a3fd(F?Y@x%-eAI6xy?cA%xj(zl<-bJc7wY|yY{ zJKr_96MFQVX-cFz8yCLCn@zz?n_w&kbjUUW(781s?;lNK+GlRjVs`!zlNCwuzS1Dt zoB}#`W$BOxPVmDnC{>`En5(i+kpMFkY5;|2u~Lj4W}^m`5^Zv4%^clSyi_i&j~bL( zCRrE?W^C8!x2IPIEA8lkmzV2+DN!|O`G6jgMkFN18-9_&74uZ6%kSGWe8Oq&no?Ol zr-yY@A7;bpl?xIblVqs)bI;@a!V>~VX*+f`Yr)rvpvxb*B)u+G=ZbDD~ zl32InU|Xp?QGBnXuxHeuD*+caj(m*8F4bqy&tg7~+QIt&$l?Ao8Gcwg z*6vP{sEEae)uKYxJ9ETH?^We0p{J^w3l-wCw_kD_uJJK`q(xmQgP3Mnm))nu2UXdt zM@?256O1IJ5aK(1zc2E=T;oeguN5^i-yLEHyzCL(#hW~il!30Y1~ig z?M`^l2j)xRn1BZv4>1DwUO%~IZf%H>zZ>|o+in#yX*igU*&J6F_Dr|g@hB!p^4jT1 zAgT@Dy~=JYFPHvU_4+;gHAt-TP$t?iaVO_}qUQ(+^F+x)Ez;vsDxTfabJ+VoCS(L|kx538QLSMSb-Ai=Z8HK>>X$l77(5cwV1m=wAD z81MG$eMe*hh?ZxyHyOgCj?eg)mp9fKGx0hr z&GA(R;L*PQ6eW7+RjYY=-2C#;q1|0(qh8{z{`eSWf zO?N}>+g{U)zPTi6_DZ?q)3Dhs7*D;U-q?svVZ)`9?L^j;4$Fb`SN-%?DTpPDYTIto zx!@8@PE)UvC~rtT9Awmf5=e*HiC)8Bv<)3Lln!3i#=V@#CiUEDQXyow38FA%S-`b` zg{Y-9^>fj3$42i|rb$+HQiak-WCzV>@lzFXKNUPY9MswXq$}KkjtM18ALVtMgTaE6fdP;=QmmU2ENIeq{Hw3117{k;Mt`I@KdbsaEeW~4DDr&mg zaOZIgX;Gj17{^wh;2=Vt8nsWg*(8g)*P*p=%Ao%Tn_$SKWsxuwB)!Yufhqfn-XsO`k*SMI9tfJud3STZ7`2S{!Q$f6xHFtg%AQ(B64pH`Osw z@78N+{-QL!bW~6p7EV7) zqoTf?^`Qcg7uE}iB>bGGfLzuOcA`n<2I#}VZl{QpO zd$or5F3-UxrTw~`bg?X@I%l*}Sf?sPk29;_5;o^1AVlI#T5@OKf69^llCfiTCtR@P zs6-ID`sK?eWiSao3QA@G6cg$X6w?+{Zfd&DxHFI{vJ(f2tyDwH~6dc#NlmOZ_; z*&w#Q1#D`oaUyGN&l1xhg?Wf@k=vM{)@gdczF%+F|yJe$u7%i1!aRW>< z@WRph(7Yz;V8q!Ce$QHjBS9-(a zXDvw{Al+W7KltmI*XS2 zG@J3@lIQ*^DaGjQUq7B(&}KYLVn1%h_--me+(t?Hw>}nng@X0u`HYqxpNl#%>8u@A zYp|!>plY|jizjtvBbhqdNV&ch_3ndj_+AG|^qzR?cAJbnm8nWqiYQ>tsf{6OQH|=a z+!ddZ?~~Dw+Pd$jeY+mh3@9;HQiPHakj6unnP+KJSQoQG-@TpeynU6uj8VTqV^s+{ z5;Cb#?i{=-YS3A2Eqej?#$^{b-8)CeG9(}xFvKVPSc~`2u4v%!l z-nEZq#vP`GJwi2o8L<4KKmeyzdU>2IDoDH@N)91dG-f=m-PYk21?HOQ(dN22K2WFH zgBXU7=mCVfUf_+lKrA7?RkBc6NDAoVhn~-|W;dB+2pSS50$WRkn&+>Ye5A7Y6WB{- zk(ao3_4|L+l_6X1t~IO373Puyc|Fc{pPZTGl)2~X!WRz~v1ewa~fs-q<6?nToI zV2h6JGLKQ3mmLY!vNxCPg_Phl>+t!FYa(+>F1^d2l3YIwh-?BT4ZeJL&ZPtGI%=?d z4$|mFQ@9IgL7?AzmK8ke?6~H#^U`nf^u;kHs`SBYQAj#>3_2^%Ds+YJkgHMvzm})u zXJ@g4%M78fs%r8s<|i zK&{v@q|jQL&p|c?2A$L&mR3ZJ-BXwOg8d12CGg{BS#0lIdjgl|G6-a_Rc}2Ky^9bT z%E@vl2W4!n-xh8u>2O25+s(jGPmkbW+oXjG1xtMFp<1_=`Wl=h_;%>Xn#(?yEgfdE z+{O)lrt{e(-mK9?!?yNXa@qG?B|?7A4GfEf5U`f#<5G?-QBO!{#mKhe%%f6em#MQE z)=>zNg>K3jiP`SJ!o8REYL=Ty7WYznFxCcTkn3KZCDwisCEDOxGLFXqRLr)+2=+o!8S6M>^nTp^tU+r9t9!1 z4)t&1tPo$PpUn}P0F=<8YmvJ|-`tBh$4DZdN8-)dGz^tQU83idUJuVp)_pdllonv) zRIp8n)g?`B7L2D>pxLt}y)&Ig08ktKxvFERYa zD)tx4Tp{<|aa02+=3(Md?<^Saoj|su-|i7L1f!bxZJ1>$Qa7o|$8kNc{&|XRdbU46 zM0PSnpp1i9tuxR;Kk{??j%d7H$9HlOz*f|Zcs5wboe!D| z885kgN-dQ&GC>kSM7MDl#j9CYW-CHRB7AcWd+L3^aIP_KNop3W%OPy=>vK)R#jr?D zPs?__YCd;aSfVt{XaLNi^F5VRYD4H$bk)PYmP;m*O~ohO(Mcmf{Oj!`w9h@XR{zeH z%9d1pGD3&@FSBpy-_VW7vi4ObrE@#`)WXZH<-rDR#EM%Iz_Er@ZaubCP zMwu1yjh5 z&+@HyaR}2xLHV^US~{C{l|=q9Q60qrtx^1zPi`YH=QW#O=g>4Vmf!wR5w`{PHX;8a zqser8L|2WLO~IwGvK$>`_v6d7-Pdk(F?t^QZt|Ra>k_T<@;B$YCsN(1>LC%-?u|>$ zox%C>18)Nn9%k_Gjw@Hp84`bhge zqOsJq?&IN0&JnJQeR}llxb#B7!n0W+VQJ%v=QT<71bJUe&njS0fU_p` z+Khk9;flV>-WZl)*b-u9Pijm#p5p9;))ld*JE>Xsxt2HA&qo1!8`MHnPE3Mqh9qp-$y6gIspRZ=!euN>NDq;_mF`ZB$s`yAk zh2%gzji8E(I)NML`-CgO+qsKw^1WFBTD5Mm-&Vhn{m4}S>|%<43O~=Rat$y4OuyAn*buNNQL?;lEESQB4Txv8 zE@z-rP57Q6##F;@huKKe`VmD=T>BuiX2=Ru%Xp{>PjE?TxD-Jjf{b4`c-dGfcl=zd z4^T_2Kg{tLx;g9`Ifxq}R{UH)?_bc*JIi$!G&<)Q^(|VI-fkZ;fFr z0pZ?rqW&mDkk%E^D}(79b=8WXRIwhaXxm|7ZZ)Vc`bU)RPOYdV988gS=^cpS zt<0*1WJ@m)`KfFw#LjZGh*D_~+D8!Dpct-?iso}jEelI=hAWSkY5Y|XpYlG7v^ISk z*LB(mlkYeRWS-F}>JfPfs5N-=$^v|wV&yuRN_id4G`r}*d)Etcie|y)^@;PPD@FxS zmSRi&huet+HkI8q*B~D~<_E8wu}(vQk>OLl=O@=9o(kumD<_fa2Ko25H$ICx(B#0j z)9(sJ+&4$7y_^_{hI9R>s*r;eMFO3_U@RTiS=G{vT4E=KITKg|9A)$&QWeX$)Zj}V z!o`h-t4Be>hAWCvJUU~!CfUf)=)q%Xs>RznAa@ZL{^7EZ&{furp&4pwpxm6ptS2U{ zgSJv6b*Wt)*X-AJ@bSpw?fwEO^2h2e9OO^wi=86o@dgTSor=TnF6M)I_X|h1b)^B} zvPBfywRo}ejn^#kHY*8ikcR3}KYzXKSX+H;YxLHl;Q$^@@EebUcbLV@j2_qTgxU}l9 z-%N#ez&1W01T5@~8zPicg-M+!om)NVo8y%s2tJw{D4EvVQ|l|EN#?JIv*)+h)D2c>jTm`wRB_ zPYWH8ygm@|@a<^Y+aK$EY%mpzlDfY-veTaXwQd1Y@k)(0ky1Zht$nz~j;8)%EYZ^o zOlX$w4!zNlVGy#*v^BM;F=t1pox{n;uX95g>&?emE_KA9FxU>}J{l>>v$q+c3KnddG#KK{jZVhs=Z`x*G&vKb z+6`;2iLspCeO!vY>f#m_{K%$@&&{5ehSSO|TE`J)GfVZ7d~p zpW^7+sa%F04emxCVfC83)%g(|M~LUbwIK(%est^%wScRSdCGHl;95M)FDs9pQi2;g zbVZnDT!hE#z+?x{lTdxGMRZ$)sCXY4DC>UQ_wId9%vjcU_1g{sUOXYU&71nn{e&uG z$n~^R;}bQ7Bz)g*ddDP!x~3N&V4H(HZ6?D=%}~SdgPd!7z>l)K1^Wo2&x2K~nivi+ zw<^DrGr%O5_{!**zI+h-PXO;f9r>YLIlzprA9b0v@6F~ z>y1m-vj-c~3Q?=Epe*~KhF%9kL}RxIEtx~m?J zo-qYCJoj~p5|FPul-gu4cyf5?PM@fe>UUEoSBl2qgUt1Kawf_$=7UuXkPqj1rhLKm z-mYyBYZz z)|;y1+m;tM?mjZ6l9biI4_e(;{aWGTmuG?3$pFnxv2E>Tf+E^ty2OWNk-sOyVqFD< z-c2snVnTpXyUAzwpHK!{rPOIC-x&Du8TZj==J`-8*9S;yqQc5Kgx3=I7<69 zU4zhn{)@fp&o=|zKu%AK|HTQH(*$nlROzee{(i`93U9K;>$Xa;bXn`z-MH+HI*=uF zL73a8u~wfYB=aE9mSpMc`$zA=CFcns8me3RVMBq?+C=TH`}&_IEdn~xZ)3r&M5>hB zuWKXzMc}t){)1tG5y?Q!5CGn7GyHz(5X9!oO?1yq*RMKT{7?Hf z;UOq;%x~9Avdyb6uf>{p@NY36!L{&0RKHM-{L@rwi`A3 zTowK-+kf`KK9PDqaK`=G&fhwrxe{n{a21XE^8fwp>30LYgix(+?OZ@+XKn8Tqq~rVDS>JZl?df8Ng(C3nQr{?+KL{wu z3ZL`&M!vXg|3YrkQ{tQXVpIAp{o@tiDqo)8r6d*lezSbZTozf{@LJ&;2~x1p%m{({ zW<3@AEAVJL|MzHrQakp4kM=ha|DUA&jUfM%w7+>uyZ@&i|I-ft|JkO+h7C6U#iT9l z7J%}RzzlwF94un>ov=S~jR9;l2M7HbT>clor49}lA69ah^S_jD)}|HFq~O-D7Irw^ z7;$%P5Y(5;r9zt`mfLEVTYvg;?Dwy4`LJs9Mwu50Ucde6rDG<@(O15Q$)t@rFREIgg9+< zisk7t%ZBdBZml1~8wgf|5YjBC$sNjpVV>f!4n{$r7K*`tay+`NX(c-`%I`aJF+~+x z|K<4Z_jsdwBhfkL!_xkv-vO7WtO!nudn-JdOxHKS0;^b!V|fQLW}goIBKN0f8ryoH z+n<{9I%p5z(#QkjytWRKv$PHtKHXb4dtL|gm7wKC)#kAkla7euKqtK5JroyHNUGTi zjq*+Tp2w!U#?=ZUF35;3I|*Cbf2;&h>9Id<@7VoZbP8395XuF+SM_HE)wvym5$m^Ui2!+QVw>6Ts2WZnwckcocdLB zQTw@&ck9%SlJsN#@=4S-jf#h5;p<6&%igg?731CMi_##;9~D&g7`uV9&NUr_=*$ne zz!9b&$wIp?NtXBIrTI7r92zPSkwBp7QMFYw*F*{yFoRL>Kql7$Lz~fw)Ol$%E|JA6Y}?r3QDNE;3wh z!$b<9xTSJLZf-)!=|j@(nNSG=D@09}b%Ec0u=e3s-qi14K$W7byU2@NmHLB7q}iR$ zyf?XHLjA=7y_c56D)Y^N-mCB;2pjcg<=n`FA*D{`+6OPY&@~n1Bo+vEp zSUJg_Vb%BsFWFEhOmB^sdk>O+asBk&^D;>wxuWiD-eak%c1|hAuvD!lLcO_*gDTB$ zVR+B*=cnEbs59^b;{&>3@s8cP7&W`%;cTpQ`$gnW5|<#e?@)ckFab~X&Ph*~ zpadgtFvYtIy-heDI(>v57M7V$dCxZ0o@Eu*+tQstIt8!ADOSz+m~!e*d4|lC$LAHS z8MLtsTp1~Md6@d#GD<;$;YnvDyzfH6sq<~3G91_9Z3;dK%dSrbemwapgx`B|!ZrCr z+z}Ut(<$;*^b1I!u#C!uw-AHoQUU|n)n*H&Wb6t&^%Vgf8 zG{$`lGzSYV6+M#OC@0OeeOWi_BDpt#mQXT1a_HTEH-QU#1+=0>g0znYUiC6MuCV)B z&>25AWtwS~W@dk;na4qbumq3RE~}*)xg6^h5d4+wTu>~}B(^>VWjj(#;>wXT`*<@q zLr6m$_7KK8WInr~=dRx^DL3)CI0)S!77%mzvG~yoQ)(4CyeBSQOO`X>t1N+y>*fN>s!&>_Z9ZA@}+cA=ni3JyI) z$1AM-P`GqSahESG!sV?rG6ay} zeZe#@$zx^38eLI;I%c2OKl*Vm8lzm7U4u?2Sn+Uim?M00+`WyWmI2+?52~OuEff zh6XEkM_*X_J=d(ft8VITVZvjJe06fk2){O9rj4#MZy&Yg!QwUk>O?-DpG5CJuP6)F zl~ONbuLzHw9zlJ@f!Pr2JmHs;TJdqsm z6GMN21=f?$g@Qx`K7tC#uw5YW*RI@n35|}KE;5lu#yN(WDrl|&o>Tf{g&rqQtQqP`isCezuYN)vrmp%EYUosOQh8M>p zxAZH-u-qjR_Ir=lxrqezxjGKt|HRgxfB8SMk%b%Qd2*9hOZdE-x{KPP!uaO?KyUx< zRWI?NMC%j@=EA9l8p(q9Q3vmvo#q{m(6`AD44UoqtnftCDr1UPKwV5gNlqBl|8Ix9uHO=}nb8Soqm5dK>)G`*9KzzLaYP5l+c}%b9+r*nTROnd!%YddAXCVeZBK6^Bg5C1BN}WTx>pc&hI$kR@zc2T z)Fpf9rrEFaoP}n;XGe6aA z<^98Sp3v=1m!*Eo)4Fhf&ieOF*b0DFYq5h-v_U@*Y_UOwwVSiT4L=X*OL*g4pCRZZ+A`xEU z-YJnhZz62gs~4-WsP{D%kaC!COG#3z&w$L|;b%YTJayZ&&p>fr+$~`RrH!*-9lY7X z$A;RJ8~@xPm>eVWCNrcW!)J&4{iqpl#JRU>5og~O=@R2=K1nEM`T8@LcDJ0|pPvifF-IhcN|B#wpp9)TyC*U+K+`M-O^a*#;JiQx1h?@S&Re zkmaQ+y-%Y=QDSGJ41p--UO{eP-^h%~S}+H$(Qa7SUY1)yNEWKon5zfwv;?_-S#YDqo3^oaXgri8z2GDn_@W)`o@J)I>Y^Hg|-w@?S45j$=rW zXfD(0ZA=TJTkv#9=%E6uw<=WD1zpu~Vp(ov0+XR1h-(;`y@n>Lna7dWt?@)qY`nF7 zS}h$FaUdB~ae_>j)Y!4YgVq;@Z-`iLV)%vAU4(WQH)k|j0Q zVb0+83h6nHJf+K$r?VrxtdC`BLVuLK=3FlFtz zr1G=qmnY!-uD16rFvYg0r5se%@6R?-)R-MRg+2AFx1yXJ0$$iMEV_kAaf}ckXhb+E zjhi^%_f8tJ)O>yLN_h=iZs4Al+Uco#gQ6#V0YI_|w=smDSWd6gjA4<1SkQz2c8*si|;- z!In8y?SaB6nRmQN5|^BmK757s^^q^k5x3TYtPL%lIE*+uEdS#U9Z~VqDdKp!8}NHS zODiy(8-{`r1|(<#c1S@?ah&0K-Gp2-^UNK%*1g)-!@S$!(6T%|(Q_hhGXqNouK4$+ zb;{lnkoaNxgX3MxLn*P;BR~wtSo3c3XEfEQSu-k!G1DqpO>SaSkw9i-f@BG?g@K%HACMh(hi$$Hvm( zt>j{FdCC92Nhy}H{bM7Tw*==CD%ph~Zc%9@+DJx=RyC=>vr5}vuzCOmOS1@>>OXrS z=96e41OVk$=_qVXwVpPKJ;veN($zw>{ru<#@j!x57Ki{_g|8m zl*TgUl#DZ@$9|i<>*?poigfrcWC}&>``yo%`sH%Mkyj)>rBIw!)Qj{p=xfw4OH6S% z_?7YCvBsj|9FIN8(tlBIQkD}yPI0=I01fZGq#(m*kiaB|FE%Xv%d7WOnlS08WrS+} zYG%3`<6`b4)Sdm?)_i6uE4{O~NKQ9K-q$NSW#b1?j`Qgu50RK*E0BNPANwP9M zhOt<~&ncAQFZi~+{$hveziJr)-avKIUu8b}FV;R<;cz5=(LL7Cr$ca(zl!UZBK+$r zU-~81;io3_RA=^oEPH|fl>TdUQT8W=`b9{`dYY9jfVkDvT(tWyw$b)Ll2E%p|4Q^Z zCU=1&3?e162%q3ze>vzs9hEU>pt4KI(%b(Ra(*9crs-$uz^Ask1{Fig;*_g{?e#%|4BCVVa31(OG?6YL@)=a==!5cf?p{m{rw6P7Xiz1X|wk?QnCktt3~{fEc1;YYx)TQ$9Y{@Uy}I^pN!oD zPy~Bi2%CFg;l1*|*tDnZqXmitIUa<3IWCs|Q{<1h7`g?QdQ2LY=38({|VdQ z1^@8LiShWuH}oI9z=5IM>Gh#ZrhUyoFN;X01p;rU42GPli5p>k!9Nc{Hv+D0f8lXV@iy8;(I9VG^-j_qURCsFU z-KIf-M(fI<6up;FZQA-|04)$_6zeSVhG+XIe|mjJeU^Xo>U6I(Zy^pfQ{)U~lz`Ez zG+75-?q zkg{k1O?g@5pMd^#VKEk~>y(=u`{*m`M7ivmJkBCP`O{b^Z+Xz7I*WYWGhMgn$YQk+ z4BkFd7qW3yBe-|4xP>#{Xepu<);jG>HK|#Z3m(tfkJ`^raDwMZU$R!^1H=6DeAldA z0lQg@ccgo@6te63C+pI1^$@$wEjYu{d@MCaaAfYjbsWbP20eZ(#ECi6*ARH|=S9Q| z+sm_=nX}aPim^~?DZV(D`P$f=Vd24{W!~0aIk8E5s-^9+%zQ7Ro}@}HuW`T@>V8vQV@vz zxyh6bu@sSxaQ_w3?xi1hi3!y1w5?Jr3v?BDFQq7pWoVRTD#?#kZQkp9V?4L!BG#Ed z$-gK=x;@ExwF0*8?q{QlqThZgK{v0mz$6N3hw;XCcBD8`uXP1uMnNhI!+&9@6Tg-_Pko;6_VW7*IL8&9TumQj|hc zbB9u_qSS{IC#RtbHME(T+4>W@XXyyO>+-U*6#!0pp|bI`FFBtAI*SbT5W1_%N9OxJk$Ad;ZWacD)Wf>j&=E*k>S)d83As zqu&qJ5(3`sN@XE}=QSgOEFIXun(D^MnwA+&%E$dfDMd^<+Aj)MYP0UDv_yHEp4K|E z{7MGru5_eaaFhPc<9KQ*0lk046MJqXswcPkW6g#55@*2B+a5ZHoIrx2d!Qj+-74&c z&@yzh)F&OmvKK~~U26XEDG7N^U};Et9|iU!o4!SaImCMCP{7?m4yEZ|E$R~eyT<-x z$_#gfb5;vD{+;llTnRy({xE}ApA5Lteg~66<+Oy2`2xp8n}UObgiX;WG8JVMY3u0- z0QZA$M6INNDodf6*QCpCv(8>N{|>SkVNNbyK5ex910mV$+A~ucbvA}Bw7t&xQH+1M zmq1Y8Nb}J%b-`E4EpvANhky5P>-xgwr@0`Jpxm;QAIGb`)t!-66Uio33{OWuVIYx- zswr+>4kEWAgM-u#BO0pV$w@$F(NFe`<>7fweKUVRmH0$1J9pPPN@Rj1Q0OpZEF`{2 zJ=g&uD_1997@IWJOII#VlW^H>(I6?Kar*ZYc0mJ^HhcExnN_DS36J zTogO5{gF*A2d%Q=GajX9ZOhH)vx>OZRzb^$`3?0@yj3FByxnXi`?qosCM}SnuYu&& zQ`rY^iic9K*DmM#1b;u19f(Bi3hw-GgNniCWY~Vam@nY zS+{{ee%uy2q+X|opHp^9nxR?Ftt55FU^}I8uEq$iN(2AWu*EyS7Ph{B1GCeEOBx6b zEHU)Wdy9WI=RM>5E_vQ8Qb$Wc{~Jbl9@GTwhi}eKKOoJ%z zI*R$E$NuK&0dI?ydrmd!sMopVuQ^^7fZx?$=(oK(D>UQLnBM`c$#PmCR)?Q|1$Bls zwDn_JyIVFZ*lz+wPGn|gDfWh?GTCw@>nnss){>Ve;XU3nLXTyyxIr#@7Jo3sdZu@= zRJ9<-KJt4l3{JfVrIDsGi2lV+wSF46umgbDadvzlOxKH6&F8R#eQgHdD0R?`Vp^h* z1COn^YFYK3Zw4S24qOjF_+~mc%(yq$kt$@<{OfV6CDz+AuUR1iAs#b$l z5lSiaP^aBB#O0QzQmz)%@ILJpf3 z_rGG{L=mc*%rtWd1*YRSn62UBA7pil(r?qh$yWO`@ATg5bQx!9RHhZr&I)7Q!0sC24h#(W$uKxURr@W4B*ydTZ8eM< za$gIjZxD34`v5vOAQ)AeF<-ROUO)b-OZ28a+tNHVJ%zbHZU&h>wDcg$+nP~2JS>Jn zOI0AMtJNUATkCYRo)!9?V%#a+#`N?^(JAP9B;5F#T{=L^Bt2PqWik=5(Tgy~@;6od z$#=9cCsXcv8T8CdB4U&6px&&5eakTHwg{MjU?@j`mUMAi@qHP-I`d;th6k63*%{4l z)S6+%_u=UNREL7b9G6m@m9w{@@s$x>KKgwTZvKL9-$U2L66ev8S$N>ZV}`2reU^~s zF?Q9Em}|uS(C4eZ4EvT^52OQOb*Z_WTxeKT<1*_#$H}ib2x;==Uoh~*R0l+qVqmQ+ z?NHpph04mYZ<(B--Yb{3p5zv-`97EzrySsyf-LduhC!6#xZP6B5EeSt*h?ST z2D^%^+&dL`ea(h&Iz)c8Bh1+QqhzV%-iRL0oAVG_HM`>V$Hv!y@mQBgzJaUb!H9wnxwp_qo{x!0K-N|}Gge7&cwh~F`r zQrC=ouDK1BlloDc0i9oQ>NJj%ym+~Bo@rQi*3iM;!70088lLVmz719Fw`vcv9`Z&z zE1Aw3n}$`j6d=ZmON(9cOG!A>mbf$7HP|fj+cA4_wn?+EL)7>opn#}Sxv%J#GtFS%^Yr)O&i@AM_KY=kP;p&c?mhMNQL zA0M6_+FBO6znpltNkKRYgkrBSp5>!kc4SdK{JX^&*Qol#iXAGYarGuPic*tq%h~d- zk*YrUmo|KkcI}xkX{Zx8SJ^wq*~@8g(qP^6eo%BzXop61T=aEGDJTj(%o(tt6q;*h zW-32;UYJ&$V(shl9;CG`lhB7+8R@*z8OH3jD;UtBycKu5e;r8$JBXLf+;`aP4Bj|f z6I_g_ZWzINlZ#i8Y7}R!gEK7=MJ2%evalP6MULk!$j zVgT47IqGizDifG(G2>zM{(`P?iU*ZaUF70l!v*kbcG+Gn4(aHo#Ik#7sG-Med4{fA z@c1?qe~4;Dc$w?0H>~G+badPM zm?2j`2sWWgr&|ZB6X+=FRvH;(EaFNx7c8rZ4KfE+97|! zp>PW{2$R(ImKpMF0Oyo_#GZ4-i*fbV(j*h1JDh&Rr|%-V>6H-qBr1xl|_}|m^CrZ+Hh3O zY-j!QTm+Om7UgHOo&!cz4FT^&Q8EtcGUdUk=y{&&2I=}f{WRDFUYks3{x(VQE^M*dj#)}OU zv$vzOW0a+67?*3F968uvZZzv(J#z01>r61TZ-44=sy7nWABips^X51dMwL`v?}d56 zeFYIGFCR0xW|0-JIj4UzRo*k}s9nS%X#mfW;{{VQ38P_?%kUVpd<}AHcCg>aqHw>Q z`J(G@W6;M-H~Th4s!rPrCzSNvOJHF=3oUA7Af!URn(CBJcO^p zsrIIJ?kLZ}qYAc6uXqc=T~jHrsCkDpm93wzoi2C?gk{~*-=z*l(P!MO&=J~N(!s61 z0EBWG48W_dmxr9B4CwEr)y1fv_A9H-8ep9EMwV-I6~X*x*k~+B5smh4)xzmuh(~)$ z2hpeP8m8%XF4hw9MMKROT)1Q) zEHuF6Cl1!Duq?J30*M-xuAPj=N}&>Wo!@0l+B01EbiPK4rr}iNUfMEG^#$|Up%Y?& z%Rg^Al7d{zYaYVBQ)!;`oVU%#LiJ)wa2m6nxlVfC_M}Q>oLOz%=R8oE=ZfpngUEDr z^cS4GKheK6-{8Bmn`2cr22~ZcoX9E6o@%#?3bJYJA19qFzGBbDo4;c6_JFCP{)qnL z2p}W(+&EVA$TgT}iKo5GzB38SPw9lW`?%iiw8Avam*h|B9w4Av)2^QxI>Mwmyr}ac zP3;dM0BFpz)iEXm2gVu(a>g_{8@>ax6Y-Szy#&hC>FKC^g^D?b6=!uQZY^(q$Ydmf zw1hVECOu9m+z-}kCvnQa=RaGTj;)Q_w|jhdm-%<=NcxfOPqlK#JM2$h+zUA1;i|EC zxK9RW?Lj{gZsygw+t5gi=#i$mgT5*%uraKn|DMJnSAUn(npu+s${AeW zQ*`OnG+_Ha=lG9VPN-TM89p4>m#>E=<8uvfPo~B~r2UCO>0%yQ7mZU4g7zQO8njP; zRY{R3AFOwTTKcOiGV7*16HMVBNx?c-8{lcZ29TUAAWe=H6GlS;B|uCvQ}NV z8P%!6ecLRl6&4TDG6-&~S&l+GUoKkRfl;*5{q)HJe88!c{D^E(o;{^HAs6%t5j^j{ zEhR<)a>k+91!Bbba5PwNgsL8^!d`VfXbZZ&l)88pWaCLH%GM?9AiM;g0EeoD*`yUN zxqN=7-n{JdMxfbD-IzZGJ-4(oIohsyq;d+5^Uk-@UlznqrbRr4?J9N_w$^H!?ad=k zUFYn?W%cX0pl877L7QizOrM9{K>kStX52EZb|i4icLIc;hBP(Z9in_1e%W?8T z9wk|x>rOpM$eWBAuzkN*hp0CWpJeQT9Vv^9KabQaE5=P(wRadF$hXo9zjd9Ym%xDG zqA=`NL+lJX(X)lJid$2i14hvyR*_Nj_HjXDxz#s~>qCpfx*oOkE%OHQ+eaJx)f4Qvrc!3?aIfNDj1Usi`!@I!IfoIZ#UGDb38nEK2 zb*>#i)Qif{Gv-Z~GF_xrJG0s^!bg6iB}zDfDP>uCZu51s10QR<7r8EFG}q>~bI;rvC$58L|vlS8wzK{vvc({?G#v*b!IT1ve#)>?pm*> zyPA2M4Q4oU5N-vI1AP4WCY(4F_TKQSo!>>{SEm0?KK(oU6Kg6MswJe8@f7@~`~CU- z_d7h~=Er^A*L~mDd7amJ{i4N|YIN>+9U7K?-q=o*e^!F+TfKD|lkm~8u5wSrlP$OO zM79rP0K0F_Ju|&uNmnVK6Cy?<+d}bXj4z&xj&EhvKQVh=LIXwg<}@uk@I&YLArH#R zy+W&11&$1lHcc8*xoHusBdfV$-=D+BbAqoxe@fFoKU#5iX7d~Y$lzMHs6&m4s{721 zM~myOU@>Jl_rul~c zJM|5GBkom29Jc6kmB?A%)PD*M9Y1XBrGn_2dH>}YW9G#N7vlq^8a7JmnC#Nmqe>jk z+Ut=Uh2R`WoZ;u=8HUk~R%qET7R%d>9m1ZF)CfJTZ#8%=3aj*b9e-<;PjFUbbZEgv z4@_?&U-$(Lt@l-U{j6Aea+)k?7zl5eL*-)}epYO^Hu8sYLTRyq^Kq_zsa9{)eeQT- zS@SoVy*(6-Dp-VYJ0H`Z892wmY3KaD)Tjwr+;QzC>Wof`pEjdBq>w?xWTgVe%2@~1 zd-#hBuGa9*6+yT|HNc)lXZ_Jr{S!dEqOIMJLkLGAVCki%(?G?mn0MvT24T%g)yfuK zSc8Qi1f!tVa-Z+sh?(AxT_I$MJ#(WSZ`buBUxVyFc|7RZ|CZ~2n%lG@7ZqBp4tgfM zxmXfPwCDxK9C2+dzr@m%M208U$Cge-w<2VGCcEUFO+1>NiX98IkwZ(kCOqB=Jz*u?CyD2KT~|R(OWDkw3P5OgfYiSFQPI>u~q=+&5)$qTWAs}*#7bO7WFJs&6yUIo3T^RNo={Zi%;h07$qLiNa}qQwaS7^5j<1C9 z5f=Tv4v76YA8Qafq*^F>(ZA#eEl6*oS<~lQuFX(b1tKU^;!J-fI9%66Knx!Dv|hPMH!cK#JN7p#2CG=9Z{-3wI*+ZBB0Og)x8npE^g0GO54 z=kHx(?rsCKWf!d$x$HV}F}PGz2cZvrj5=b9ZN7%SS=vWa?Z=d{$P*QZfNzs=KH>st ztDSeyB#+RuPl9n?ru^(FM19BAFYR9lvsk4*bg`a^_%kHojot%!Soh% zE3>xSjh(sDP~Hd(gmWN4Hcr~ysjdO39jhq+QPjnOg01g+{v2#qYP_A>Fi%iRg}hbK z9?@=wFRY%VttxH1xn);>-)c|mf++eh?RmW33gM_Aa}MsW z%(V_c9Gom+A@vQ>Gv};8Ewsp2g9M7p(h3qly24e0Gcv=cVsh&iF)QwxIBf~+A|K9Z zUTdA})A#CM>Z|WlaMT8neU2Ad!eBlTIw{qxLh;C3!m<+=)JH)*W~U?gba#2XKFf&J zer6hThsrdaFc9Ok0y-o-Dg%5A?r)sjHBA_?+G@I$lKn=K0j<^My>8YSMxq3|N5v9? z-jl68#p9y8RN>(dUHW@^%cLa%ji#=eCA!U9>(Z1!$j2T`o2HXKLhFjbdk4JWiv&y( zq0^8J!g<5T;o5}al13np0EyE+IxmB8KV42B_LvPCt4WF04NI{Q{MBG#bEZ#a5`-v-Do}*2&IpzKQLiQ5he+^eZd>EA98+&Z*h+GQ!Wu-aqc2-1jYYWj+xhBOmxN0{`NF z{a+rgU;8xD@bOVft3a+r)+2Ltb=J>1#s&5JDi_ZRiVyMozl`zM|3rf2YcIY!k?^rU zg>!q{`S&$hyS%3Py%SH9q5t;c8%)JtBdk9p@MSC^Zj!UZ#o#FlOB<- zwEZu2s(*WzR;cU^h}HPlg}av*$hwsKul}c|;YK&q|9ZhsqjE4_;dkr}m;ZnM6|#Cf zjl-&yO)vhpdbPiY)~zG!FB`M_!harlqjyaJ%jnFpRSW6v|L0l#MzM(4FQX>To%?mu z|J4@%Ma)o_vDIq200I9i$Nq0tW_o=Z8FBe_Q^f9dPhqXDvaRDyg?Lt+cxv5ey!t-B z5Gz~)3cRfT8K5u9xG{^>_y5Zqy?;nPyq>22+amq<@z<*+u1stl6&im?ACVy(G+n~! z-78yvjz6O?nDN8)-`A53GP?MZf1{4dqsG^*5iEqz{^!xZs5oD{lSar;uZ#$=JCPJa%>+Pum9GggPf5PbK1}UGYym^? zk<%!?bOO%M%KIyhX1$S=qezLd|ChZ!mDWNuR=0u%!+;Ou3TtV#wGtC z1CcFUU~NJ@EwVSb2@O)t;kl{e=LPU1j zz=jJ!ru%~TKz*Vw!}n+b2^Gdum=s}d+M28@u@yN^1MMa_`lRePA=xr0vr-eW^*Tn* zKi>`@jcf~1O~~w&QL{WGlZa(aO5Qx6%V#F?itdCjViPKYYP|2?>r?*aWvLo> zvo#N+q7QKfw!g7BbGKUaiAwbosuK*J?5_aq_4J6eo|p7nOZwX%IRkY{W0t??q^#CW zBN&DGPpYLB79HF5O$Pl0QwV+i&qhi5U#`sIM@4k2AGG>;Eo)MegeBDgJpN zm`r$7lzX?J)0{p;T`jXXQ9n71kRHKwYWklv?l6V zp^uO5sdtjCf6l7XhV6e7>~;@Ls!crb(7cj6M7`Z)Rotp>?7+z&F6a(uZ>H|O1Efi1 zeYmY33DQL(`^}>#<=@{=GCSNfy32d-^VZ5O1E=e~bjyyw_Dr6SPY#=@FXlGBNO@T# zsw>VC;igAi%wNXAJgBrbVwo(ZWTn)YYQvGWouJJ#T}~3H9HG5EYJR@xqP@GynP;gK zkH+ZZFv>y{TLw^WICGJP2@!Ub4_`ppsQmgx8J-)z!21Y?9|!%OhU5{&bEF=L%T@!z zCm9mFtX8zSdwaLTj69{RE^LG;jFLA1Y?{TB1JY8&W z4FI{SC?Yz(G`vkPF}g(o*k2(KVq_H6(W+I(@Nw`t|u0E~e)Y%;@DxIS;bR zZ>ao?k~CX!has)dg?O|w^Y}h|1A+j+xGb=s)IcVF)~t!U~q%F=PLY?#7?ye+ZYTO~CgI1$kL;ADkmjP|jimM4(-e z%5BiwlWy*w9&OEP%7Ax4Pv>HTRTHn{mc^k))? z=3U~cLWtU)kVPUC5_N~>+;zJX>#B*vEze!S(^q&abQ))-Ae2uPIZ7W_?p9rNx@|l*-Rm<P?;MHnry;KRC0yA!|_2(##{Wd2kX>hbB2yq|BFV% zPp2P81QirRs#7<4#GS|RnQVH-jMsSJG_kbBp#UL!Go1bxN_JhE6=2XT51f4x;D~Iq z)SM;g=jE4vr;cyOfWzU?q@h(aUG)V#o>cuWnw6YZh3K)1_#;I&ibNq$1kG)SJ6HIxY zI_)y(LD;Q3YjM*({qSifN6P$#>*!Qs@L4`C4M4UNg6V$dM{PfWGb1w8un)vXpBdy<~Ik=vekDrHm8EEfm{yqVs6#g2?E_Bwazqh-$LfqY)S;f40@qt-^ij)p-!zJ_hHb7W=c z61y{-^^G}XwvOG4)8pZUaAt0u5r3e-Ia*w&>jp9yahXnmH?APdy6cu$<3Enc=WD+c z02%)5PRExY9jj(xVc0*Q7`rM>Z7zhE8tZNeVITa%U+mPJn(A?4u6$9z_3LG!QTJ6x zzVu*?uSC#IMJBJS(_T087Q-s6a3=W3<}Ber&xdg7=%14Yj1Z=*wb$_JYC$yGvWg}; zhNuoIs5IDW-0-G3%YMdpf!4Rb&SCHS%N*`YVBSKnXM9j~wZ#=GM? z#Og3Al)d~EWGT%Zm07F24o`+OpT?W_*XGbFSZw;xi+}+f5S#5n_#zg=C1=KR3?Af| z(JXPON=*@&0`TET7ZwfBEhQM*qY;zv)x=P!gFyfQr$j=7#xQzRk+^}~kB#OEW9(EU zQaGntS>+GNR2Yj1FAW0z!5uI98D6p7n#M~W>&7V=8%cX3ZimHMu;E}XK-_et5kBp- z>`eDCO|jZJAks4k@Jar+8>j$djMBpt}#28XGrc|k~p zOM`~ERrVueh)i1{CUo(nvGaLj%z}DcP@pRhyHJ-Hd0r+%FkN9>b^fLk)ZE?DG%Fh- zNSSeK{+y-wNYe9`z-H*rl^agb-}5u_OR&lpR02jrlu?bQR~Zul&YanF0qnSHc3{gN zLZ;w&DWQf%@0{>U<*Tn)ML0B5A<7quYLn?Bnb1ZpR<8?(Ow}ldmEUXjDKva)$QNf& zJ->GWRKF$!)mD2O@Ry^tmok14y?UfcJHxG9u(I}V;e-vSu3g{^%Fbg^oz_8y@Z{Yj zk!1kuJU6UB9)}wSh$iZQF2NwP2Sf0c!MbVP%J=yc=}V2U+dcnfQNajyt(rEU4)N_7 zI7C91ujrxOaaf%?11h8iO5qr>P<49Ysw`JUMq=*kB7qeR>{Z&4Q!G=!V~oO#aA}L` z2v_BCU`h*qMi(NvzWCa;y4WrNJYGAF^{DQA|<(T430}%{1 z#Lk($50+q`2*ZxJ;IKZ1r|*a_`{oX$Tg=w<1Whx?u+;2;Jh;H8#!eMMS1=lHFu_27 z!kCLWA3bCOUN8qN&Hfx6XXb=HjVV{gq=?W8`eGe_bH?g`-s%6=0+<)ZRV#?dX=_%} zQHgBw{^a=uNO}kmDa3Nv41rH>!8yBd?H$fT&p^}M=?0~4oHA7wc3E{YtV^7}n$mTI zyEZUn=p&M`q*WPTle6r63hDx{0Occk8*d*ROf0v!n&C1!Uyo}ETzN9BnFI)C6y6>hZv{!?o@VFwyy$Ho7QhZhn3EJRkdj8^3SsM}Vnrj537&UwZ#6F} zptoSMfL&mM-un8g<-wA}VSc@oFGF@C;l1W7Xk!vJC(wDEIo|fhs4Lb#=8D(MJgrm< z5#WU!z3-G4ph_j>nhommJ0g4f38&fe8Ffj;kL1ez27jF{1YcT|S?guSuN45;0M&p{ zJcZ|yA-%aZz?87Af5y>HhX?dsCjW>r7DgOi}b6eM{8SV`=2a& z_Zts@DY*lb?ZO~1ez^%gP|K{16NdF}Ed3x*TaUdqz0dA+vEFwKREla0zLYjRBOxg2 z(h4HT^%#2^0W6aqEO>O(qfqQw#H(p(+2jIyh*xxyEhV$hpH=+lC@T&=gKV)k2j0Z# zsd4eIHa0CA!vxP&s}yyOGZBMFNQDqg1t7JY7L3#ON=G`poM9xkeWc%4pP$Te$xtZm zvS8Pj*!NvuG!~7Q5XK)k7Xh;zS-l#(GSAu;?ee3!v(B0(SV>gR?Ryqyz7DL2zuI~8 zIDtK|6Rgo_7_^faVjXf&S)B{P-GfXZ>VeclG zPo>Y}*3#=a{EYh21rsx&>rh+2urkWps23Alr{|MuiXEr}g>XUr#%fT2qbN8e6%|0M zQbFjRcBxtBn&tnCdmuSK8MDi&ex?3o(i6VJ8e>Z3g7Jo44zbF0j; z17+$!83E5gubu~R%5n@tLDJzRO^X>E1NIlna9=ttGfJQ_klGZCtGeXsaui%k*z>IxpJud`+Iy?VWmwv-K_WtpiIGFqtPR41Csm;u~BWVA4{1R$UL|@VB5t-RP& z_R@BMgJ7UT5Cx24v*{FbiYv02RW2Gye7zwYm(aX*Hd;P}_!}zb-d)(MK3mx_&iw7A zaW?g#@ab3%!)e0bi9f|VYU-JnO$e*PB$fpw59U)O!P%wr&Z+qj%PyWgsbtSx#tN=z zfZE&N;tfuZr9Rs6NJdw54F5tI!O%Jn`=2;Jo(5REQEGjS%IH}s09QaS9!f`-M3uAY z{bER03~*&gUt3h?KjKk$uiwwQg^lE!bMNW()H?(@1DCQ}q`Tu~cOudrFG3$J$+OZW zDR?%sn>2rgXYw7holrbg;r;hl{oR2^p zUraw;j~}52+BcN;>C#3u!otsC-9(fYhl;bzUrog3a!!6KE139B@Pm!dPJ3zyBuhX9i*?0U1fM!Vh+W#1~}Lygp>iI`W( zn--%WhAP#c8DjcQEH?(BjCCwt#qq4%t_(dptTwP2l#k|K^5+uLjT_IB8 z8zJqj@`%HMk^4Djqv7i)=5^4s(dC|l`n#iM%1UqSG?qg0R6Zj#oF~g9H!12Fu$V+? z+CdRF#*4CiV~KPzto9>wiDuurj&1rSQXw}DgH~prZW`i5ZBpCrp<+Pu3#!kfG9OyGTbmeT;P0+vG^sj9cL@gY z%&%Sn$gh%�E+=*#$Yf8)8vJb1}=9_dWABXCqD%pWa_q_sbD7Q@=YUrk0Qi3$a5 zS=Fn5S&oE`_j|oFZ_D+yPvE4}!D9m%`DxdI?vkAD0akeTcH_tF-D0v#6bqA-#hksR^_wjm7 zyHWIrZM^A4S~+x3trRbH2sw_R%>kr3D@}`AdQHe^23CtVu4>Z?VW2J{3z)kpX3whDnT;pQ~(JQt=qYXB@J*E z`j)AW*?o(cD5iTyBSl?%1T*pj(Mhn8j{Dn581t?JSt0V5nBup zr#y!T7rD<{n%b)KmcUc)W!X;ML^VqfRTr`;J7%D^sWcAewPS3Ce~Ry+HK#%)_m*%Bm%7Bv(isWuwV62RP1+#>ej!2Qj+T=BZoXm#6Wy3UVW{q2*z< z@rS&i9x~qb_2{|suO76K^2N~rF(LZ$2rNs7eOShLQTmIn zs}!8X)6LuL!GWy)qr&XsXculW*zV%^Ry5-MOb((ryxiJ%Cx`H(sK&F;m6Q~7!O!vC z`|u^VfW1L8oov2Rb`wihRWZ)9!bo!BorY5!dP~IeN!4lP8VE}?c-#Y_F|1E1rkJO> zBWVLXZL-bA1f}|`HzG2gWIPxB5rfkv1m8VAtDcb_5=R!u@k{#%ig#pGw$cHCR+Hr5 zd1G%;zQVt#Y=sQ=)Usc9PfI}KRWvm<#wnKnqi>}xq9`DTU~DRG$XyPwkeG`2E<^~9 z1&q0EFWm84d0}$Qm)aI=vo5>J3`D#EewALs?q%>$ z@M^VD&z-q@4bALulo1vxhQoh~v4TRv=2;hSa6}{Y1|+KPk77;>mo;O=uHxRMw>eAk z7vDV{S2n#u$!h_Sb{UOcO%x1)s1_JLQBdAdGv4_Qi*{X;DY~bykvu!-m0l2MO}oFY zoj?y88S9M%`oTX3PtuJkvjXnXVh z@t49=W46kmh%(uFe23)?AE)?l>z^8!+%2xlBN?%1#N)wfUGsT*XQ2$?CHs z7l_NKoC9Hdf!j0clfh+YVU3pj_<^e6zgUYthHO z@OLWR-Dj4~rz<31GS4IxH>WyWR-MYLi=30VJEB({YJI$KH44~;$Wc3OGGHbm^%0** ziQLKnvC7vZer-+o4bB=FdCD;%0&*Vb>$y@(usr;yEc18C&R7P2#j2hLbxm!ftxlYG zL57dNB2tJlBHmbj4EQLC8|5bYBjlI!K$YGXzdv13h@wQLr^?tUlMl|vf3IO&>>fp} z<)tCo_(&c+s?x`_Au7Wp^*XS3644_m�-ID=%B|=h~b5ZOc}~$w;f(<4)0Z?9))3 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 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png b/.pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png deleted file mode 100644 index c531f719c85429fa6192eae82bb434e0318de801..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13152 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 - - - Prompt - - - - Inline Prediction - - - - Prediction List View - - - - Error Feedback Provider - - - - Feedback Provider - - - - Experimental Features - - diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 4e68af42c5d..97d2f4fc46a 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -12,7 +12,6 @@ jobs: variables: - group: msixTools - group: 'Azure Blob variable group' - - group: 'Store Publish Variables' - name: ob_sdl_credscan_suppressionsFile value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - name: ob_sdl_tsa_configFile @@ -153,199 +152,3 @@ jobs: Write-Verbose -Verbose "Uploaded Bundles:" Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose displayName: Upload msixbundle to Artifacts - - - pwsh: | - Write-Verbose -Verbose "Pipeline.Workspace: $(Pipeline.Workspace)" - Get-ChildItem -Path $(Pipeline.Workspace) -Recurse | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "System.DefaultWorkingDirectory: $(System.DefaultWorkingDirectory)" - Get-ChildItem -Path $(System.DefaultWorkingDirectory) -Recurse | Select-Object -ExpandProperty FullName - Test-Path -Path '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP-Private.xml' | Write-Verbose -Verbose - displayName: Output Pipeline.Workspace and System.DefaultWorkingDirectory - - - template: channelSelection.yml@self - - - pwsh: | - $IsLTS = '$(ChannelSelection.IsLTS)' -eq 'true' - $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' - $IsPreview = '$(ChannelSelection.IsPreview)' -eq 'true' - - Write-Verbose -Verbose "Channel Selection - LTS: $IsLTS, Stable: $IsStable, Preview: $IsPreview" - - # Define app configurations for each channel - $channelConfigs = @{ - 'LTS' = @{ - AppStoreName = 'PowerShell-LTS' - ProductId = '$(productId-LTS)' - AppId = '$(AppID-LTS)' - ServiceEndpoint = "StoreAppPublish-Stable" - } - 'Stable' = @{ - AppStoreName = 'PowerShell' - ProductId = '$(productId-Stable)' - AppId = '$(AppID-Stable)' - ServiceEndpoint = "StoreAppPublish-Stable" - } - 'Preview' = @{ - AppStoreName = 'PowerShell (Preview)' - ProductId = '$(productId-Preview)' - AppId = '$(AppID-Preview)' - ServiceEndpoint = "StoreAppPublish-Preview" - } - } - - $currentChannel = if ($IsLTS) { 'LTS' } - elseif ($IsStable) { 'Stable' } - elseif ($IsPreview) { 'Preview' } - else { - Write-Error "No valid channel detected" - exit 1 - } - - $config = $channelConfigs[$currentChannel] - Write-Verbose -Verbose "Selected channel: $currentChannel" - Write-Verbose -Verbose "App Store Name: $($config.AppStoreName)" - Write-Verbose -Verbose "Product ID: $($config.ProductId)" - - # Update PDP.xml file - $pdpPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP/en-US/PDP.xml' - if (Test-Path $pdpPath) { - Write-Verbose -Verbose "Updating PDP file: $pdpPath" - - [xml]$pdpXml = Get-Content $pdpPath -Raw - - # Create namespace manager for XML with default namespace - $nsManager = New-Object System.Xml.XmlNamespaceManager($pdpXml.NameTable) - $nsManager.AddNamespace("pd", "http://schemas.microsoft.com/appx/2012/ProductDescription") - - $appStoreNameElement = $pdpXml.SelectSingleNode("//pd:AppStoreName", $nsManager) - if ($appStoreNameElement) { - $appStoreNameElement.SetAttribute("_locID", $config.AppStoreName) - Write-Verbose -Verbose "Updated AppStoreName _locID to: $($config.AppStoreName)" - } else { - Write-Warning "AppStoreName element not found in PDP file" - } - - $pdpXml.Save($pdpPath) - Write-Verbose -Verbose "PDP file updated successfully" - Get-Content -Path $pdpPath | Write-Verbose -Verbose - } else { - Write-Error "PDP file not found: $pdpPath" - exit 1 - } - - # Update SBConfig.json file - $sbConfigPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/SBConfig.json' - if (Test-Path $sbConfigPath) { - Write-Verbose -Verbose "Updating SBConfig file: $sbConfigPath" - - $sbConfigJson = Get-Content $sbConfigPath -Raw | ConvertFrom-Json - - $sbConfigJson.appSubmission.productId = $config.ProductId - Write-Verbose -Verbose "Updated productId to: $($config.ProductId)" - - $sbConfigJson | ConvertTo-Json -Depth 100 | Set-Content $sbConfigPath -Encoding UTF8 - Write-Verbose -Verbose "SBConfig file updated successfully" - Get-Content -Path $sbConfigPath | Write-Verbose -Verbose - } else { - Write-Error "SBConfig file not found: $sbConfigPath" - exit 1 - } - - Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" - Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" - - # Select the correct bundle based on channel - $bundleFiles = @(Get-ChildItem -Path '$(BundleDir)' -Filter '*.msixbundle') - Write-Verbose -Verbose "Available bundles: $($bundleFiles.Name -join ', ')" - - if ($IsLTS) { - $bundleFile = $bundleFiles | Where-Object { $_.Name -match '-LTS-' } - } else { - # Catches Stable or Preview - $bundleFile = $bundleFiles | Where-Object { $_.Name -notmatch '-LTS-' } - } - - if (-not $bundleFile) { - Write-Error "No matching bundle found for channel '$currentChannel'. Available bundles: $($bundleFiles.Name -join ', ')" - exit 1 - } - - # Copy the selected bundle to a dedicated directory for store packaging - $storeBundleDir = '$(Pipeline.Workspace)\releasePipeline\msix\store-bundle' - New-Item $storeBundleDir -Type Directory -Force > $null - Copy-Item -Path $bundleFile.FullName -Destination $storeBundleDir -Force -Verbose - Write-Host "##vso[task.setvariable variable=StoreBundleDir]$storeBundleDir" - Write-Verbose -Verbose "Selected bundle for store packaging: $($bundleFile.Name)" - - # These variables are used in the next tasks to determine which ServiceEndpoint to use - $ltsValue = $IsLTS.ToString().ToLower() - $stableValue = $IsStable.ToString().ToLower() - $previewValue = $IsPreview.ToString().ToLower() - - Write-Verbose -Verbose "About to set variables:" - Write-Verbose -Verbose " LTS=$ltsValue" - Write-Verbose -Verbose " STABLE=$stableValue" - Write-Verbose -Verbose " PREVIEW=$previewValue" - - Write-Host "##vso[task.setvariable variable=LTS]$ltsValue" - Write-Host "##vso[task.setvariable variable=STABLE]$stableValue" - Write-Host "##vso[task.setvariable variable=PREVIEW]$previewValue" - - Write-Verbose -Verbose "Variables set successfully" - name: UpdateConfigs - displayName: Update PDPs and SBConfig.json - - - pwsh: | - Write-Verbose -Verbose "Checking variables after UpdateConfigs:" - Write-Verbose -Verbose "LTS=$(LTS)" - Write-Verbose -Verbose "STABLE=$(STABLE)" - Write-Verbose -Verbose "PREVIEW=$(PREVIEW)" - displayName: Debug - Check Variables - - - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 - displayName: 'Create StoreBroker Package (Preview)' - condition: eq(variables['PREVIEW'], 'true') - inputs: - serviceEndpoint: 'StoreAppPublish-Preview' - sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(StoreBundleDir)' - contents: '*.msixBundle' - outSBName: 'PowerShellStorePackage' - pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' - pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - - - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 - displayName: 'Create StoreBroker Package (Stable/LTS)' - condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) - inputs: - serviceEndpoint: 'StoreAppPublish-Private' - sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(StoreBundleDir)' - contents: '*.msixBundle' - outSBName: 'PowerShellStorePackage' - pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' - pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - - - pwsh: | - Get-Item -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue | - Copy-Item -Destination "$(ob_outputDirectory)" -Verbose - displayName: Upload Store Failure Log - condition: failed() - - - pwsh: | - $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" - $jsonFile = "$submissionPackageDir/PowerShellStorePackage.json" - $zipFile = "$submissionPackageDir/PowerShellStorePackage.zip" - - if ((Test-Path $jsonFile) -and (Test-Path $zipFile)) { - Write-Verbose -Verbose "Uploading StoreBroker Package files:" - Write-Verbose -Verbose "JSON File: $jsonFile" - Write-Verbose -Verbose "ZIP File: $zipFile" - - Copy-Item -Path $submissionPackageDir -Destination "$(ob_outputDirectory)" -Verbose -Recurse - } - - else { - Write-Error "Required files not found in $submissionPackageDir" - } - displayName: 'Upload StoreBroker Package' diff --git a/.pipelines/templates/package-store-package.yml b/.pipelines/templates/package-store-package.yml new file mode 100644 index 00000000000..7667b1361e7 --- /dev/null +++ b/.pipelines/templates/package-store-package.yml @@ -0,0 +1,242 @@ +jobs: +- job: CreateStorePackage + displayName: Create StoreBroker Package + pool: + type: windows + + variables: + - group: 'Azure Blob variable group' + - group: 'Store Publish Variables' + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_codeSignValidation_enabled + value: false + + steps: + - checkout: self + clean: true + + - template: release-SetReleaseTagandContainerName.yml@self + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_msixbundle_CreateMSIXBundle + itemPattern: | + **/*.msixbundle + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download signed msixbundle + + - pwsh: | + $bundleDir = '$(Build.ArtifactStagingDirectory)/downloads' + $bundle = Get-ChildItem -Path $bundleDir -Filter '*.msixbundle' -Recurse | Select-Object -First 1 + if (-not $bundle) { + Write-Error "No .msixbundle file found in $bundleDir" + exit 1 + } + Write-Verbose -Verbose "Found bundle: $($bundle.FullName)" + $vstsCommandString = "vso[task.setvariable variable=BundleDir]$($bundle.DirectoryName)" + Write-Host "##$vstsCommandString" + displayName: Locate msixbundle + + - template: channelSelection.yml@self + + - pwsh: | + $IsLTS = '$(ChannelSelection.IsLTS)' -eq 'true' + $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' + $IsPreview = '$(ChannelSelection.IsPreview)' -eq 'true' + + Write-Verbose -Verbose "Channel Selection - LTS: $IsLTS, Stable: $IsStable, Preview: $IsPreview" + + # Define app configurations for each channel + $channelConfigs = @{ + 'LTS' = @{ + AppStoreName = 'PowerShell-LTS' + ProductId = '$(productId-LTS)' + AppId = '$(AppID-LTS)' + ServiceEndpoint = "StoreAppPublish-Stable" + } + 'Stable' = @{ + AppStoreName = 'PowerShell' + ProductId = '$(productId-Stable)' + AppId = '$(AppID-Stable)' + ServiceEndpoint = "StoreAppPublish-Stable" + } + 'Preview' = @{ + AppStoreName = 'PowerShell (Preview)' + ProductId = '$(productId-Preview)' + AppId = '$(AppID-Preview)' + ServiceEndpoint = "StoreAppPublish-Preview" + } + } + + $currentChannel = if ($IsLTS) { 'LTS' } + elseif ($IsStable) { 'Stable' } + elseif ($IsPreview) { 'Preview' } + else { + Write-Error "No valid channel detected" + exit 1 + } + + $config = $channelConfigs[$currentChannel] + Write-Verbose -Verbose "Selected channel: $currentChannel" + Write-Verbose -Verbose "App Store Name: $($config.AppStoreName)" + Write-Verbose -Verbose "Product ID: $($config.ProductId)" + + # Update PDP.xml file + $pdpPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP/en-US/PDP.xml' + if (Test-Path $pdpPath) { + Write-Verbose -Verbose "Updating PDP file: $pdpPath" + + [xml]$pdpXml = Get-Content $pdpPath -Raw + + # Create namespace manager for XML with default namespace + $nsManager = New-Object System.Xml.XmlNamespaceManager($pdpXml.NameTable) + $nsManager.AddNamespace("pd", "http://schemas.microsoft.com/appx/2012/ProductDescription") + + $appStoreNameElement = $pdpXml.SelectSingleNode("//pd:AppStoreName", $nsManager) + if ($appStoreNameElement) { + $appStoreNameElement.SetAttribute("_locID", $config.AppStoreName) + Write-Verbose -Verbose "Updated AppStoreName _locID to: $($config.AppStoreName)" + } else { + Write-Warning "AppStoreName element not found in PDP file" + } + + $pdpXml.Save($pdpPath) + Write-Verbose -Verbose "PDP file updated successfully" + Get-Content -Path $pdpPath | Write-Verbose -Verbose + } else { + Write-Error "PDP file not found: $pdpPath" + exit 1 + } + + # Update SBConfig.json file + $sbConfigPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/SBConfig.json' + if (Test-Path $sbConfigPath) { + Write-Verbose -Verbose "Updating SBConfig file: $sbConfigPath" + + $sbConfigJson = Get-Content $sbConfigPath -Raw | ConvertFrom-Json + + $sbConfigJson.appSubmission.productId = $config.ProductId + Write-Verbose -Verbose "Updated productId to: $($config.ProductId)" + + $sbConfigJson | ConvertTo-Json -Depth 100 | Set-Content $sbConfigPath -Encoding UTF8 + Write-Verbose -Verbose "SBConfig file updated successfully" + Get-Content -Path $sbConfigPath | Write-Verbose -Verbose + } else { + Write-Error "SBConfig file not found: $sbConfigPath" + exit 1 + } + + Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" + Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" + + # Select the correct bundle based on channel + $bundleFiles = @(Get-ChildItem -Path '$(BundleDir)' -Filter '*.msixbundle') + Write-Verbose -Verbose "Available bundles: $($bundleFiles.Name -join ', ')" + + if ($IsLTS) { + $bundleFile = $bundleFiles | Where-Object { $_.Name -match '-LTS-' } + } else { + # Catches Stable or Preview + $bundleFile = $bundleFiles | Where-Object { $_.Name -notmatch '-LTS-' } + } + + if (-not $bundleFile) { + Write-Error "No matching bundle found for channel '$currentChannel'. Available bundles: $($bundleFiles.Name -join ', ')" + exit 1 + } + + # Copy the selected bundle to a dedicated directory for store packaging + $storeBundleDir = '$(Pipeline.Workspace)\releasePipeline\msix\store-bundle' + New-Item $storeBundleDir -Type Directory -Force > $null + Copy-Item -Path $bundleFile.FullName -Destination $storeBundleDir -Force -Verbose + Write-Host "##vso[task.setvariable variable=StoreBundleDir]$storeBundleDir" + Write-Verbose -Verbose "Selected bundle for store packaging: $($bundleFile.Name)" + + # These variables are used in the next tasks to determine which ServiceEndpoint to use + $ltsValue = $IsLTS.ToString().ToLower() + $stableValue = $IsStable.ToString().ToLower() + $previewValue = $IsPreview.ToString().ToLower() + + Write-Verbose -Verbose "About to set variables:" + Write-Verbose -Verbose " LTS=$ltsValue" + Write-Verbose -Verbose " STABLE=$stableValue" + Write-Verbose -Verbose " PREVIEW=$previewValue" + + Write-Host "##vso[task.setvariable variable=LTS]$ltsValue" + Write-Host "##vso[task.setvariable variable=STABLE]$stableValue" + Write-Host "##vso[task.setvariable variable=PREVIEW]$previewValue" + + Write-Verbose -Verbose "Variables set successfully" + name: UpdateConfigs + displayName: Update PDPs and SBConfig.json + + - pwsh: | + Write-Verbose -Verbose "Checking variables after UpdateConfigs:" + Write-Verbose -Verbose "LTS=$(LTS)" + Write-Verbose -Verbose "STABLE=$(STABLE)" + Write-Verbose -Verbose "PREVIEW=$(PREVIEW)" + displayName: Debug - Check Variables + + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 + displayName: 'Create StoreBroker Package (Preview)' + condition: eq(variables['PREVIEW'], 'true') + inputs: + serviceEndpoint: 'StoreAppPublish-Preview' + sbConfigPath: '$(SBConfigPath)' + sourceFolder: '$(StoreBundleDir)' + contents: '*.msixBundle' + outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 + displayName: 'Create StoreBroker Package (Stable/LTS)' + condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) + inputs: + serviceEndpoint: 'StoreAppPublish-Stable' + sbConfigPath: '$(SBConfigPath)' + sourceFolder: '$(StoreBundleDir)' + contents: '*.msixBundle' + outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + + - pwsh: | + $outputDirectory = "$(ob_outputDirectory)" + if (-not (Test-Path -LiteralPath $outputDirectory)) { + New-Item -ItemType Directory -Path $outputDirectory -Force | Out-Null + } + + Get-Item -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue | + Copy-Item -Destination $outputDirectory -Verbose + displayName: Upload Store Failure Log + condition: failed() + + - pwsh: | + $outputDirectory = "$(ob_outputDirectory)" + if (-not (Test-Path -LiteralPath $outputDirectory)) { + New-Item -ItemType Directory -Path $outputDirectory -Force | Out-Null + } + + $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" + $jsonFile = "$submissionPackageDir/PowerShellStorePackage.json" + $zipFile = "$submissionPackageDir/PowerShellStorePackage.zip" + + if ((Test-Path $jsonFile) -and (Test-Path $zipFile)) { + Write-Verbose -Verbose "Uploading StoreBroker Package files:" + Write-Verbose -Verbose "JSON File: $jsonFile" + Write-Verbose -Verbose "ZIP File: $zipFile" + + Copy-Item -Path $submissionPackageDir -Destination $outputDirectory -Verbose -Recurse + } + else { + Write-Error "Required files not found in $submissionPackageDir" + exit 1 + } + displayName: 'Upload StoreBroker Package' diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index aaef3c6f269..cbbdb70cc4f 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -12,7 +12,7 @@ jobs: inputs: - input: pipelineArtifact pipeline: PSPackagesOfficial - artifactName: drop_msixbundle_CreateMSIXBundle + artifactName: drop_store_package_CreateStorePackage variables: - group: 'Store Publish Variables' - name: LTS @@ -107,28 +107,32 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Stable/LTS)' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true'))) - continueOnError: true + condition: and(not(${{ parameters.skipMSIXPublish }}), or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true'))) inputs: serviceEndpoint: 'StoreAppPublish-Stable' appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' + force: true + deletePackages: true numberOfPackagesToKeep: 2 jsonZipUpdateMetadata: true targetPublishMode: 'Immediate' + skipPolling: true - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Preview)' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) - continueOnError: true + condition: and(not(${{ parameters.skipMSIXPublish }}), eq(variables['PREVIEW'], 'true')) inputs: serviceEndpoint: 'StoreAppPublish-Preview' appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' + force: true + deletePackages: true numberOfPackagesToKeep: 2 jsonZipUpdateMetadata: true targetPublishMode: 'Immediate' + skipPolling: true diff --git a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml index ff40941e31b..b1efb2a8097 100644 --- a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml @@ -173,6 +173,12 @@ stages: parameters: OfficialBuild: ${{ parameters.OfficialBuild }} +- stage: store_package + displayName: 'Store Package' + dependsOn: [msixbundle] + jobs: + - template: /.pipelines/templates/package-store-package.yml@self + - stage: upload displayName: 'Upload' dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON From e033a3b6be8671852f85d74933b0d73846b1930b Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 9 Apr 2026 10:15:48 -0700 Subject: [PATCH 246/275] [release/v7.5.6] Add comment-based help documentation to build.psm1 functions (#27221) --- build.psm1 | 847 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 822 insertions(+), 25 deletions(-) diff --git a/build.psm1 b/build.psm1 index abe4547e740..ec89abe22e4 100644 --- a/build.psm1 +++ b/build.psm1 @@ -35,6 +35,16 @@ $tagsUpToDate = $false # This function is used during the setup phase in tools/ci.psm1 function Sync-PSTags { + <# + .SYNOPSIS + Syncs git tags from the PowerShell/PowerShell upstream remote. + .DESCRIPTION + Ensures that tags from the PowerShell/PowerShell upstream remote have been fetched. + Functions like Get-PSCommitId and Get-PSLatestTag require tags to be current. + This is called during the setup phase in tools/ci.psm1. + .PARAMETER AddRemoteIfMissing + If specified, adds the upstream remote automatically when it is not present. + #> param( [Switch] $AddRemoteIfMissing @@ -78,6 +88,15 @@ function Sync-PSTags # Gets the latest tag for the current branch function Get-PSLatestTag { + <# + .SYNOPSIS + Gets the latest git tag reachable from the current HEAD. + .DESCRIPTION + Returns the most recent annotated git tag. Run Sync-PSTags first to ensure tags + are up to date; otherwise a warning is emitted. + .OUTPUTS + System.String. The latest tag string, e.g. 'v7.5.0'. + #> [CmdletBinding()] param() # This function won't always return the correct value unless tags have been sync'ed @@ -92,6 +111,17 @@ function Get-PSLatestTag function Get-PSVersion { + <# + .SYNOPSIS + Returns the PowerShell version string for the current commit. + .DESCRIPTION + Derives the version from the latest git tag, optionally omitting the commit-ID suffix. + .PARAMETER OmitCommitId + When specified, returns only the bare version (e.g. '7.5.0') from the latest tag, + without the commit-count and hash suffix appended by git describe. + .OUTPUTS + System.String. A version string such as '7.5.0' or '7.5.0-15-gabcdef1234'. + #> [CmdletBinding()] param( [switch] @@ -109,6 +139,16 @@ function Get-PSVersion function Get-PSCommitId { + <# + .SYNOPSIS + Returns the PowerShell commit-ID string produced by git describe. + .DESCRIPTION + Returns the full git describe string including the tag, number of commits since + the tag, and the abbreviated commit hash (e.g. 'v7.5.0-15-gabcdef1234567890'). + Run Sync-PSTags first; otherwise a warning is emitted. + .OUTPUTS + System.String. A git describe string such as 'v7.5.0-15-gabcdef1234567890'. + #> [CmdletBinding()] param() # This function won't always return the correct value unless tags have been sync'ed @@ -123,6 +163,19 @@ function Get-PSCommitId function Get-EnvironmentInformation { + <# + .SYNOPSIS + Collects information about the current operating environment. + .DESCRIPTION + Returns a PSCustomObject containing OS-identity flags, architecture, admin status, + NuGet package root paths, and Linux distribution details. The object is used + throughout the build module to make platform-conditional decisions. + .OUTPUTS + System.Management.Automation.PSCustomObject. An object with properties such as + IsWindows, IsLinux, IsMacOS, IsAdmin, OSArchitecture, and distribution-specific flags + (IsUbuntu, IsDebian, IsRedHatFamily, etc.). + #> + param() $environment = @{'IsWindows' = [System.Environment]::OSVersion.Platform -eq [System.PlatformID]::Win32NT} # PowerShell will likely not be built on pre-1709 nanoserver if ('System.Management.Automation.Platform' -as [type]) { @@ -281,6 +334,54 @@ function Test-IsReleaseCandidate $optimizedFddRegex = 'fxdependent-(linux|win|win7|osx)-(x64|x86|arm64|arm)' function Start-PSBuild { + <# + .SYNOPSIS + Builds PowerShell from source using dotnet publish. + .DESCRIPTION + Compiles the PowerShell source tree for the specified runtime and configuration. + Optionally restores NuGet packages, regenerates resources, generates the type catalog, + and restores Gallery modules. Saves build options so subsequent commands can reuse them. + .PARAMETER StopDevPowerShell + Stops any running dev pwsh process before building to prevent file-in-use errors. + .PARAMETER Restore + Forces NuGet package restore even when packages already exist. + .PARAMETER Output + Path to the output directory. Defaults to the standard build location. + .PARAMETER ResGen + Regenerates C# bindings for resx resource files before building. + .PARAMETER TypeGen + Regenerates the CorePsTypeCatalog.cs type-catalog file before building. + .PARAMETER Clean + Runs 'git clean -fdX' to remove untracked and ignored files before building. + .PARAMETER PSModuleRestore + Restores PowerShell Gallery modules to the build output directory (legacy parameter set). + .PARAMETER NoPSModuleRestore + Skips restoring PowerShell Gallery modules to the build output directory. + .PARAMETER CI + Indicates a CI build; restores the Pester module to the output directory. + .PARAMETER ForMinimalSize + Produces a build optimized for minimal binary size (linux-x64, win7-x64, or osx-x64 only). + .PARAMETER SkipExperimentalFeatureGeneration + Skips the step that runs the built pwsh to produce the experimental-features list. + .PARAMETER SMAOnly + Rebuilds only System.Management.Automation.dll for rapid engine iteration. + .PARAMETER UseNuGetOrg + Uses nuget.org instead of the private PowerShell feed for package restore. + .PARAMETER Runtime + The .NET runtime identifier (RID) to target, e.g. 'win7-x64' or 'linux-x64'. + .PARAMETER Configuration + The build configuration: Debug, Release, CodeCoverage, or StaticAnalysis. + .PARAMETER ReleaseTag + A git tag in 'vX.Y.Z[-preview.N|-rc.N]' format to embed as the release version. + .PARAMETER Detailed + Passes '--verbosity d' to dotnet for detailed build output. + .PARAMETER InteractiveAuth + Passes '--interactive' to dotnet restore for interactive feed authentication. + .PARAMETER SkipRoslynAnalyzers + Skips Roslyn analyzer execution during the build. + .PARAMETER PSOptionsPath + When supplied, saves the resolved build options to this JSON file path. + #> [CmdletBinding(DefaultParameterSetName="Default")] param( # When specified this switch will stops running dev powershell @@ -763,6 +864,20 @@ Fix steps: } function Switch-PSNugetConfig { + <# + .SYNOPSIS + Switches the NuGet configuration between public, private, and NuGet.org-only sources. + .DESCRIPTION + Regenerates nuget.config files in the repository root, src/Modules, and test/tools/Modules + to point to the specified feed source. Optionally stores authenticated credentials. + .PARAMETER Source + The feed set to activate: 'Public' (nuget.org + dotnet feed), 'Private' (PowerShell ADO + feed), or 'NuGetOnly' (nuget.org only). + .PARAMETER UserName + Username for authenticated private feed access. + .PARAMETER ClearTextPAT + Personal access token in clear text for authenticated private feed access. + #> param( [Parameter(Mandatory = $true, ParameterSetName = 'user')] [Parameter(Mandatory = $true, ParameterSetName = 'nouser')] @@ -814,6 +929,18 @@ function Switch-PSNugetConfig { function Test-ShouldGenerateExperimentalFeatures { + <# + .SYNOPSIS + Determines whether experimental-feature JSON files should be generated on this host. + .DESCRIPTION + Returns $true only when the current runtime identifier matches the host OS and + architecture, the build is not a release build (PS_RELEASE_BUILD not set), and the + runtime is not fxdependent. + .PARAMETER Runtime + The .NET runtime identifier (RID) being targeted by the build. + .OUTPUTS + System.Boolean. $true if the experimental-feature list should be generated. + #> param( [Parameter(Mandatory)] $Runtime @@ -853,6 +980,23 @@ function Test-ShouldGenerateExperimentalFeatures function Restore-PSPackage { + <# + .SYNOPSIS + Restores NuGet packages for the PowerShell project directories. + .DESCRIPTION + Runs 'dotnet restore' on the main PowerShell project directories with up to five + retries on transient failures. Honors the target runtime identifier and build verbosity. + .PARAMETER ProjectDirs + Explicit list of project directories to restore. Defaults to the standard PS project set. + .PARAMETER Options + PSOptions object specifying runtime and configuration. Defaults to Get-PSOptions. + .PARAMETER Force + Forces restore even when project.assets.json already exists. + .PARAMETER InteractiveAuth + Passes '--interactive' to dotnet restore for interactive feed authentication. + .PARAMETER PSModule + Restores in PSModule mode, omitting the runtime argument. + #> [CmdletBinding()] param( [ValidateNotNullOrEmpty()] @@ -967,6 +1111,16 @@ function Restore-PSPackage function Restore-PSModuleToBuild { + <# + .SYNOPSIS + Copies PowerShell Gallery modules from the NuGet cache into the build output Modules folder. + .DESCRIPTION + Resolves Gallery module packages referenced in PSGalleryModules.csproj and copies + them to the Modules subdirectory of the specified publish path. Also removes + .nupkg.metadata files left behind by the restore. + .PARAMETER PublishPath + The PowerShell build output directory whose Modules sub-folder receives the modules. + #> param( [Parameter(Mandatory)] [string] @@ -983,6 +1137,14 @@ function Restore-PSModuleToBuild function Restore-PSPester { + <# + .SYNOPSIS + Downloads and saves the Pester module (v4.x) from the PowerShell Gallery. + .DESCRIPTION + Uses Save-Module to install Pester up to version 4.99 into the target directory. + .PARAMETER Destination + Directory to save Pester into. Defaults to the Modules folder of the current build output. + #> param( [ValidateNotNullOrEmpty()] [string] $Destination = ([IO.Path]::Combine((Split-Path (Get-PSOptions -DefaultToNew).Output), "Modules")) @@ -991,6 +1153,15 @@ function Restore-PSPester } function Compress-TestContent { + <# + .SYNOPSIS + Compresses the test directory into a zip archive for distribution. + .DESCRIPTION + Publishes PSTestTools and then zips the entire test/ directory to the given + destination path using System.IO.Compression.ZipFile. + .PARAMETER Destination + The path of the output zip file to create. + #> [CmdletBinding()] param( $Destination @@ -1005,6 +1176,30 @@ function Compress-TestContent { } function New-PSOptions { + <# + .SYNOPSIS + Creates a new PSOptions hashtable describing a PowerShell build configuration. + .DESCRIPTION + Computes the output path, project directory, and framework for a PowerShell build + based on the supplied runtime and configuration. The resulting hashtable is consumed + by Start-PSBuild, Restore-PSPackage, and related functions. + .PARAMETER Configuration + The build configuration: Debug (default), Release, CodeCoverage, or StaticAnalysis. + .PARAMETER Framework + The target .NET framework moniker. Defaults to 'net11.0'. + .PARAMETER Runtime + The .NET runtime identifier (RID). Detected automatically via 'dotnet --info' if omitted. + .PARAMETER Output + Optional path to the output directory. The executable name is appended automatically. + .PARAMETER SMAOnly + Targets only the System.Management.Automation project rather than the full host. + .PARAMETER PSModuleRestore + Indicates whether Start-PSBuild should restore PowerShell Gallery modules. + .PARAMETER ForMinimalSize + Produces a build targeting minimal binary size. + .OUTPUTS + System.Collections.Hashtable. A hashtable with build option properties. + #> [CmdletBinding()] param( [ValidateSet('Debug', 'Release', 'CodeCoverage', 'StaticAnalysis', '')] @@ -1152,6 +1347,17 @@ function New-PSOptions { # Get the Options of the last build function Get-PSOptions { + <# + .SYNOPSIS + Returns the PSOptions from the most recent Start-PSBuild call. + .DESCRIPTION + Retrieves the script-level $script:Options object. If no build has been run and + -DefaultToNew is specified, returns a fresh object from New-PSOptions. + .PARAMETER DefaultToNew + When specified, returns default options from New-PSOptions if no build has occurred. + .OUTPUTS + System.Collections.Hashtable. The current PSOptions hashtable, or $null. + #> param( [Parameter(HelpMessage='Defaults to New-PSOption if a build has not occurred.')] [switch] @@ -1167,6 +1373,15 @@ function Get-PSOptions { } function Set-PSOptions { + <# + .SYNOPSIS + Stores the supplied PSOptions as the active build options. + .DESCRIPTION + Writes the options hashtable to the script-scoped $script:Options variable, + making it available to subsequent Get-PSOptions calls. + .PARAMETER Options + The PSOptions hashtable to store. + #> param( [PSObject] $Options @@ -1176,6 +1391,17 @@ function Set-PSOptions { } function Get-PSOutput { + <# + .SYNOPSIS + Returns the path to the PowerShell executable produced by the build. + .DESCRIPTION + Looks up the Output path from the supplied options hashtable, the cached + script-level options, or a fresh New-PSOptions call, in that order of precedence. + .PARAMETER Options + An explicit options hashtable. If omitted, the most recent build options are used. + .OUTPUTS + System.String. The full path to the built pwsh or pwsh.exe executable. + #> [CmdletBinding()]param( [hashtable]$Options ) @@ -1189,6 +1415,21 @@ function Get-PSOutput { } function Get-PesterTag { + <# + .SYNOPSIS + Scans the Pester test tree and returns a summary of all tags in use. + .DESCRIPTION + Parses every *.tests.ps1 file under the specified base directory using the + PowerShell AST, validates that each Describe block has exactly one priority tag + (CI, Feature, or Scenario), and returns a summary object with tag counts and + any validation warnings. + .PARAMETER testbase + Root directory to search for test files. + Defaults to '$PSScriptRoot/test/powershell'. + .OUTPUTS + PSCustomObject (DescribeTagsInUse). Properties are tag names mapped to usage + counts, plus 'Result' (Pass/Fail) and 'Warnings' (string[]). + #> param ( [Parameter(Position=0)][string]$testbase = "$PSScriptRoot/test/powershell" ) $alltags = @{} $warnings = @() @@ -1255,6 +1496,13 @@ function Get-PesterTag { # testing PowerShell remote custom connections. function Publish-CustomConnectionTestModule { + <# + .SYNOPSIS + Builds and publishes the Microsoft.PowerShell.NamedPipeConnection test module. + .DESCRIPTION + Invokes the module's own build.ps1 script, copies the output to + test/tools/Modules, and then runs a clean build to remove intermediate artifacts. + #> Write-LogGroupStart -Title "Publish-CustomConnectionTestModule" $sourcePath = "${PSScriptRoot}/test/tools/NamedPipeConnection" $outPath = "${PSScriptRoot}/test/tools/NamedPipeConnection/out/Microsoft.PowerShell.NamedPipeConnection" @@ -1285,6 +1533,18 @@ function Publish-CustomConnectionTestModule } function Publish-PSTestTools { + <# + .SYNOPSIS + Builds and publishes all test tool projects to their bin directories. + .DESCRIPTION + Runs 'dotnet publish' for each test tool project (TestAlc, TestExe, UnixSocket, + WebListener, and on Windows TestService), copies Gallery test modules, and + publishes the NamedPipeConnection module. The tool bin directories are added to PATH + so that tests can locate the executables. + .PARAMETER runtime + The .NET runtime identifier (RID) used when publishing executables. + Defaults to the runtime from the current build options. + #> [CmdletBinding()] param( [string] @@ -1367,6 +1627,16 @@ function Publish-PSTestTools { } function Get-ExperimentalFeatureTests { + <# + .SYNOPSIS + Returns a mapping of experimental feature names to their associated test files. + .DESCRIPTION + Reads test/tools/TestMetadata.json and extracts the ExperimentalFeatures section, + returning a hashtable where keys are feature names and values are arrays of test paths. + .OUTPUTS + System.Collections.Hashtable. Keys are experimental feature names; values are + arrays of test file paths. + #> $testMetadataFile = Join-Path $PSScriptRoot "test/tools/TestMetadata.json" $metadata = Get-Content -Path $testMetadataFile -Raw | ConvertFrom-Json | ForEach-Object -MemberName ExperimentalFeatures $features = $metadata | Get-Member -MemberType NoteProperty | ForEach-Object -MemberName Name @@ -1379,6 +1649,57 @@ function Get-ExperimentalFeatureTests { } function Start-PSPester { + <# + .SYNOPSIS + Runs the Pester test suite against the built PowerShell. + .DESCRIPTION + Launches the built pwsh process with the Pester module and runs the specified + test paths. Automatically adjusts tag exclusions based on the current elevation + level, and emits NUnit XML results that are optionally published to Azure DevOps + or GitHub Actions. + .PARAMETER Path + One or more test file or directory paths to run. Defaults to test/powershell. + .PARAMETER OutputFormat + The Pester output format. Defaults to 'NUnitXml'. + .PARAMETER OutputFile + Path for the XML results file. Defaults to 'pester-tests.xml'. + .PARAMETER ExcludeTag + Tags to exclude from the run. Defaults to 'Slow'; adjusted for elevation level. + .PARAMETER Tag + Tags to include in the run. Defaults to 'CI' and 'Feature'. + .PARAMETER ThrowOnFailure + Throws an exception after the run if any tests failed. + .PARAMETER BinDir + Directory containing the built pwsh executable. Defaults to the current build output. + .PARAMETER powershell + Full path to the pwsh executable used for running tests. + .PARAMETER Pester + Path to the Pester module directory. + .PARAMETER Unelevate + Runs tests in an unelevated child process on Windows. + .PARAMETER Quiet + Suppresses most Pester output. + .PARAMETER Terse + Shows compact pass/fail indicators instead of full output lines. + .PARAMETER PassThru + Returns the Pester result object to the caller. + .PARAMETER Sudo + Runs tests under sudo on Unix (PassThru parameter set). + .PARAMETER IncludeFailingTest + Includes tests from tools/failingTests. + .PARAMETER IncludeCommonTests + Includes tests from test/common. + .PARAMETER ExperimentalFeatureName + Enables the named experimental feature for this test run via a temporary config file. + .PARAMETER Title + Title for the published test results. Defaults to 'PowerShell 7 Tests'. + .PARAMETER Wait + Waits for a debugger to attach before starting Pester (Debug builds only). + .PARAMETER SkipTestToolBuild + Skips rebuilding test tool executables before running tests. + .PARAMETER UseNuGetOrg + Switches NuGet config to public feeds before running tests. + #> [CmdletBinding(DefaultParameterSetName='default')] param( [Parameter(Position=0)] @@ -1428,7 +1749,7 @@ function Start-PSPester { if($IncludeCommonTests.IsPresent) { - $path = += "$PSScriptRoot/test/common" + $path += "$PSScriptRoot/test/common" } # we need to do few checks and if user didn't provide $ExcludeTag explicitly, we should alternate the default @@ -1744,6 +2065,20 @@ function Start-PSPester { function Publish-TestResults { + <# + .SYNOPSIS + Publishes test result files to Azure DevOps or GitHub Actions. + .DESCRIPTION + In an Azure DevOps build (TF_BUILD), uploads the result file via a ##vso command + and attaches it as a build artifact. In GitHub Actions, copies the file to the + testResults directory under $env:RUNNER_WORKSPACE. Does nothing outside of CI environments. + .PARAMETER Title + The run title shown in the CI testing tab. + .PARAMETER Path + Path to the NUnit or XUnit result file to publish. + .PARAMETER Type + The result file format: 'NUnit' (default) or 'XUnit'. + #> param( [Parameter(Mandatory)] [string] @@ -1804,6 +2139,17 @@ function Publish-TestResults function script:Start-UnelevatedProcess { + <# + .SYNOPSIS + Starts a process at an unelevated trust level on Windows. + .DESCRIPTION + Uses runas.exe /trustlevel:0x20000 to launch a process without elevation. + Only supported on Windows and non-arm64 architectures. + .PARAMETER process + The path to the executable to start. + .PARAMETER arguments + Arguments to pass to the executable. + #> param( [string]$process, [string[]]$arguments @@ -1814,7 +2160,7 @@ function script:Start-UnelevatedProcess throw "Start-UnelevatedProcess is currently not supported on non-Windows platforms" } - if (-not $environment.OSArchitecture -eq 'arm64') + if ($environment.OSArchitecture -eq 'arm64') { throw "Start-UnelevatedProcess is currently not supported on arm64 platforms" } @@ -1824,6 +2170,18 @@ function script:Start-UnelevatedProcess function Show-PSPesterError { + <# + .SYNOPSIS + Outputs a formatted error block for a single Pester test failure. + .DESCRIPTION + Accepts either an XmlElement from a NUnit result file or a PSCustomObject from + a Pester PassThru result, and writes a structured description/name/message/stack-trace + block to the log output. + .PARAMETER testFailure + An XML test-case element from a Pester NUnit result file (xml parameter set). + .PARAMETER testFailureObject + A Pester test-result PSCustomObject from a PassThru run (object parameter set). + #> [CmdletBinding(DefaultParameterSetName='xml')] param ( [Parameter(ParameterSetName='xml',Mandatory)] @@ -1866,6 +2224,18 @@ $stack_trace function Get-PesterFailureFileInfo { + <# + .SYNOPSIS + Parses a Pester stack-trace string and returns the source file path and line number. + .DESCRIPTION + Tries several common stack-trace formats produced by Pester 4 and Pester 5 (on + both Windows and Unix) and returns a hashtable with File and Line keys. + Returns $null values for both keys when no pattern matches. + .PARAMETER StackTraceString + The raw stack trace text from a Pester test failure. + .OUTPUTS + System.Collections.Hashtable. A hashtable with 'File' (string) and 'Line' (string). + #> [CmdletBinding()] param ( [Parameter(Mandatory)] @@ -1879,23 +2249,23 @@ function Get-PesterFailureFileInfo # "at , C:\path\to\file.ps1: line 123" # "at 1 | Should -Be 2, /path/to/file.ps1:123" (Pester 5) # "at 1 | Should -Be 2, C:\path\to\file.ps1:123" (Pester 5 Windows) - + $result = @{ File = $null Line = $null } - + if ([string]::IsNullOrWhiteSpace($StackTraceString)) { return $result } - + # Try pattern: "at line: 123 in " (Pester 4) if ($StackTraceString -match 'at line:\s*(\d+)\s+in\s+(.+?)(?:\r|\n|$)') { $result.Line = $matches[1] $result.File = $matches[2].Trim() return $result } - + # Try pattern: ", :123" (Pester 5 format) # This handles both Unix paths (/path/file.ps1:123) and Windows paths (C:\path\file.ps1:123) if ($StackTraceString -match ',\s*((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1):(\d+)') { @@ -1903,7 +2273,7 @@ function Get-PesterFailureFileInfo $result.Line = $matches[2] return $result } - + # Try pattern: "at :123" (without comma) # Handle both absolute Unix and Windows paths if ($StackTraceString -match 'at\s+((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):(\d+)(?:\r|\n|$)') { @@ -1911,24 +2281,33 @@ function Get-PesterFailureFileInfo $result.Line = $matches[2] return $result } - + # Try pattern: ": line 123" if ($StackTraceString -match '((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):\s*line\s+(\d+)(?:\r|\n|$)') { $result.File = $matches[1].Trim() $result.Line = $matches[2] return $result } - + # Try to extract just the file path if no line number found if ($StackTraceString -match '(?:at\s+|in\s+)?((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1)') { $result.File = $matches[1].Trim() } - + return $result } function Test-XUnitTestResults { + <# + .SYNOPSIS + Validates an xUnit XML result file and throws if any tests failed. + .DESCRIPTION + Parses the specified xUnit result file, logs description, name, message, and + stack trace for each failed test, then throws an exception summarizing the count. + .PARAMETER TestResultsFile + Path to the xUnit XML result file to validate. + #> param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] @@ -1984,6 +2363,23 @@ function Test-XUnitTestResults # Throw if a test failed function Test-PSPesterResults { + <# + .SYNOPSIS + Validates Pester test results and throws if any tests failed. + .DESCRIPTION + In file mode, reads a NUnit XML result file and logs each failure before throwing. + In object mode, inspects a Pester PassThru result object. Optionally permits + empty result sets. + .PARAMETER TestResultsFile + Path to the NUnit XML result file. Defaults to 'pester-tests.xml'. + .PARAMETER TestArea + Label for the test area, used in error messages. Defaults to 'test/powershell'. + .PARAMETER ResultObject + A Pester PassThru result object to inspect instead of parsing a file. + .PARAMETER CanHaveNoResult + When specified with ResultObject, suppresses the 'NO TESTS RUN' exception for + zero-count results. + #> [CmdletBinding(DefaultParameterSetName='file')] param( [Parameter(ParameterSetName='file')] @@ -2059,6 +2455,20 @@ function Test-PSPesterResults } function Start-PSxUnit { + <# + .SYNOPSIS + Runs the xUnit tests for the PowerShell engine. + .DESCRIPTION + Executes 'dotnet test' in the test/xUnit directory against the built PowerShell + binaries. On Unix, copies native libraries and required dependencies into the test + output directory. Publishes results to CI when not in debug-logging mode. + .PARAMETER xUnitTestResultsFile + Path for the xUnit XML result file. Defaults to 'xUnitResults.xml'. + .PARAMETER DebugLogging + Enables detailed console test output instead of writing an XML result file. + .PARAMETER Filter + An xUnit filter expression to restrict which tests are run. + #> [CmdletBinding()]param( [string] $xUnitTestResultsFile = "xUnitResults.xml", [switch] $DebugLogging, @@ -2150,6 +2560,29 @@ function Start-PSxUnit { } function Install-Dotnet { + <# + .SYNOPSIS + Installs the .NET SDK using the official install script. + .DESCRIPTION + Downloads and runs dotnet-install.sh (Linux/macOS) or dotnet-install.ps1 (Windows) + to install the specified SDK version into the user-local dotnet installation directory. + .PARAMETER Channel + The release channel to install from when no explicit version is given. + .PARAMETER Version + The exact SDK version to install. Defaults to the version required by this repository. + .PARAMETER Quality + The quality level (e.g. 'GA', 'preview') used when installing by channel. + .PARAMETER RemovePreviousVersion + Attempts to uninstall previously installed dotnet packages before installing. + .PARAMETER NoSudo + Omits sudo from install commands, useful inside containers running as root. + .PARAMETER InstallDir + Custom installation directory for the .NET SDK. + .PARAMETER AzureFeed + Override URL for the Azure CDN feed used to download the SDK. + .PARAMETER FeedCredential + Credential token for accessing a private Azure feed. + #> [CmdletBinding()] param( [string]$Channel = $dotnetCLIChannel, @@ -2301,6 +2734,15 @@ function Install-Dotnet { } function Get-RedHatPackageManager { + <# + .SYNOPSIS + Returns the install command prefix for the available Red Hat-family package manager. + .DESCRIPTION + Detects whether yum, dnf, or tdnf is installed and returns the corresponding + install command string for use in bootstrapping scripts. + .OUTPUTS + System.String. A package-manager install command such as 'dnf install -y -q'. + #> if ($environment.IsCentOS -or (Get-Command -Name yum -CommandType Application -ErrorAction SilentlyContinue)) { "yum install -y -q" } elseif ($environment.IsFedora -or (Get-Command -Name dnf -CommandType Application -ErrorAction SilentlyContinue)) { @@ -2313,6 +2755,27 @@ function Get-RedHatPackageManager { } function Start-PSBootstrap { + <# + .SYNOPSIS + Installs build dependencies for PowerShell. + .DESCRIPTION + Depending on the selected scenario, installs native OS packages, the required + .NET SDK, Windows packaging tools (WiX), and/or .NET global tools (dotnet-format). + Supports Linux, macOS, and Windows. + .PARAMETER Channel + The .NET SDK release channel to use when installing by channel. + .PARAMETER Version + The exact .NET SDK version to install. Defaults to the required version. + .PARAMETER NoSudo + Omits sudo from native-package install commands, useful inside containers. + .PARAMETER BuildLinuxArm + Installs Linux ARM cross-compilation dependencies (Ubuntu/AzureLinux only). + .PARAMETER Force + Forces .NET SDK reinstallation even if the correct version is already present. + .PARAMETER Scenario + What to install: 'Package' (packaging tools), 'DotNet' (.NET SDK), + 'Both' (Package + DotNet), 'Tools' (.NET global tools), or 'All' (everything). + #> [CmdletBinding()] param( [string]$Channel = $dotnetCLIChannel, @@ -2580,6 +3043,17 @@ function Start-PSBootstrap { ## If the required SDK version is found, return it. ## Otherwise, return the latest installed SDK version that can be found. function Find-RequiredSDK { + <# + .SYNOPSIS + Returns the installed .NET SDK version that best satisfies the required version. + .DESCRIPTION + Lists installed SDKs with 'dotnet --list-sdks'. Returns the required version + string if it is installed; otherwise returns the newest installed SDK version. + .PARAMETER requiredSdkVersion + The exact .NET SDK version string to search for. + .OUTPUTS + System.String. The matched or newest installed SDK version string. + #> param( [Parameter(Mandatory, Position = 0)] [string] $requiredSdkVersion @@ -2604,6 +3078,28 @@ function Find-RequiredSDK { } function Start-DevPowerShell { + <# + .SYNOPSIS + Launches a PowerShell session using the locally built pwsh. + .DESCRIPTION + Starts a new pwsh process from the build output directory, optionally setting + the DEVPATH environment variable, redirecting PSModulePath to the built Modules + directory, and loading or suppressing the user profile. + .PARAMETER ArgumentList + Additional arguments passed to the pwsh process. + .PARAMETER LoadProfile + When specified, the user profile is loaded (by default -noprofile is prepended). + .PARAMETER Configuration + Build configuration whose output directory to use (ConfigurationParamSet). + .PARAMETER BinDir + Explicit path to the directory containing the pwsh binary (BinDirParamSet). + .PARAMETER NoNewWindow + Runs pwsh in the current console window instead of a new one. + .PARAMETER Command + A command string passed to pwsh via -command. + .PARAMETER KeepPSModulePath + Preserves the existing PSModulePath instead of redirecting it to the build output. + #> [CmdletBinding(DefaultParameterSetName='ConfigurationParamSet')] param( [string[]]$ArgumentList = @(), @@ -2671,6 +3167,16 @@ function Start-DevPowerShell { function Start-TypeGen { + <# + .SYNOPSIS + Generates the CorePsTypeCatalog type-catalog file. + .DESCRIPTION + Invokes the TypeCatalogGen .NET tool to produce CorePsTypeCatalog.cs, which maps + .NET types to their containing assemblies. The output .inc file name varies by + runtime to allow simultaneous builds on Windows and WSL. + .PARAMETER IncFileName + Name of the .inc file listing dependent assemblies. Defaults to 'powershell.inc'. + #> [CmdletBinding()] param ( @@ -2699,6 +3205,13 @@ function Start-TypeGen function Start-ResGen { + <# + .SYNOPSIS + Regenerates C# resource bindings from resx files. + .DESCRIPTION + Runs the ResGen .NET tool in src/ResGen to produce strongly-typed resource classes + for all resx files in the PowerShell project. + #> [CmdletBinding()] param() @@ -2771,6 +3284,17 @@ function Set-PSEnvironmentVariable { } function Find-Dotnet { + <# + .SYNOPSIS + Ensures the required .NET SDK is available on PATH. + .DESCRIPTION + Checks whether the dotnet currently on PATH can locate the required SDK version. + If not, prepends the user-local dotnet installation directory to PATH. + Optionally sets DOTNET_ROOT and adds the global tools directory to PATH. + .PARAMETER SetDotnetRoot + When specified, sets the DOTNET_ROOT environment variable and adds the + .NET global tools path to PATH. + #> param ( [switch] $SetDotnetRoot ) @@ -2867,6 +3391,14 @@ function Convert-TxtResourceToXml } function script:Use-MSBuild { + <# + .SYNOPSIS + Ensures that the msbuild command is available in the current scope. + .DESCRIPTION + If msbuild is not found in PATH, creates a script-scoped alias pointing to the + .NET Framework 4 MSBuild at its standard Windows location. Throws if neither + location provides a usable msbuild. + #> # TODO: we probably should require a particular version of msbuild, if we are taking this dependency # msbuild v14 and msbuild v4 behaviors are different for XAML generation $frameworkMsBuildLocation = "${env:SystemRoot}\Microsoft.Net\Framework\v4.0.30319\msbuild" @@ -2886,6 +3418,18 @@ function script:Use-MSBuild { function script:Write-Log { + <# + .SYNOPSIS + Writes a colored message to the host, with optional error annotation. + .DESCRIPTION + In GitHub Actions, error messages are emitted as workflow error annotations + using the '::error::' command. Normal messages are written in green; errors + in red. Console colors are reset after each call. + .PARAMETER message + The text to write. + .PARAMETER isError + When specified, writes the message as an error (red / GitHub Actions annotation). + #> param ( [Parameter(Position=0, Mandatory)] @@ -2913,6 +3457,18 @@ function script:Write-Log } function script:Write-LogGroup { + <# + .SYNOPSIS + Emits a titled group of log messages wrapped in log-group markers. + .DESCRIPTION + Calls Write-LogGroupStart, writes each message line via Write-Log, then calls + Write-LogGroupEnd. In GitHub Actions this creates a collapsible group; on other + hosts it adds BEGIN/END banners. + .PARAMETER Message + One or more message lines to write inside the group. + .PARAMETER Title + The title displayed for the log group. + #> param ( [Parameter(Position = 0, Mandatory)] @@ -2935,6 +3491,15 @@ function script:Write-LogGroup { $script:logGroupColor = [System.ConsoleColor]::Cyan function script:Write-LogGroupStart { + <# + .SYNOPSIS + Opens a collapsible log group section. + .DESCRIPTION + In GitHub Actions emits '::group::'. On other hosts writes a colored + begin banner using the script-level log group color. + .PARAMETER Title + The label for the group. + #> param ( [Parameter(Mandatory)] @@ -2950,6 +3515,15 @@ function script:Write-LogGroupStart { } function script:Write-LogGroupEnd { + <# + .SYNOPSIS + Closes a collapsible log group section. + .DESCRIPTION + In GitHub Actions emits '::endgroup::'. On other hosts writes a colored + end banner using the script-level log group color. + .PARAMETER Title + The group label (used only in non-GitHub-Actions output). + #> param ( [Parameter(Mandatory)] @@ -2965,6 +3539,20 @@ function script:Write-LogGroupEnd { } function script:precheck([string]$command, [string]$missedMessage) { + <# + .SYNOPSIS + Tests whether a command exists on PATH and optionally emits a warning if missing. + .DESCRIPTION + Uses Get-Command to locate the specified command. Returns $true if found, + $false otherwise. If the command is absent and a message is provided, + Write-Warning is called with that message. + .PARAMETER command + The command name to look for. + .PARAMETER missedMessage + Warning text to emit when the command is not found. Pass $null to suppress it. + .OUTPUTS + System.Boolean. $true when the command is found; $false otherwise. + #> $c = Get-Command $command -ErrorAction Ignore if (-not $c) { if (-not [string]::IsNullOrEmpty($missedMessage)) @@ -2980,6 +3568,13 @@ function script:precheck([string]$command, [string]$missedMessage) { # Cleans the PowerShell repo - everything but the root folder function Clear-PSRepo { + <# + .SYNOPSIS + Cleans all subdirectories of the PowerShell repository using 'git clean -fdX'. + .DESCRIPTION + Iterates over every top-level directory under the repository root and removes all + files that are not tracked by git, including ignored files. + #> [CmdletBinding()] param() @@ -2992,6 +3587,20 @@ function Clear-PSRepo # Install PowerShell modules such as PackageManagement, PowerShellGet function Copy-PSGalleryModules { + <# + .SYNOPSIS + Copies PowerShell Gallery modules from the NuGet cache to a Modules directory. + .DESCRIPTION + Reads the PackageReference items in the specified csproj file, resolves each + package from the NuGet global cache, and copies it to the destination directory. + Package nupkg and metadata files are excluded from the copy. + .PARAMETER CsProjPath + Path to the csproj file whose PackageReference items describe Gallery modules. + .PARAMETER Destination + Destination Modules directory. Must end with 'Modules'. + .PARAMETER Force + Forces NuGet package restore even if packages are already present. + #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] @@ -3051,6 +3660,22 @@ function Copy-PSGalleryModules function Merge-TestLogs { + <# + .SYNOPSIS + Merges xUnit and NUnit test log files into a single xUnit XML file. + .DESCRIPTION + Converts NUnit Pester logs to xUnit assembly format and appends them, along with + any additional xUnit logs, to the primary xUnit log. The merged result is saved + to the specified output path. + .PARAMETER XUnitLogPath + Path to the primary xUnit XML log file. + .PARAMETER NUnitLogPath + One or more NUnit (Pester) XML log file paths to merge in. + .PARAMETER AdditionalXUnitLogPath + Optional additional xUnit XML log files to append. + .PARAMETER OutputLogPath + Path for the merged xUnit output file. + #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] @@ -3092,6 +3717,23 @@ function Merge-TestLogs } function ConvertFrom-PesterLog { + <# + .SYNOPSIS + Converts Pester NUnit XML log files to xUnit assembly format. + .DESCRIPTION + Accepts one or more NUnit log files produced by Pester, or existing xUnit logs, + and converts them to an in-memory xUnit assembly object model. If multiple logs + are provided and -MultipleLog is not set, they are combined into a single + assemblies object. + .PARAMETER Logfile + Path(s) to the NUnit or xUnit log file(s) to convert. Accepts pipeline input. + .PARAMETER IncludeEmpty + When specified, includes test assemblies that contain zero test cases. + .PARAMETER MultipleLog + When specified, returns one assemblies object per log file instead of combining. + .OUTPUTS + assemblies. One or more xUnit assemblies objects containing converted test data. + #> [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true, Mandatory = $true, Position = 0)] @@ -3099,21 +3741,6 @@ function ConvertFrom-PesterLog { [Parameter()][switch]$IncludeEmpty, [Parameter()][switch]$MultipleLog ) - <# -Convert our test logs to -xunit schema - top level assemblies -Pester conversion -foreach $r in "test-results"."test-suite".results."test-suite" -assembly - name = $r.Description - config-file = log file (this is the only way we can determine between admin/nonadmin log) - test-framework = Pester - environment = top-level "test-results.environment.platform - run-date = date (doesn't exist in pester except for beginning) - run-time = time - time = -#> - BEGIN { # CLASSES class assemblies { @@ -3460,6 +4087,17 @@ assembly # Save PSOptions to be restored by Restore-PSOptions function Save-PSOptions { + <# + .SYNOPSIS + Persists the current PSOptions to a JSON file. + .DESCRIPTION + Serializes the current build options (or the supplied Options object) to JSON + and writes them to the specified path. Defaults to psoptions.json in the repo root. + .PARAMETER PSOptionsPath + Path to the JSON file to write. Defaults to '$PSScriptRoot/psoptions.json'. + .PARAMETER Options + PSOptions object to save. Defaults to the current build options. + #> param( [ValidateScript({$parent = Split-Path $_;if($parent){Test-Path $parent}else{return $true}})] [ValidateNotNullOrEmpty()] @@ -3477,6 +4115,17 @@ function Save-PSOptions { # Restore PSOptions # Optionally remove the PSOptions file function Restore-PSOptions { + <# + .SYNOPSIS + Loads saved PSOptions from a JSON file and makes them the active build options. + .DESCRIPTION + Reads the JSON file produced by Save-PSOptions, reconstructs a PSOptions + hashtable, and stores it via Set-PSOptions. Optionally deletes the file afterward. + .PARAMETER PSOptionsPath + Path to the JSON file to read. Defaults to '$PSScriptRoot/psoptions.json'. + .PARAMETER Remove + When specified, deletes the JSON file after loading. + #> param( [ValidateScript({Test-Path $_})] [string] @@ -3509,6 +4158,31 @@ function Restore-PSOptions { function New-PSOptionsObject { + <# + .SYNOPSIS + Constructs the PSOptions hashtable from individual build-option components. + .DESCRIPTION + Assembles the hashtable consumed by Start-PSBuild, Restore-PSPackage, and related + commands. Prefer New-PSOptions, which auto-computes fields such as the output path. + .PARAMETER RootInfo + PSCustomObject with repo root path validation metadata. + .PARAMETER Top + Path to the top-level project directory (pwsh source directory). + .PARAMETER Runtime + The .NET runtime identifier (RID) for the build. + .PARAMETER Configuration + The build configuration: Debug, Release, CodeCoverage, or StaticAnalysis. + .PARAMETER PSModuleRestore + Whether Gallery modules should be restored to the build output. + .PARAMETER Framework + The target .NET framework moniker, e.g. 'net11.0'. + .PARAMETER Output + Full path to the output pwsh executable. + .PARAMETER ForMinimalSize + Whether this is a minimal-size build. + .OUTPUTS + System.Collections.Hashtable. A PSOptions hashtable. + #> param( [PSCustomObject] $RootInfo, @@ -3679,6 +4353,17 @@ $script:RESX_TEMPLATE = @' '@ function Get-UniquePackageFolderName { + <# + .SYNOPSIS + Returns a unique temporary folder path for a test package under the specified root. + .DESCRIPTION + Tries the path '<Root>/TestPackage' first, then appends a random numeric suffix + until an unused path is found. Throws if a unique name cannot be found in 10 tries. + .PARAMETER Root + The parent directory under which the unique folder name is generated. + .OUTPUTS + System.String. A path under Root that does not yet exist. + #> param( [Parameter(Mandatory)] $Root ) @@ -3705,6 +4390,18 @@ function Get-UniquePackageFolderName { function New-TestPackage { + <# + .SYNOPSIS + Creates a zip archive containing all test content and test tools. + .DESCRIPTION + Builds and publishes test tools, copies the test directory, assets directory, + and resx resource directories into a temporary staging folder, then zips the + staging folder to TestPackage.zip in the specified destination directory. + .PARAMETER Destination + Directory where the TestPackage.zip file is created. + .PARAMETER Runtime + The .NET runtime identifier (RID) used when publishing test tool executables. + #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] @@ -3781,6 +4478,16 @@ class NugetPackageSource { } function New-NugetPackageSource { + <# + .SYNOPSIS + Creates a NugetPackageSource object with the given URL and name. + .PARAMETER Url + The NuGet feed URL. + .PARAMETER Name + The feed name used as the key in nuget.config. + .OUTPUTS + NugetPackageSource. An object with Url and Name properties. + #> param( [Parameter(Mandatory = $true)] [string]$Url, [Parameter(Mandatory = $true)] [string] $Name @@ -3791,6 +4498,22 @@ function New-NugetPackageSource { $script:NuGetEndpointCredentials = [System.Collections.Generic.Dictionary[String,System.Object]]::new() function New-NugetConfigFile { + <# + .SYNOPSIS + Generates a nuget.config file at the specified destination. + .DESCRIPTION + Creates a nuget.config XML file with the supplied package sources and optional + credentials. The generated file is marked as skip-worktree in git to prevent + accidental commits of feed credentials. + .PARAMETER NugetPackageSource + One or more NugetPackageSource objects defining the feeds to include. + .PARAMETER Destination + Directory where nuget.config is written. + .PARAMETER UserName + Username for authenticated feed access. + .PARAMETER ClearTextPAT + Personal access token in clear text for authenticated feed access. + #> param( [Parameter(Mandatory = $true, ParameterSetName ='user')] [Parameter(Mandatory = $true, ParameterSetName ='nouser')] @@ -3872,10 +4595,24 @@ function New-NugetConfigFile { } function Clear-PipelineNugetAuthentication { + <# + .SYNOPSIS + Clears cached NuGet feed credentials used by the pipeline. + .DESCRIPTION + Removes all entries from the script-scoped NuGetEndpointCredentials dictionary. + #> $script:NuGetEndpointCredentials.Clear() } function Set-PipelineNugetAuthentication { + <# + .SYNOPSIS + Publishes cached NuGet feed credentials to the Azure DevOps pipeline. + .DESCRIPTION + Serializes the script-scoped NuGetEndpointCredentials dictionary to JSON and sets + the VSS_NUGET_EXTERNAL_FEED_ENDPOINTS pipeline variable so that subsequent NuGet + operations authenticate automatically. + #> $endpointcredentials = @() foreach ($key in $script:NuGetEndpointCredentials.Keys) { @@ -3890,6 +4627,14 @@ function Set-PipelineNugetAuthentication { function Set-CorrectLocale { + <# + .SYNOPSIS + Configures the Linux locale to en_US.UTF-8 for consistent build behavior. + .DESCRIPTION + On Ubuntu 20+ systems, generates the en_US.UTF-8 locale and sets LC_ALL and LANG + environment variables. Skips execution on non-Linux platforms and Ubuntu versions + earlier than 20. + #> Write-LogGroupStart -Title "Set-CorrectLocale" if (-not $IsLinux) @@ -3926,6 +4671,13 @@ function Set-CorrectLocale } function Write-Locale { + <# + .SYNOPSIS + Writes the current system locale settings to the log output. + .DESCRIPTION + Runs the 'locale' command on Linux or macOS and writes the output inside a + collapsible log group. Does nothing on Windows. + #> if (-not $IsLinux -and -not $IsMacOS) { Write-Verbose -Message "only supported on Linux and macOS" -Verbose return @@ -3937,6 +4689,13 @@ function Write-Locale { } function Install-AzCopy { + <# + .SYNOPSIS + Downloads and installs AzCopy v10 on Windows. + .DESCRIPTION + Downloads the AzCopy v10 zip archive from the official Microsoft URL and extracts + it to the Agent tools directory. Skips installation if AzCopy is already present. + #> $testPath = "C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy\AzCopy.exe" if (Test-Path $testPath) { Write-Verbose "AzCopy already installed" -Verbose @@ -3951,6 +4710,15 @@ function Install-AzCopy { } function Find-AzCopy { + <# + .SYNOPSIS + Locates the AzCopy executable on the system. + .DESCRIPTION + Searches several well-known installation paths for AzCopy.exe and falls back to + Get-Command if none of the paths contain the executable. + .OUTPUTS + System.String. The full path to the AzCopy executable. + #> $searchPaths = @('$(Agent.ToolsDirectory)\azcopy10\AzCopy.exe', "C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy\AzCopy.exe", "C:\azcopy10\AzCopy.exe") foreach ($filter in $searchPaths) { @@ -3966,6 +4734,16 @@ function Find-AzCopy { function Clear-NativeDependencies { + <# + .SYNOPSIS + Removes unnecessary native dependency files from the publish output. + .DESCRIPTION + Strips architecture-specific DiaSym reader DLLs that are not needed for the + target runtime from both the publish folder and the pwsh.deps.json manifest. + Skips fxdependent runtimes where no cleanup is needed. + .PARAMETER PublishFolder + Path to the publish output directory containing pwsh.deps.json. + #> param( [Parameter(Mandatory=$true)] [string] $PublishFolder ) @@ -4032,6 +4810,14 @@ function Clear-NativeDependencies function Update-DotNetSdkVersion { +<# + .SYNOPSIS + Updates the .NET SDK version in global.json and DotnetRuntimeMetadata.json. + .DESCRIPTION + Queries the official .NET SDK feed for the latest version in the current channel + and writes the new version to global.json and DotnetRuntimeMetadata.json. + #> + param() $globalJsonPath = "$PSScriptRoot/global.json" $globalJson = get-content $globalJsonPath | convertfrom-json $oldVersion = $globalJson.sdk.version @@ -4051,6 +4837,17 @@ function Update-DotNetSdkVersion { } function Set-PipelineVariable { + <# + .SYNOPSIS + Sets an Azure DevOps pipeline variable and the corresponding environment variable. + .DESCRIPTION + Emits a ##vso[task.setvariable] logging command so that subsequent pipeline steps + can access the variable, and also sets it in the current process environment. + .PARAMETER Name + The pipeline variable name. + .PARAMETER Value + The value to assign. + #> param( [parameter(Mandatory)] [string] $Name, From c3999def93bdc7d383c533c501c4909fa92e44c2 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Thu, 9 Apr 2026 15:34:05 -0700 Subject: [PATCH 247/275] [release/v7.5.6] Build, package, and create VPack for the PowerShell-LTS store package within the same `msixbundle-vpack` pipeline (#27240) --- .pipelines/MSIXBundle-vPack-Official.yml | 513 +++++++++++++++--- PowerShell.Common.props | 2 +- .../host/msh/ConsoleHost.cs | 2 +- .../host/msh/ManagedEntrance.cs | 4 +- .../resources/ManagedEntranceStrings.resx | 2 +- .../resources/RemotingErrorIdStrings.resx | 2 +- .../utils/Telemetry.cs | 8 +- tools/packaging/packaging.psm1 | 4 +- 8 files changed, 448 insertions(+), 89 deletions(-) diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 876da9c2aff..08edd0367bd 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -1,31 +1,56 @@ trigger: none +pr: none parameters: # parameters are shown up in ADO UI in a build queue time - name: 'createVPack' displayName: 'Create and Submit VPack' type: boolean default: true +- name: 'ReleaseTagVar' + type: string + displayName: 'Release Tag Var:' + default: 'fromBranch' - name: 'debug' displayName: 'Enable debug output' type: boolean default: false -- name: 'ReleaseTagVar' +- name: netiso + displayName: "Network Isolation Policy" type: string - displayName: 'Release Tag Var:' - default: 'fromBranch' + values: + - KS4 + - R1 + - Netlock + default: "R1" -name: msixbundle_vPack_$(date:yyMM).$(date:dd)$(rev:rrr) +name: msixbundle_vPack_$(Build.SourceBranchName)_Prod.True_Create.${{ parameters.createVPack }}_$(date:yyyyMMdd).$(rev:rr) variables: - CDP_DEFINITION_BUILD_COUNT: $[counter('', 0)] - system.debug: ${{ parameters.debug }} - BuildSolution: $(Build.SourcesDirectory)\dirs.proj - ReleaseTagVar: ${{ parameters.ReleaseTagVar }} - BuildConfiguration: Release - WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - Codeql.Enabled: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack - DOTNET_CLI_TELEMETRY_OPTOUT: 1 - POWERSHELL_TELEMETRY_OPTOUT: 1 + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: BuildSolution + value: $(Build.SourcesDirectory)\dirs.proj + - name: BuildConfiguration + value: Release + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' + - name: Codeql.Enabled + value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack + - name: DOTNET_CLI_TELEMETRY_OPTOUT + value: 1 + - name: POWERSHELL_TELEMETRY_OPTOUT + value: 1 + - name: nugetMultiFeedWarnLevel + value: none + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - name: netiso + value: ${{ parameters.netiso }} + - group: certificate_logical_to_actual # used within signing task + - group: MSIXSigningProfile + - group: msixTools resources: repositories: @@ -34,27 +59,17 @@ resources: name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main - pipelines: - - pipeline: PSPackagesOfficial - source: 'PowerShell-Packages-Official' - trigger: - branches: - include: - - master - - releases/* - extends: template: v2/Microsoft.Official.yml@onebranchTemplates parameters: + platform: + name: 'windows_undocked' # windows undocked featureFlags: WindowsHostVersion: Version: 2022 - platform: - name: 'windows_undocked' # windows undocked - + Network: ${{ variables.netiso }} cloudvault: enabled: false - globalSdl: useCustomPolicy: true # for signing code disableLegacyManifest: true @@ -78,71 +93,417 @@ extends: tsaOptionsFile: .config/tsaoptions.json stages: - - stage: build + - stage: Build_MSIX_Package + displayName: 'Build and create MSIX packages' + dependsOn: [] jobs: - - job: main + - job: Build pool: type: windows + strategy: + matrix: + x64: + Architecture: x64 + arm64: + Architecture: arm64 + variables: + ArtifactPlatform: 'windows' ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_artifactBaseName: drop_build_$(Architecture) + + steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. + env: + ob_restore_phase: true + + # The env variable 'ReleaseTagVar' will be updated in this step. + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: yes + + - pwsh: | + $releaseTag = '$(ReleaseTagVar)' + if ($releaseTag -match '-') { + throw "Never release msixbundle vpack for a preview build. Current version: $releaseTag" + } + + # Check if release tag matches the expected format v#.#.# + $matched = $releaseTag -match '^v\d+\.(\d+)\.\d+$' + if (-not $matched) { + throw "Release tag must be in the format v#.#.#, such as 'v7.4.3'. Current version: $releaseTag" + } + + # Extract minor version and verify it's even (LTS versions only) + $minorVersion = [int]$Matches[1] + if($minorVersion % 2 -ne 0) { + throw "Only release msixbundle vpack for LTS releases. Current version: $releaseTag" + } + displayName: Stop any preview release + env: + ob_restore_phase: true + + ### START BUILD ### + + # Clone the checked out PowerShell repo to '/PowerShell' and set the variable 'PowerShellRoot'. + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(PowerShellRoot) + + # Add CodeQL Init task right before your 'Build' step. + - task: CodeQL3000Init@0 + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + inputs: + Enabled: true + # AnalyzeInPipeline: false = upload results + # AnalyzeInPipeline: true = do not upload results + AnalyzeInPipeline: false + Language: csharp + + - template: /.pipelines/templates/install-dotnet.yml@self + + - pwsh: | + $runtime = switch ($env:Architecture) + { + "x64" { "win7-x64" } + "arm64" { "win-arm64" } + } + + $vstsCommandString = "vso[task.setvariable variable=Runtime]$runtime" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + Write-Verbose -Message "Building PowerShell with Runtime: $runtime for '$env:BuildConfiguration' configuration" + Import-Module -Name $(PowerShellRoot)/build.psm1 -Force + $buildWithSymbolsPath = New-Item -ItemType Directory -Path $(Pipeline.Workspace)/Symbols_$(Architecture) -Force + + Start-PSBootstrap -Scenario Package + $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose + + Start-PSBuild -Runtime $runtime -Configuration Release -Output $buildWithSymbolsPath -Clean -PSModuleRestore -ReleaseTag $(ReleaseTagVar) + + $refFolderPath = Join-Path $buildWithSymbolsPath 'ref' + Write-Verbose -Verbose "refFolderPath: $refFolderPath" + $outputPath = Join-Path '$(ob_outputDirectory)' 'psoptions' + $null = New-Item -ItemType Directory -Path $outputPath -Force + $psOptPath = "$outputPath/psoptions.json" + Save-PSOptions -PSOptionsPath $psOptPath + + Write-Verbose -Verbose "Verifying pdbs exist in build folder" + $pdbs = Get-ChildItem -Path $buildWithSymbolsPath -Recurse -Filter *.pdb + if ($pdbs.Count -eq 0) { + throw "No pdbs found in build folder" + } + else { + Write-Verbose -Verbose "Found $($pdbs.Count) pdbs in build folder" + $pdbs | ForEach-Object { + Write-Verbose -Verbose "Pdb: $($_.FullName)" + } + + $pdbs | Compress-Archive -DestinationPath '$(ob_outputDirectory)\symbols-$(Architecture).zip' -Update + } + + Write-Verbose -Verbose "Completed building PowerShell for '$env:BuildConfiguration' configuration" + displayName: 'Build Windows Universal - $(Architecture)-$(BuildConfiguration) Symbols folder' + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + # Add CodeQL Finalize task right after your 'Build' step. + - task: CodeQL3000Finalize@0 + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + inputs: + sourceScanPath: '$(PowerShellRoot)\src' + ob_restore_phase: true + + # The signed files will be put in '$(ob_outputDirectory)\Signed-$(Runtime)' after this step. + - template: /.pipelines/templates/obp-file-signing.yml@self + parameters: + binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' + OfficialBuild: true + + ### END OF BUILD ### + + - pwsh: | + Get-ChildItem -Path '$(ob_outputDirectory)\Signed-$(Runtime)' -Recurse | Out-String -Width 9999 + displayName: Capture signed files + condition: succeededOrFailed() + + - pwsh: | + Get-ChildItem -Path env: | Out-String -Width 9999 + displayName: Capture Environment + condition: succeededOrFailed() + + ### START Packaging ### + + - template: /.pipelines/templates/shouldSign.yml@self + parameters: + ob_restore_phase: false + + - pwsh: | + Write-Verbose -Verbose "runtime = '$(Runtime)'" + Write-Verbose -Verbose "RepoRoot = '$(PowerShellRoot)'" + + $runtime = '$(Runtime)' + $repoRoot = '$(PowerShellRoot)' + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + + Find-Dotnet + + $signedFilesPath = '$(ob_outputDirectory)\Signed-$(Runtime)' + $psoptionsFilePath = '$(ob_outputDirectory)\psoptions\psoptions.json' + + Write-Verbose -Verbose "signedFilesPath: $signedFilesPath" + Write-Verbose -Verbose "psoptionsFilePath: $psoptionsFilePath" + + Write-Verbose -Message "checking pwsh exists in $signedFilesPath" -Verbose + if (-not (Test-Path $signedFilesPath\pwsh.exe)) { + throw "pwsh.exe not found in $signedFilesPath" + } + + Write-Verbose -Message "Restoring PSOptions from $psoptionsFilePath" -Verbose + + Restore-PSOptions -PSOptionsPath "$psoptionsFilePath" + Get-PSOptions | Write-Verbose -Verbose + + ## Generated packages are placed in the current directory by default. + Set-Location $repoRoot + Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $runtime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS + + $msixPkgNameFilter = "PowerShell*.msix" + $msixPkgFile = Get-ChildItem -Path $repoRoot -Filter $msixPkgNameFilter -File + $msixPkgPath = $msixPkgFile.FullName + Write-Verbose -Verbose "Unsigned msix package: $msixPkgPath" + + $pkgDir = '$(ob_outputDirectory)\pkgs' + $null = New-Item -ItemType Directory -Path $pkgDir -Force + Copy-Item -Path $msixPkgPath -Destination $pkgDir -Force -Verbose + displayName: 'Build MSIX Package (Unsigned)' + + ### END OF Packaging ### + + - pwsh: | + Get-ChildItem -Path '$(ob_outputDirectory)\pkgs' -Recurse + displayName: 'List Unsigned Package' + + - stage: Pack_MSIXBundle_And_Sign + displayName: 'Pack and sign MSIXBundle' + dependsOn: [Build_MSIX_Package] + jobs: + - job: Bundle + pool: + type: windows + variables: + ArtifactPlatform: 'windows' + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_artifactBaseName: drop_pack_msixbundle ob_createvpack_enabled: ${{ parameters.createVPack }} - ob_createvpack_packagename: 'PowerShell.app' + ob_createvpack_packagename: 'PowerShell7.Store.app' ob_createvpack_owneralias: 'dongbow' - ob_createvpack_description: 'VPack for the PowerShell Application' - ob_createvpack_targetDestinationDirectory: '$(Destination)' + ob_createvpack_description: 'VPack for the PowerShell 7 Store Application' + ob_createvpack_targetDestinationDirectory: '$(Destination)' ## The value is from the 'CreateVpack' task, used when pulling the generated VPack. ob_createvpack_propsFile: false ob_createvpack_provData: true ob_createvpack_metadata: '$(Build.SourceVersion)' ob_createvpack_versionAs: string - ob_createvpack_version: '$(version)' + ob_createvpack_version: '$(Version)' ob_createvpack_verbose: true steps: - - template: .pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - pwsh: | - Write-Verbose -Verbose 'PowerShell Version: $(version)' - if('$(version)' -match '-') { - throw "Don't release a preview build msixbundle package" - } - displayName: Stop any preview release - - - download: PSPackagesOfficial - artifact: 'drop_msixbundle_CreateMSIXBundle' - displayName: Download package - - - pwsh: | - $payloadDir = '$(Pipeline.Workspace)\PSPackagesOfficial\drop_msixbundle_CreateMSIXBundle' - Get-ChildItem $payloadDir -Recurse | Out-String -Width 150 - $vstsCommandString = "vso[task.setvariable variable=PayloadDir]$payloadDir" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: 'Capture Artifact Listing' - - - pwsh: | - $bundlePackage = Get-ChildItem '$(PayloadDir)\*.msixbundle' - Write-Verbose -Verbose ("MSIX bundle package: " + $bundlePackage.FullName -join ', ') - if ($bundlePackage.Count -ne 1) { - throw "Expected to find 1 MSIX bundle package, but found $($bundlePackage.Count)" - } + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. + env: + ob_restore_phase: true - if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { - $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop - } + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no - $targetPath = Join-Path '$(ob_outputDirectory)' 'Microsoft.PowerShell_8wekyb3d8bbwe.msixbundle' - Copy-Item -Verbose -Path $bundlePackage.FullName -Destination $targetPath - displayName: 'Stage msixbundle for vpack' + - template: /.pipelines/templates/shouldSign.yml@self - - pwsh: | - Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose - $vpackFiles = Get-ChildItem -Path $(ob_outputDirectory)\* -Recurse - if($vpackFiles.Count -eq 0) { - throw "No files found in $(ob_outputDirectory)" - } - $vpackFiles | Out-String -Width 150 - displayName: Debug Output Directory and Version - condition: succeededOrFailed() + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_x64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download msix for x64 + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_arm64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download msix for arm64 + + # Finds the makeappx tool on the machine. + - pwsh: | + Write-Verbose -Verbose 'PowerShell Version: $(Version)' + $cmd = Get-Command makeappx.exe -ErrorAction Ignore + if ($cmd) { + Write-Verbose -Verbose 'makeappx available in PATH' + $exePath = $cmd.Source + } else { + $makeappx = Get-ChildItem -Recurse 'C:\Program Files (x86)\Windows Kits\10\makeappx.exe' | + Where-Object { $_.DirectoryName -match 'x64' } | + Select-Object -Last 1 + $exePath = $makeappx.FullName + Write-Verbose -Verbose "makeappx was found: $exePath" + } + $vstsCommandString = "vso[task.setvariable variable=MakeAppxPath]$exePath" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Find makeappx tool + retryCountOnTaskFailure: 1 + + - pwsh: | + $sourceDir = '$(Pipeline.Workspace)\releasePipeline\msix' + $null = New-Item -Path $sourceDir -ItemType Directory -Force + + $msixFiles = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse + foreach ($msixFile in $msixFiles) { + $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose + } + + $file = Get-ChildItem $sourceDir | Select-Object -First 1 + $prefix = ($file.BaseName -split "-win")[0] + $pkgName = "$prefix.msixbundle" + Write-Verbose -Verbose "Creating $pkgName" + + $makeappx = '$(MakeAppxPath)' + $outputDir = "$sourceDir\output" + New-Item $outputDir -Type Directory -Force > $null + & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" + if ($LASTEXITCODE -ne 0) { + throw "makeappx bundle failed with exit code $LASTEXITCODE" + } + + Get-ChildItem -Path $sourceDir -Recurse | Out-String -Width 200 + $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Create MsixBundle + retryCountOnTaskFailure: 1 + + - task: onebranch.pipeline.signing@1 + displayName: Sign MsixBundle + inputs: + command: 'sign' + signing_profile: $(MSIXProfile) + files_to_sign: '**/*.msixbundle' + search_root: '$(BundleDir)' + + - pwsh: | + $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File + Write-Verbose -Verbose "Signed bundle: $signedBundle" + + $signature = Get-AuthenticodeSignature -FilePath $signedBundle.FullName + if ($signature.Status -ne 'Valid') { + throw "The bundle file doesn't have a valid signature. Signature status: $($signature.Status)" + } + + if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { + $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop + } + + $targetPath = Join-Path '$(ob_outputDirectory)' 'Microsoft.PowerShell-LTS_8wekyb3d8bbwe.msixbundle' + Copy-Item -Verbose -Path $signedBundle.FullName -Destination $targetPath + + Write-Verbose -Verbose "Uploaded Bundle:" + Get-ChildItem -Path $(ob_outputDirectory) | Out-String -Width 200 -Stream | Write-Verbose -Verbose + displayName: 'Stage msixbundle for VPack' + + - pwsh: | + Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose + $vpackFiles = Get-ChildItem -Path '$(ob_outputDirectory)\*' -Recurse + if($vpackFiles.Count -eq 0) { + throw "No files found in $(ob_outputDirectory)" + } + $vpackFiles | Out-String -Width 200 + displayName: Debug Output Directory and Version + condition: succeededOrFailed() + + - stage: Publish_Symbols + displayName: 'Publish Symbols' + dependsOn: [Pack_MSIXBundle_And_Sign] + jobs: + - job: PublishSymbols + pool: + type: windows + variables: + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + + steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. + env: + ob_restore_phase: true + + - pwsh: | + Get-ChildItem Env: | Out-String -Width 9999 + displayName: 'Capture Environment Variables' + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_x64 + itemPattern: | + **/symbols-*.zip + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download symbols for x64 + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_arm64 + itemPattern: | + **/symbols-*.zip + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download symbols for arm64 + + - pwsh: | + $downloadDir = '$(Build.ArtifactStagingDirectory)\downloads' + Write-Verbose -Verbose "Enumerating $downloadDir" + $downloadedArtifacts = Get-ChildItem -Path $downloadDir -Recurse -Filter 'symbols-*.zip' + $downloadedArtifacts | Out-String -Width 9999 + + $expandedRoot = New-Item -Path "$(Pipeline.Workspace)\expanded" -ItemType Directory -Verbose + $downloadedArtifacts | ForEach-Object { + $expandDir = Join-Path $expandedRoot $_.BaseName + Write-Verbose -Verbose "Expanding $($_.FullName) to $expandDir" + $null = New-Item -Path $expandDir -ItemType Directory -Verbose + Expand-Archive -Path $_.FullName -DestinationPath $expandDir -Force + } + + Write-Verbose -Verbose "Enumerating $expandedRoot" + Get-ChildItem -Path $expandedRoot -Recurse | Out-String -Width 9999 + $vstsCommandString = "vso[task.setvariable variable=SymbolsPath]$expandedRoot" + Write-Verbose -Message "$vstsCommandString" -Verbose + Write-Host -Object "##$vstsCommandString" + displayName: Expand and capture symbols folders + + - task: PublishSymbols@2 + condition: and(succeeded(), ${{ parameters.createVPack }}) + inputs: + symbolsFolder: '$(SymbolsPath)' + searchPattern: '**/*.pdb' + indexSources: false + publishSymbols: true + symbolServerType: TeamServices + detailedLog: true diff --git a/PowerShell.Common.props b/PowerShell.Common.props index 07d22b49cb9..712653d06ae 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -163,7 +163,7 @@ <PropertyGroup> <DefineConstants>$(DefineConstants);CORECLR</DefineConstants> - <IsWindows Condition="'$(IsWindows)' =='true' or ( '$(IsWindows)' == '' and '$(OS)' == 'Windows_NT')">true</IsWindows> + <IsWindows Condition="'$(IsWindows)' == 'true' or ('$(IsWindows)' == '' and '$(OS)' == 'Windows_NT')">true</IsWindows> </PropertyGroup> <!-- Define non-windows, all configuration properties --> diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index aa5d532da2a..8fc815f59e6 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -323,7 +323,7 @@ internal static int Start( } s_theConsoleHost.BindBreakHandler(); - PSHost.IsStdOutputRedirected = Console.IsOutputRedirected; + IsStdOutputRedirected = Console.IsOutputRedirected; // Send startup telemetry for ConsoleHost startup ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("Normal", s_cpp.ParametersUsedAsDouble); diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs index 6dfd5d54e6f..acfdea07153 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs @@ -86,9 +86,9 @@ public static int Start([MarshalAs(UnmanagedType.LPArray, ArraySubType = Unmanag int exitCode = 0; try { - var banner = string.Format( + string banner = string.Format( CultureInfo.InvariantCulture, - ManagedEntranceStrings.ShellBannerNonWindowsPowerShell, + ManagedEntranceStrings.ShellBannerPowerShell, PSVersionInfo.GitCommitId); ConsoleHost.DefaultInitialSessionState = InitialSessionState.CreateDefault2(); diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx index 40f02e7a37f..276bed7e2e8 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx @@ -117,7 +117,7 @@ <resheader name="writer"> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> - <data name="ShellBannerNonWindowsPowerShell" xml:space="preserve"> + <data name="ShellBannerPowerShell" xml:space="preserve"> <value>PowerShell {0}</value> </data> <data name="ShellBannerCLMode" xml:space="preserve"> diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx index 05f12b0c29b..5d47e15fe27 100644 --- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx +++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx @@ -846,7 +846,7 @@ Note that 'Start-Job' is not supported by design in scenarios where PowerShell i <value>The WriteEvents parameter cannot be used without the Wait parameter.</value> </data> <data name="PowerShellVersionNotSupported" xml:space="preserve"> - <value>PowerShell remoting endpoint versioning is not supported on PowerShell Core.</value> + <value>PowerShell remoting endpoint versioning is not supported on PowerShell 7+.</value> </data> <data name="JobManagerRegistrationConstructorError" xml:space="preserve"> <value>The following type cannot be instantiated because its constructor is not public: {0}.</value> diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index 3579401e810..cffedb7c579 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -165,7 +165,7 @@ public static class ApplicationInsightsTelemetry private static readonly HashSet<string> s_knownSubsystemNames; /// <summary>Gets a value indicating whether telemetry can be sent.</summary> - public static bool CanSendTelemetry { get; private set; } = false; + public static bool CanSendTelemetry { get; private set; } /// <summary> /// Initializes static members of the <see cref="ApplicationInsightsTelemetry"/> class. @@ -834,11 +834,11 @@ internal static void SendUseTelemetry(string featureName, string detail, double if (string.Compare(featureName, s_subsystemRegistration, true) == 0) { - ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, GetSubsystemName(detail)), value); + SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, GetSubsystemName(detail)), value); } else { - ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, detail), value); + SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, detail), value); } } @@ -854,7 +854,7 @@ internal static void SendExperimentalUseData(string featureName, string detail) return; } - ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.ExperimentalFeatureUse, string.Join(":", featureName, detail)); + SendTelemetryMetric(TelemetryType.ExperimentalFeatureUse, string.Join(":", featureName, detail)); } // Get the experimental feature name. If we can report it, we'll return the name of the feature, otherwise, we'll return "anonymous" diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 269715d3551..d75688e3921 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4301,8 +4301,7 @@ function New-MSIXPackage Write-Verbose "Using LTS assets" -Verbose } - # Appx manifest needs to be in root of source path, but the embedded version needs to be updated - # cp-459155 is 'CN=Microsoft Windows Store Publisher (Store EKU), O=Microsoft Corporation, L=Redmond, S=Washington, C=US' + # Appx manifest needs to be in root of source path, but the embedded version needs to be updated. # authenticodeFormer is 'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US' $releasePublisher = 'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US' @@ -4344,7 +4343,6 @@ function New-MSIXPackage else { Copy-Item -Path "$RepoRoot\assets\$_.png" -Destination "$ProductSourcePath\assets\" } - } if ($PSCmdlet.ShouldProcess("Create .msix package?")) { From f0926d8bc24a1c7770c9821a6a18d48af15f0a77 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Thu, 9 Apr 2026 15:34:46 -0700 Subject: [PATCH 248/275] [release/v7.5.6] [StepSecurity] ci: Harden GitHub Actions tags (#27239) --- .github/actions/build/ci/action.yml | 4 ++-- .../get-changed-files/action.yml | 2 +- .../infrastructure/path-filters/action.yml | 2 +- .../actions/test/linux-packaging/action.yml | 8 ++++---- .github/actions/test/nix/action.yml | 6 +++--- .../test/process-pester-results/action.yml | 2 +- .github/actions/test/windows/action.yml | 4 ++-- .github/workflows/analyze-reusable.yml | 2 +- .github/workflows/copilot-setup-steps.yml | 2 +- .github/workflows/labels.yml | 4 ++-- .github/workflows/linux-ci.yml | 18 ++++++++--------- .github/workflows/macos-ci.yml | 20 +++++++++---------- .github/workflows/verify-markdown-links.yml | 2 +- .github/workflows/windows-ci.yml | 14 ++++++------- .../workflows/windows-packaging-reusable.yml | 8 ++++---- .github/workflows/xunit-tests.yml | 8 ++++---- 16 files changed, 53 insertions(+), 53 deletions(-) diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml index be9c0ecd20b..65331fb3185 100644 --- a/.github/actions/build/ci/action.yml +++ b/.github/actions/build/ci/action.yml @@ -13,7 +13,7 @@ runs: if: github.event_name != 'PullRequest' run: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhmmss"))" shell: pwsh - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: global-json-file: ./global.json - name: Bootstrap @@ -34,7 +34,7 @@ runs: Invoke-CIBuild shell: pwsh - name: Upload build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: build path: ${{ runner.workspace }}/build diff --git a/.github/actions/infrastructure/get-changed-files/action.yml b/.github/actions/infrastructure/get-changed-files/action.yml index c897d4f388d..51631cfe141 100644 --- a/.github/actions/infrastructure/get-changed-files/action.yml +++ b/.github/actions/infrastructure/get-changed-files/action.yml @@ -21,7 +21,7 @@ runs: steps: - name: Get changed files id: get-files - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: script: | const eventTypes = '${{ inputs.event-types }}'.split(',').map(t => t.trim()); diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml index 656719262b2..af23540256d 100644 --- a/.github/actions/infrastructure/path-filters/action.yml +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -39,7 +39,7 @@ runs: - name: Check if GitHubWorkflowChanges is present id: filter - uses: actions/github-script@v7.0.1 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 env: FILES_JSON: ${{ steps.get-files.outputs.files }} with: diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index ef9ba23e799..7a06e3feb17 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -11,7 +11,7 @@ runs: Show-Environment shell: pwsh - - uses: actions/setup-dotnet@v5 + - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json @@ -97,21 +97,21 @@ runs: shell: pwsh - name: Upload deb packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: packages-deb path: ${{ runner.workspace }}/packages/*.deb if-no-files-found: ignore - name: Upload rpm packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: packages-rpm path: ${{ runner.workspace }}/packages/*.rpm if-no-files-found: ignore - name: Upload tar.gz packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: packages-tar path: ${{ runner.workspace }}/packages/*.tar.gz diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index ef943bfce78..35ebc09ba4a 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -26,7 +26,7 @@ runs: shell: pwsh - name: Download Build Artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: path: "${{ github.workspace }}" @@ -39,7 +39,7 @@ runs: Write-LogGroupEnd -Title 'Artifacts Directory' shell: pwsh - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: global-json-file: ./global.json @@ -53,7 +53,7 @@ runs: Write-LogGroupEnd -Title 'Bootstrap' - name: Extract Files - uses: actions/github-script@v7.0.0 + uses: actions/github-script@e69ef5462fd455e02edcaf4dd7708eda96b9eda0 # v7.0.0 env: DESTINATION_FOLDER: "${{ github.workspace }}/bins" ARCHIVE_FILE_PATTERNS: "${{ github.workspace }}/build/build.zip" diff --git a/.github/actions/test/process-pester-results/action.yml b/.github/actions/test/process-pester-results/action.yml index 27b94f6ebcb..44f2037626f 100644 --- a/.github/actions/test/process-pester-results/action.yml +++ b/.github/actions/test/process-pester-results/action.yml @@ -21,7 +21,7 @@ runs: - name: Upload testResults artifact if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: junit-pester-${{ inputs.name }} path: ${{ runner.workspace }}/testResults diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index 3b3ce0cafe8..85c026ee8c6 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -26,7 +26,7 @@ runs: shell: pwsh - name: Download Build Artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: path: "${{ github.workspace }}" @@ -39,7 +39,7 @@ runs: Write-LogGroupEnd -Title 'Artifacts Directory' shell: pwsh - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: global-json-file: .\global.json diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 75886342851..aca43b54ca9 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -41,7 +41,7 @@ jobs: with: fetch-depth: '0' - - uses: actions/setup-dotnet@v5 + - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 6b6f3a1f928..d78e745a4a9 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -25,7 +25,7 @@ jobs: # You can define any steps you want, and they will run before the agent starts. # If you do not check out your code, Copilot will do this for you. steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index 794ef64b213..27ceac59bbd 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -18,11 +18,11 @@ jobs: steps: - name: Check out the repository - uses: actions/checkout@v2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Verify PR has label starting with 'cl-' id: verify-labels - uses: actions/github-script@v6 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: | const labels = context.payload.pull_request.labels.map(label => label.name.toLowerCase()); diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 773f565c601..9f8790263d9 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -55,7 +55,7 @@ jobs: packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -74,7 +74,7 @@ jobs: contents: read steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Check for merge conflict markers uses: "./.github/actions/infrastructure/merge-conflict-checker" @@ -86,7 +86,7 @@ jobs: if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 @@ -101,7 +101,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Linux Unelevated CI @@ -118,7 +118,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Linux Elevated CI @@ -135,7 +135,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Linux Unelevated Others @@ -152,7 +152,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Linux Elevated Others @@ -175,7 +175,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 @@ -250,7 +250,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 - name: Linux Packaging diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 917ed633151..bc2c5eb9d9f 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -57,7 +57,7 @@ jobs: packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Change Detection id: filter @@ -72,7 +72,7 @@ jobs: if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Build @@ -86,7 +86,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: macOS Unelevated CI @@ -103,7 +103,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: macOS Elevated CI @@ -120,7 +120,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: macOS Unelevated Others @@ -137,7 +137,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: macOS Elevated Others @@ -164,10 +164,10 @@ jobs: - macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json - name: Bootstrap packaging @@ -226,7 +226,7 @@ jobs: testResultsFolder: "${{ runner.workspace }}/testResults" - name: Upload package artifact if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: macos-package path: "*.pkg" @@ -242,4 +242,4 @@ jobs: if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: - needs_context: ${{ toJson(needs) }} \ No newline at end of file + needs_context: ${{ toJson(needs) }} diff --git a/.github/workflows/verify-markdown-links.yml b/.github/workflows/verify-markdown-links.yml index db9fb7e416a..19da648a959 100644 --- a/.github/workflows/verify-markdown-links.yml +++ b/.github/workflows/verify-markdown-links.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Verify markdown links id: verify diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 118da99f366..68956ff604e 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -58,7 +58,7 @@ jobs: packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Change Detection id: filter @@ -73,7 +73,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Build @@ -87,7 +87,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Windows Unelevated CI @@ -104,7 +104,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Windows Elevated CI @@ -121,7 +121,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Windows Unelevated Others @@ -138,7 +138,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Windows Elevated Others @@ -185,4 +185,4 @@ jobs: if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: - needs_context: ${{ toJson(needs) }} \ No newline at end of file + needs_context: ${{ toJson(needs) }} diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 436287e96f9..8d0255d4443 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -39,7 +39,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 @@ -64,7 +64,7 @@ jobs: shell: pwsh - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json @@ -84,9 +84,9 @@ jobs: - name: Upload Build Artifacts if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: windows-packaging-${{ matrix.architecture }}-${{ matrix.channel }} path: | ${{ github.workspace }}/artifacts/**/* - !${{ github.workspace }}/artifacts/**/*.pdb \ No newline at end of file + !${{ github.workspace }}/artifacts/**/*.pdb diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index 1495f91b9a1..c643917edd0 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -23,12 +23,12 @@ jobs: runs-on: ${{ inputs.runner_os }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json @@ -49,8 +49,8 @@ jobs: Write-Host "Completed xUnit test run." - name: Upload xUnit results - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 if: always() with: name: ${{ inputs.test_results_artifact_name }} - path: ${{ github.workspace }}/xUnitTestResults.xml \ No newline at end of file + path: ${{ github.workspace }}/xUnitTestResults.xml From 763d8f18b3b2def924c5eacf218de2d25e04da51 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Thu, 9 Apr 2026 16:43:10 -0700 Subject: [PATCH 249/275] [release/v7.5.6] Pin ready-to-merge.yml reusable workflow to commit SHA (#27246) --- .github/workflows/linux-ci.yml | 2 +- .github/workflows/macos-ci.yml | 2 +- .github/workflows/windows-ci.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 9f8790263d9..5a2e75a0169 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -238,7 +238,7 @@ jobs: - infrastructure_tests # - analyze if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@c8b3ad5819ad7078f3e375519b4f8c6232d1cbdf # v1.0.0 with: needs_context: ${{ toJson(needs) }} linux_packaging: diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index bc2c5eb9d9f..aa3f11b3985 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -240,6 +240,6 @@ jobs: - macos_test_unelevated_ci - macos_test_unelevated_others if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@c8b3ad5819ad7078f3e375519b4f8c6232d1cbdf # v1.0.0 with: needs_context: ${{ toJson(needs) }} diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 68956ff604e..4da53f797a4 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -183,6 +183,6 @@ jobs: - analyze - windows_packaging if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@c8b3ad5819ad7078f3e375519b4f8c6232d1cbdf # v1.0.0 with: needs_context: ${{ toJson(needs) }} From a9e7f2afcd060471bc8e75a0dd0f21c880446a93 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Fri, 10 Apr 2026 15:28:59 -0700 Subject: [PATCH 250/275] [release/v7.5.6] Fix package pipeline by adding in PDP-Media directory (#27256) --- .pipelines/store/PDP/PDP-Media/en-US/.gitkeep | 0 .pipelines/templates/package-store-package.yml | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/.gitkeep diff --git a/.pipelines/store/PDP/PDP-Media/en-US/.gitkeep b/.pipelines/store/PDP/PDP-Media/en-US/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/.pipelines/templates/package-store-package.yml b/.pipelines/templates/package-store-package.yml index 7667b1361e7..6abddae6851 100644 --- a/.pipelines/templates/package-store-package.yml +++ b/.pipelines/templates/package-store-package.yml @@ -195,6 +195,7 @@ jobs: contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package (Stable/LTS)' @@ -206,6 +207,7 @@ jobs: contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - pwsh: | $outputDirectory = "$(ob_outputDirectory)" From 944ee51797b1802560646676ab6f6a902e2f35a2 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:16:58 -0400 Subject: [PATCH 251/275] [release/v7.5.6] Update branch for the v7.5.6 release (#27268) --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 670d68870ea..123a66e4a10 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "9.0.312", + "sdkImageVersion": "9.0.313", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index f903f66dc23..135a2663e2e 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.312" + "version": "9.0.313" } } From 6633028deaa1c5da4b57bf889f3467b63e9ea5a5 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 15 Apr 2026 14:52:14 -0700 Subject: [PATCH 252/275] [release/v7.5.6] Fix the APIScan pipeline (#27276) --- .pipelines/apiscan-gen-notice.yml | 2 +- .pipelines/templates/compliance/apiscan.yml | 55 +++++++-------------- 2 files changed, 20 insertions(+), 37 deletions(-) diff --git a/.pipelines/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml index af122fb2365..a93f98a2e53 100644 --- a/.pipelines/apiscan-gen-notice.yml +++ b/.pipelines/apiscan-gen-notice.yml @@ -83,7 +83,7 @@ extends: break: true # always break the build on binskim issues in addition to TSA upload policheck: break: true # always break the build on policheck issues. You can disable it by setting to 'false' - # APIScan requires a non-Ready-To-Run build + # APIScan requires a non-Ready-To-Run build apiscan: enabled: true softwareName: "PowerShell" # Default is repo name diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml index 27cb3a83a5c..b5a15699026 100644 --- a/.pipelines/templates/compliance/apiscan.yml +++ b/.pipelines/templates/compliance/apiscan.yml @@ -15,7 +15,6 @@ jobs: - name: branchCounter value: $[counter(variables['branchCounterKey'], 1)] - group: DotNetPrivateBuildAccess - - group: Azure Blob variable group - group: ReleasePipelineSecrets - group: mscodehub-feed-read-general - group: mscodehub-feed-read-akv @@ -72,34 +71,6 @@ jobs: workingDirectory: '$(repoRoot)' retryCountOnTaskFailure: 2 - - task: AzurePowerShell@5 - displayName: Download winverify-private Artifacts - inputs: - azureSubscription: az-blob-cicd-infra - scriptType: inlineScript - azurePowerShellVersion: LatestVersion - workingDirectory: '$(repoRoot)' - pwsh: true - inline: | - # download smybols for getfilesiginforedist.dll - $downloadsDirectory = '$(Build.ArtifactStagingDirectory)/downloads' - $uploadedDirectory = '$(Build.ArtifactStagingDirectory)/uploaded' - $storageAccountName = "pscoretestdata" - $containerName = 'winverify-private' - $winverifySymbolsPath = New-Item -ItemType Directory -Path '$(System.ArtifactsDirectory)/winverify-symbols' -Force - $dllName = 'getfilesiginforedist.dll' - $winverifySymbolsDllPath = Join-Path $winverifySymbolsPath $dllName - - $context = New-AzStorageContext -StorageAccountName $storageAccountName -UseConnectedAccount - - Get-AzStorageBlobContent -Container $containerName -Blob $dllName -Destination $winverifySymbolsDllPath -Context $context - - - pwsh: | - Get-ChildItem -Path '$(System.ArtifactsDirectory)/winverify-symbols' - displayName: Capture winverify-private Artifacts - workingDirectory: '$(repoRoot)' - condition: succeededOrFailed() - - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. displayName: 🔏 CodeQL 3000 Init condition: eq(variables['CODEQL_ENABLED'], 'true') @@ -118,23 +89,35 @@ jobs: Remove-Item -Recurse -Force $OutputFolder/ref } - Copy-Item -Path "$OutputFolder\*" -Destination '$(ob_outputDirectory)' -Recurse -Verbose + $Destination = '$(ob_outputDirectory)' + if (-not (Test-Path $Destination)) { + Write-Verbose -Verbose -Message "Creating destination folder '$Destination'" + $null = mkdir $Destination + } + + Copy-Item -Path "$OutputFolder\*" -Destination $Destination -Recurse -Verbose workingDirectory: '$(repoRoot)' displayName: 'Build PowerShell Source' - pwsh: | - # Only key windows runtimes - Get-ChildItem -Path '$(ob_outputDirectory)\runtimes\*' -File -Recurse | Where-Object {$_.FullName -notmatch '.*\/runtimes\/win'} | Foreach-Object { + # Only keep windows runtimes + Write-Verbose -Verbose -Message "Deleting non-win-x64 runtimes ..." + Get-ChildItem -Path '$(ob_outputDirectory)\runtimes\*' | Where-Object {$_.FullName -notmatch '.*\\runtimes\\win'} | Foreach-Object { Write-Verbose -Verbose -Message "Deleting $($_.FullName)" - Remove-Item -Force -Verbose -Path $_.FullName + Remove-Item -Path $_.FullName -Recurse -Force } - # Temporarily remove runtimes/win-x64 due to issues with that runtime - Get-ChildItem -Path '$(ob_outputDirectory)\runtimes\*' -File -Recurse | Where-Object {$_.FullName -match '.*\/runtimes\/win-x86\/'} | Foreach-Object { + # Remove win-x86/arm/arm64 runtimes due to issues with those runtimes + Write-Verbose -Verbose -Message "Temporarily deleting win-x86/arm/arm64 runtimes ..." + Get-ChildItem -Path '$(ob_outputDirectory)\runtimes\*' | Where-Object {$_.FullName -match '.*\\runtimes\\win-(x86|arm)'} | Foreach-Object { Write-Verbose -Verbose -Message "Deleting $($_.FullName)" - Remove-Item -Force -Verbose -Path $_.FullName + Remove-Item -Path $_.FullName -Recurse -Force } + Write-Host + Write-Verbose -Verbose -Message "Show content in 'runtimes' folder:" + Get-ChildItem -Path '$(ob_outputDirectory)\runtimes' + Write-Host workingDirectory: '$(repoRoot)' displayName: 'Remove unused runtimes' From 562aa412958340e46e9dd9e7a1e97942b5d7c3fb Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:16:49 -0400 Subject: [PATCH 253/275] [release/v7.5.6] Update referenced packages and `cgmanifest.json` for v7.5.6 release (#27286) --- ...oft.PowerShell.Commands.Diagnostics.csproj | 8 +- ...soft.PowerShell.Commands.Management.csproj | 4 +- ...crosoft.PowerShell.Commands.Utility.csproj | 8 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 107 +++++++++--------- .../Microsoft.WSMan.Management.csproj | 4 +- .../PSVersionInfoGenerator.csproj | 6 +- .../System.Management.Automation.csproj | 24 ++-- .../BenchmarkDotNet.Extensions.csproj | 10 +- .../ResultsComparer/ResultsComparer.csproj | 10 +- ...soft.PowerShell.NamedPipeConnection.csproj | 26 ++--- test/tools/TestService/TestService.csproj | 96 ++++++++-------- test/tools/WebListener/WebListener.csproj | 6 +- tools/cgmanifest/main/cgmanifest.json | 106 ++++++++--------- 14 files changed, 208 insertions(+), 209 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 0c53b99662d..2884b44d129 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,11 +7,11 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.14" /> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.14" /> - <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.14" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> + <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.15" /> <ProjectReference Include="..\System.Management.Automation\System.Management.Automation.csproj" /> - <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.14" /> + <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.15" /> </ItemGroup> <PropertyGroup> diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 835483b822b..edfd9c0322b 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,8 +47,8 @@ <ItemGroup> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.14" /> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.14" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.15" /> </ItemGroup> </Project> diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 381bcf2854c..91c7d073fc1 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -13,8 +13,8 @@ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> - <PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.14" /> - <PackageReference Include="System.Reflection.Metadata" Version="9.0.14" /> + <PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.15" /> + <PackageReference Include="System.Reflection.Metadata" Version="9.0.15" /> <ProjectReference Include="..\System.Management.Automation\System.Management.Automation.csproj" /> <PackageReference Include="Markdig.Signed" Version="0.38.0" /> <PackageReference Include="Microsoft.PowerShell.MarkdownRender" Version="7.2.1" /> @@ -41,8 +41,8 @@ <ItemGroup> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" /> - <PackageReference Include="System.Threading.AccessControl" Version="9.0.14" /> - <PackageReference Include="System.Drawing.Common" Version="9.0.14" /> + <PackageReference Include="System.Threading.AccessControl" Version="9.0.15" /> + <PackageReference Include="System.Drawing.Common" Version="9.0.15" /> <PackageReference Include="JsonSchema.Net" Version="7.2.3" /> </ItemGroup> diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 7898716fb97..7149411f3da 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ <ItemGroup> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.14" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> </ItemGroup> </Project> diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 591f855d79c..d9603fbc4e8 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,57 +16,57 @@ <ItemGroup> <!-- This section is to force the version of non-direct dependencies --> - <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.14" /> - <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.14" /> - <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.14" /> - <PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.14" /> - <PackageReference Include="runtime.android-arm.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.android-arm64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.android-x64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.android-x86.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-arm.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-arm64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-bionic-arm64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-bionic-x64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-musl-arm.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-musl-arm64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-musl-x64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-x64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.maccatalyst-arm64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.maccatalyst-x64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.osx-arm64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.osx-x64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="System.CodeDom" Version="9.0.14" /> - <PackageReference Include="System.ComponentModel.Composition" Version="9.0.14" /> - <PackageReference Include="System.ComponentModel.Composition.Registration" Version="9.0.14" /> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.14" /> - <PackageReference Include="System.Data.Odbc" Version="9.0.14" /> - <PackageReference Include="System.Data.OleDb" Version="9.0.14" /> + <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.15" /> + <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.15" /> + <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.15" /> + <PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.15" /> + <PackageReference Include="runtime.android-arm.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.android-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.android-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.android-x86.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-arm.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-bionic-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-bionic-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-musl-arm.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-musl-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-musl-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.maccatalyst-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.maccatalyst-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.osx-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.osx-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="System.CodeDom" Version="9.0.15" /> + <PackageReference Include="System.ComponentModel.Composition" Version="9.0.15" /> + <PackageReference Include="System.ComponentModel.Composition.Registration" Version="9.0.15" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.15" /> + <PackageReference Include="System.Data.Odbc" Version="9.0.15" /> + <PackageReference Include="System.Data.OleDb" Version="9.0.15" /> <!-- the following package(s) are from https://github.com/dotnet/fxdac --> <PackageReference Include="System.Data.SqlClient" Version="4.9.1" /> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.14" /> - <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.14" /> - <PackageReference Include="System.DirectoryServices" Version="9.0.14" /> - <PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.14" /> - <PackageReference Include="System.DirectoryServices.Protocols" Version="9.0.14" /> - <PackageReference Include="System.Drawing.Common" Version="9.0.14" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.15" /> + <PackageReference Include="System.DirectoryServices" Version="9.0.15" /> + <PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.15" /> + <PackageReference Include="System.DirectoryServices.Protocols" Version="9.0.15" /> + <PackageReference Include="System.Drawing.Common" Version="9.0.15" /> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.IO.Packaging" Version="9.0.14" /> - <PackageReference Include="System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="System.Management" Version="9.0.14" /> - <PackageReference Include="System.Net.Http.WinHttpHandler" Version="9.0.14" /> - <PackageReference Include="System.Reflection.Context" Version="9.0.14" /> - <PackageReference Include="System.Runtime.Caching" Version="9.0.14" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.14" /> - <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.14" /> - <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.14" /> - <PackageReference Include="System.Security.Permissions" Version="9.0.14" /> - <PackageReference Include="System.ServiceModel.Syndication" Version="9.0.14" /> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.14" /> - <PackageReference Include="System.Speech" Version="9.0.14" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.14" /> - <PackageReference Include="System.Text.Encodings.Web" Version="9.0.14" /> + <PackageReference Include="System.IO.Packaging" Version="9.0.15" /> + <PackageReference Include="System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="System.Management" Version="9.0.15" /> + <PackageReference Include="System.Net.Http.WinHttpHandler" Version="9.0.15" /> + <PackageReference Include="System.Reflection.Context" Version="9.0.15" /> + <PackageReference Include="System.Runtime.Caching" Version="9.0.15" /> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.15" /> + <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.15" /> + <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.15" /> + <PackageReference Include="System.Security.Permissions" Version="9.0.15" /> + <PackageReference Include="System.ServiceModel.Syndication" Version="9.0.15" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.15" /> + <PackageReference Include="System.Speech" Version="9.0.15" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> + <PackageReference Include="System.Text.Encodings.Web" Version="9.0.15" /> <!-- the following package(s) are from https://github.com/dotnet/wcf they are pinned to the version 4.10.x due to a breaking change in newer versions. @@ -79,10 +79,10 @@ <PackageReference Include="System.ServiceModel.Security" Version="4.10.3" /> <PackageReference Include="System.Private.ServiceModel" Version="4.10.3" /> <!-- the source could not be found for the following package(s) --> - <PackageReference Include="Microsoft.Windows.Compatibility" Version="9.0.14" /> - <PackageReference Include="System.Threading.AccessControl" Version="9.0.14" /> + <PackageReference Include="Microsoft.Windows.Compatibility" Version="9.0.15" /> + <PackageReference Include="System.Threading.AccessControl" Version="9.0.15" /> <PackageReference Include="System.Web.Services.Description" Version="8.0.0" /> - <PackageReference Include="System.Windows.Extensions" Version="9.0.14" /> + <PackageReference Include="System.Windows.Extensions" Version="9.0.15" /> </ItemGroup> <!-- @@ -95,14 +95,13 @@ dotnet msbuild ./dummy.csproj /t:ResolveAssemblyReferencesDesignTime /fileLogger /noconsolelogger /v:diag 3. Search '_ReferencesFromRAR' in the produced 'msbuild.log' file. --> - <Target Name="_GetDependencies" - DependsOnTargets="ResolveAssemblyReferencesDesignTime"> + <Target Name="_GetDependencies" DependsOnTargets="ResolveAssemblyReferencesDesignTime"> <ItemGroup> <!-- Excludes 'Microsoft.Management.Infrastructure' from the type catalog reference list, as it is provided separately at runtime and must not be included in the generated catalog. --> - <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' "/> + <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' " /> </ItemGroup> <WriteLinesToFile File="$(_DependencyFile)" Lines="@(_RefAssemblyPath)" Overwrite="true" /> </Target> diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 99859a621e4..64c28602b39 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,11 +7,11 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.14" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> <ProjectReference Include="..\System.Management.Automation\System.Management.Automation.csproj" /> <ProjectReference Include="..\Microsoft.WSMan.Runtime\Microsoft.WSMan.Runtime.csproj" /> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.14" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.15" /> </ItemGroup> <PropertyGroup> diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index d14e7a41f80..d99cddb75b1 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -17,8 +17,8 @@ <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" /> <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" /> <PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.4" /> - <PackageReference Include="System.Collections.Immutable" Version="9.0.14" /> - <PackageReference Include="System.Reflection.Metadata" Version="9.0.14" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.14" /> + <PackageReference Include="System.Collections.Immutable" Version="9.0.15" /> + <PackageReference Include="System.Reflection.Metadata" Version="9.0.15" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> </ItemGroup> </Project> diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 399014b9111..c82609b1605 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,25 +32,25 @@ <!-- the Application Insights package --> <PackageReference Include="Microsoft.ApplicationInsights" Version="2.22.0" /> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.14" /> - <PackageReference Include="System.CodeDom" Version="9.0.14" /> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.14" /> - <PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.14" /> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.14" /> - <PackageReference Include="System.DirectoryServices" Version="9.0.14" /> + <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.15" /> + <PackageReference Include="System.CodeDom" Version="9.0.15" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> + <PackageReference Include="System.DirectoryServices" Version="9.0.15" /> <!--PackageReference Include="System.IO.FileSystem.AccessControl" Version="6.0.0-preview.5.21301.5" /--> - <PackageReference Include="System.Management" Version="9.0.14" /> + <PackageReference Include="System.Management" Version="9.0.15" /> <PackageReference Include="System.Security.AccessControl" Version="6.0.1" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.14" /> - <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.14" /> - <PackageReference Include="System.Security.Permissions" Version="9.0.14" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.14" /> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.15" /> + <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.15" /> + <PackageReference Include="System.Security.Permissions" Version="9.0.15" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> <!-- the following package(s) are from the powershell org --> <PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" /> <PackageReference Include="Microsoft.PowerShell.Native" Version="7.4.0" /> <!-- Signing APIs --> <PackageReference Include="Microsoft.Security.Extensions" Version="1.4.0" /> - <PackageReference Include="System.Windows.Extensions" Version="9.0.14" /> + <PackageReference Include="System.Windows.Extensions" Version="9.0.15" /> </ItemGroup> <PropertyGroup> diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index b5bae18d946..bd18dde778f 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -10,18 +10,18 @@ <PackageReference Include="BenchmarkDotNet.Annotations" Version="0.14.0" /> <PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.14.0" /> <PackageReference Include="Iced" Version="1.21.0" /> - <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.14" /> + <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.15" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" /> <PackageReference Include="Microsoft.Diagnostics.NETCore.Client" Version="0.2.661903" /> <PackageReference Include="Microsoft.Diagnostics.Runtime" Version="3.1.512801" /> <PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.30" /> <PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.4" /> - <PackageReference Include="System.Collections.Immutable" Version="9.0.14" /> - <PackageReference Include="System.IO.Pipelines" Version="9.0.14" /> + <PackageReference Include="System.Collections.Immutable" Version="9.0.15" /> + <PackageReference Include="System.IO.Pipelines" Version="9.0.15" /> <PackageReference Include="System.Management" Version="8.0.0" /> <PackageReference Include="System.Reflection.Metadata" Version="8.0.1" /> - <PackageReference Include="System.Text.Encodings.Web" Version="9.0.14" /> - <PackageReference Include="System.Text.Json" Version="9.0.14" /> + <PackageReference Include="System.Text.Encodings.Web" Version="9.0.15" /> + <PackageReference Include="System.Text.Json" Version="9.0.15" /> </ItemGroup> <ItemGroup> diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index b76542f6002..f625a77d03a 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -10,7 +10,7 @@ <PackageReference Include="CommandLineParser" Version="2.9.1" /> <PackageReference Include="Iced" Version="1.21.0" /> <PackageReference Include="MarkdownLog.NS20" Version="0.10.1" /> - <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.14" /> + <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.15" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" /> <PackageReference Include="Microsoft.Diagnostics.NETCore.Client" Version="0.2.661903" /> <PackageReference Include="Microsoft.Diagnostics.Runtime" Version="3.1.512801" /> @@ -18,11 +18,11 @@ <PackageReference Include="Newtonsoft.Json" Version="13.0.4" /> <PackageReference Include="BenchmarkDotNet" Version="0.14.0" /> <PackageReference Include="Perfolizer" Version="0.4.0" /> - <PackageReference Include="System.Collections.Immutable" Version="9.0.14" /> - <PackageReference Include="System.IO.Pipelines" Version="9.0.14" /> + <PackageReference Include="System.Collections.Immutable" Version="9.0.15" /> + <PackageReference Include="System.IO.Pipelines" Version="9.0.15" /> <PackageReference Include="System.Management" Version="8.0.0" /> <PackageReference Include="System.Reflection.Metadata" Version="8.0.1" /> - <PackageReference Include="System.Text.Encodings.Web" Version="9.0.14" /> - <PackageReference Include="System.Text.Json" Version="9.0.14" /> + <PackageReference Include="System.Text.Encodings.Web" Version="9.0.15" /> + <PackageReference Include="System.Text.Json" Version="9.0.15" /> </ItemGroup> </Project> diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index a76f1675d61..c3d9b71a150 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -17,22 +17,22 @@ <PackageReference Include="Microsoft.ApplicationInsights" Version="2.22.0" /> <PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> <PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" /> - <PackageReference Include="Microsoft.PowerShell.CoreCLR.Eventing" Version="7.5.4" /> + <PackageReference Include="Microsoft.PowerShell.CoreCLR.Eventing" Version="7.5.5" /> <PackageReference Include="Microsoft.PowerShell.Native" Version="7.4.0" /> <PackageReference Include="Microsoft.Security.Extensions" Version="1.3.0" /> - <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.14" /> + <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.15" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.4" /> - <PackageReference Include="System.CodeDom" Version="9.0.14" /> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.14" /> - <PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.14" /> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.14" /> - <PackageReference Include="System.DirectoryServices" Version="9.0.14" /> - <PackageReference Include="System.Management" Version="9.0.14" /> + <PackageReference Include="System.CodeDom" Version="9.0.15" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> + <PackageReference Include="System.DirectoryServices" Version="9.0.15" /> + <PackageReference Include="System.Management" Version="9.0.15" /> <PackageReference Include="System.Management.Automation" Version="7.5.0-preview.5" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.14" /> - <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.14" /> - <PackageReference Include="System.Security.Permissions" Version="9.0.14" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.14" /> - <PackageReference Include="System.Windows.Extensions" Version="9.0.14" /> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.15" /> + <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.15" /> + <PackageReference Include="System.Security.Permissions" Version="9.0.15" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> + <PackageReference Include="System.Windows.Extensions" Version="9.0.15" /> </ItemGroup> </Project> diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 850888b41ff..f7e29ff7745 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,57 +15,57 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.14" /> - <PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.14" /> - <PackageReference Include="Microsoft.Windows.Compatibility" Version="9.0.14" /> - <PackageReference Include="runtime.android-arm.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.android-arm64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.android-x64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.android-x86.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-arm.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-arm64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-bionic-arm64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-bionic-x64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-musl-arm.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-musl-arm64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-musl-x64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.linux-x64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.maccatalyst-arm64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.maccatalyst-x64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.osx-arm64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="runtime.osx-x64.runtime.native.System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="System.CodeDom" Version="9.0.14" /> - <PackageReference Include="System.ComponentModel.Composition" Version="9.0.14" /> - <PackageReference Include="System.ComponentModel.Composition.Registration" Version="9.0.14" /> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.14" /> - <PackageReference Include="System.Data.Odbc" Version="9.0.14" /> - <PackageReference Include="System.Data.OleDb" Version="9.0.14" /> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.14" /> - <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.14" /> - <PackageReference Include="System.DirectoryServices" Version="9.0.14" /> - <PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.14" /> - <PackageReference Include="System.DirectoryServices.Protocols" Version="9.0.14" /> - <PackageReference Include="System.Drawing.Common" Version="9.0.14" /> - <PackageReference Include="System.Formats.Asn1" Version="9.0.14" /> + <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.15" /> + <PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.15" /> + <PackageReference Include="Microsoft.Windows.Compatibility" Version="9.0.15" /> + <PackageReference Include="runtime.android-arm.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.android-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.android-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.android-x86.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-arm.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-bionic-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-bionic-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-musl-arm.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-musl-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-musl-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.linux-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.maccatalyst-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.maccatalyst-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.osx-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="runtime.osx-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="System.CodeDom" Version="9.0.15" /> + <PackageReference Include="System.ComponentModel.Composition" Version="9.0.15" /> + <PackageReference Include="System.ComponentModel.Composition.Registration" Version="9.0.15" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.15" /> + <PackageReference Include="System.Data.Odbc" Version="9.0.15" /> + <PackageReference Include="System.Data.OleDb" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.15" /> + <PackageReference Include="System.DirectoryServices" Version="9.0.15" /> + <PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.15" /> + <PackageReference Include="System.DirectoryServices.Protocols" Version="9.0.15" /> + <PackageReference Include="System.Drawing.Common" Version="9.0.15" /> + <PackageReference Include="System.Formats.Asn1" Version="9.0.15" /> <PackageReference Include="System.Data.SqlClient" Version="4.9.1" /> - <PackageReference Include="System.IO.Packaging" Version="9.0.14" /> - <PackageReference Include="System.IO.Ports" Version="9.0.14" /> - <PackageReference Include="System.Management" Version="9.0.14" /> - <PackageReference Include="System.Reflection.Context" Version="9.0.14" /> - <PackageReference Include="System.Runtime.Caching" Version="9.0.14" /> + <PackageReference Include="System.IO.Packaging" Version="9.0.15" /> + <PackageReference Include="System.IO.Ports" Version="9.0.15" /> + <PackageReference Include="System.Management" Version="9.0.15" /> + <PackageReference Include="System.Reflection.Context" Version="9.0.15" /> + <PackageReference Include="System.Runtime.Caching" Version="9.0.15" /> <PackageReference Include="System.Security.AccessControl" Version="6.0.1" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.14" /> - <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.14" /> - <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.14" /> - <PackageReference Include="System.Security.Permissions" Version="9.0.14" /> - <PackageReference Include="System.ServiceModel.Syndication" Version="9.0.14" /> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.14" /> - <PackageReference Include="System.Speech" Version="9.0.14" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.14" /> - <PackageReference Include="System.Threading.AccessControl" Version="9.0.14" /> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.15" /> + <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.15" /> + <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.15" /> + <PackageReference Include="System.Security.Permissions" Version="9.0.15" /> + <PackageReference Include="System.ServiceModel.Syndication" Version="9.0.15" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.15" /> + <PackageReference Include="System.Speech" Version="9.0.15" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> + <PackageReference Include="System.Threading.AccessControl" Version="9.0.15" /> <PackageReference Include="System.Web.Services.Description" Version="8.0.0" /> - <PackageReference Include="System.Windows.Extensions" Version="9.0.14" /> + <PackageReference Include="System.Windows.Extensions" Version="9.0.15" /> </ItemGroup> </Project> diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index e68b3df38da..51420e6d140 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,10 +7,10 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="9.0.14" /> - <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.14" /> + <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="9.0.15" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.15" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.4" /> <PackageReference Include="Newtonsoft.Json.Bson" Version="1.0.3" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.14" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> </ItemGroup> </Project> diff --git a/tools/cgmanifest/main/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json index 242178a883d..380112e0d90 100644 --- a/tools/cgmanifest/main/cgmanifest.json +++ b/tools/cgmanifest/main/cgmanifest.json @@ -86,7 +86,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -116,7 +116,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -156,7 +156,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -166,7 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -176,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -196,7 +196,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -206,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -216,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -226,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -236,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -246,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -256,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -266,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -276,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -286,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -296,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -306,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -316,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -326,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -346,7 +346,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -356,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -366,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -426,7 +426,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -446,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -456,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -466,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -476,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -486,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -506,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.DiagnosticSource", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -516,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -526,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -536,7 +536,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -546,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -556,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -566,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -576,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -586,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -596,7 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -606,7 +606,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -636,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -656,7 +656,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Metadata", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -666,7 +666,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -686,7 +686,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -696,7 +696,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -706,7 +706,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -716,7 +716,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -786,7 +786,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -796,7 +796,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -806,7 +806,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -816,7 +816,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encoding.CodePages", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -826,7 +826,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encodings.Web", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -836,7 +836,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false @@ -856,7 +856,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.14" + "Version": "9.0.15" } }, "DevelopmentDependency": false From bf86c403eb6c04d71cb69058ae0af33ac275e7b3 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Thu, 16 Apr 2026 16:52:37 -0700 Subject: [PATCH 254/275] Update the `ThirdPartyNotices.txt` for v7.5.6 release (#27288) --- ThirdPartyNotices.txt | 170 ++++++++++++++++++++++-------------------- 1 file changed, 90 insertions(+), 80 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index ce31689d1f0..8613f4da30e 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -156,19 +156,22 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Bcl.AsyncInterfaces 8.0.0 - MIT +Microsoft.Bcl.AsyncInterfaces 9.0.10 - MIT +Copyright (c) 2021 Copyright (c) Six Labors (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -178,23 +181,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -202,12 +206,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -284,7 +288,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 8.0.19 - MIT +Microsoft.Extensions.ObjectPool 9.0.10 - MIT Copyright Jorn Zaefferer @@ -374,7 +378,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Win32.Registry.AccessControl 9.0.8 - MIT +Microsoft.Win32.Registry.AccessControl 9.0.10 - MIT Copyright (c) 2021 @@ -464,7 +468,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Win32.SystemEvents 9.0.8 - MIT +Microsoft.Win32.SystemEvents 9.0.10 - MIT Copyright (c) 2021 @@ -554,7 +558,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Windows.Compatibility 9.0.8 - MIT +Microsoft.Windows.Compatibility 9.0.10 - MIT (c) Microsoft Corporation @@ -573,7 +577,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Newtonsoft.Json 13.0.3 - MIT +Newtonsoft.Json 13.0.4 - MIT Copyright James Newton-King 2008 @@ -607,7 +611,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.android-arm.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.android-arm.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -697,7 +701,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-arm64.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.android-arm64.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -787,7 +791,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x64.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.android-x64.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -877,7 +881,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x86.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.android-x86.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -967,7 +971,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.linux-arm.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -1057,7 +1061,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -1147,7 +1151,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -1237,7 +1241,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -1327,7 +1331,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -1417,7 +1421,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -1507,7 +1511,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -1597,7 +1601,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-x64.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.linux-x64.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -1687,7 +1691,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -1777,7 +1781,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -1912,7 +1916,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -2002,7 +2006,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -2092,7 +2096,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-x64.runtime.native.System.IO.Ports 9.0.8 - MIT +runtime.osx-x64.runtime.native.System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -2182,7 +2186,7 @@ SOFTWARE. --------------------------------------------------------- -System.CodeDom 9.0.8 - MIT +System.CodeDom 9.0.10 - MIT Copyright (c) 2021 @@ -2358,7 +2362,7 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition 9.0.8 - MIT +System.ComponentModel.Composition 9.0.10 - MIT Copyright (c) 2021 @@ -2448,7 +2452,7 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition.Registration 9.0.8 - MIT +System.ComponentModel.Composition.Registration 9.0.10 - MIT Copyright (c) 2021 @@ -2538,7 +2542,7 @@ SOFTWARE. --------------------------------------------------------- -System.Configuration.ConfigurationManager 9.0.8 - MIT +System.Configuration.ConfigurationManager 9.0.10 - MIT Copyright (c) 2021 @@ -2628,7 +2632,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.Odbc 9.0.8 - MIT +System.Data.Odbc 9.0.10 - MIT Copyright (c) 2021 @@ -2718,7 +2722,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.OleDb 9.0.8 - MIT +System.Data.OleDb 9.0.10 - MIT Copyright (c) 2021 @@ -2827,7 +2831,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Diagnostics.DiagnosticSource 9.0.8 - MIT +System.Diagnostics.DiagnosticSource 9.0.10 - MIT Copyright (c) 2021 @@ -2917,7 +2921,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.EventLog 9.0.8 - MIT +System.Diagnostics.EventLog 9.0.10 - MIT Copyright (c) 2021 @@ -3007,7 +3011,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.PerformanceCounter 9.0.8 - MIT +System.Diagnostics.PerformanceCounter 9.0.10 - MIT Copyright (c) 2021 @@ -3097,7 +3101,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices 9.0.8 - MIT +System.DirectoryServices 9.0.10 - MIT Copyright (c) 2021 @@ -3187,7 +3191,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.AccountManagement 9.0.8 - MIT +System.DirectoryServices.AccountManagement 9.0.10 - MIT Copyright (c) 2021 @@ -3277,7 +3281,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.Protocols 9.0.8 - MIT +System.DirectoryServices.Protocols 9.0.10 - MIT Copyright (c) 2021 @@ -3367,7 +3371,7 @@ SOFTWARE. --------------------------------------------------------- -System.Drawing.Common 9.0.8 - MIT +System.Drawing.Common 9.0.10 - MIT (c) Microsoft Corporation @@ -3402,7 +3406,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Packaging 9.0.8 - MIT +System.IO.Packaging 9.0.10 - MIT Copyright (c) 2021 @@ -3492,7 +3496,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Ports 9.0.8 - MIT +System.IO.Ports 9.0.10 - MIT Copyright (c) 2021 @@ -3582,7 +3586,7 @@ SOFTWARE. --------------------------------------------------------- -System.Management 9.0.8 - MIT +System.Management 9.0.10 - MIT Copyright (c) 2021 @@ -3672,7 +3676,7 @@ SOFTWARE. --------------------------------------------------------- -System.Net.Http.WinHttpHandler 9.0.8 - MIT +System.Net.Http.WinHttpHandler 9.0.10 - MIT Copyright (c) 2021 @@ -3816,7 +3820,7 @@ System.Private.ServiceModel 4.10.3 - MIT (c) Microsoft Corporation Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) +Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) Provided The MIT License (MIT) @@ -3847,7 +3851,7 @@ SOFTWARE. --------------------------------------------------------- -System.Reflection.Context 9.0.8 - MIT +System.Reflection.Context 9.0.10 - MIT Copyright (c) 2021 @@ -3990,20 +3994,23 @@ SOFTWARE. --------------------------------------------------------- -System.Reflection.Metadata 8.0.1 - MIT +System.Reflection.Metadata 9.0.10 - MIT +Copyright (c) 2021 Copyright (c) Six Labors Gets the Copyright Table (c) Microsoft Corporation +Copyright (c) 2022 FormatJS Copyright (c) Andrew Arnott Copyright 2019 LLVM Project +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson -Copyright (c) 1998 Microsoft. To +Copyright (c) 2015 Andrew Gallant Copyright (c) 2022, Wojciech Mula Copyright (c) 2017 Yoshifumi Kawai Copyright (c) 2022, Geoff Langdale @@ -4013,23 +4020,24 @@ Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors Copyright (c) 1999 Lucent Technologies Copyright (c) 2008-2016, Wojciech Mula Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2021 csFastFloat authors +Copyright (c) 2015-2018, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2011-2015 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors +(c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich @@ -4037,12 +4045,12 @@ Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California @@ -4077,7 +4085,7 @@ SOFTWARE. --------------------------------------------------------- -System.Runtime.Caching 9.0.8 - MIT +System.Runtime.Caching 9.0.10 - MIT Copyright (c) 2021 @@ -4242,7 +4250,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Pkcs 9.0.8 - MIT +System.Security.Cryptography.Pkcs 9.0.10 - MIT Copyright (c) 2021 @@ -4332,7 +4340,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.ProtectedData 9.0.8 - MIT +System.Security.Cryptography.ProtectedData 9.0.10 - MIT Copyright (c) 2021 @@ -4422,7 +4430,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Xml 9.0.8 - MIT +System.Security.Cryptography.Xml 9.0.10 - MIT Copyright (c) 2021 @@ -4512,7 +4520,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Permissions 9.0.8 - MIT +System.Security.Permissions 9.0.10 - MIT Copyright (c) 2021 @@ -4605,42 +4613,44 @@ SOFTWARE. System.Security.Principal.Windows 5.0.0 - MIT -(c) Microsoft Corporation. +(c) Microsoft Corporation Copyright (c) Andrew Arnott +Copyright (c) 1998 Microsoft Copyright 2018 Daniel Lemire -Copyright 2012 the V8 project -Copyright (c) .NET Foundation. +Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. -Copyright (c) 1998 Microsoft. To -(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 2020 Dan Shechter +(c) 1997-2005 Sean Eron Anderson Copyright (c) 2017 Yoshifumi Kawai Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 2012-2014, Yann Collet +Copyright (c) 1991-2020 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright 2012 the V8 project authors +Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, Wojciech Mula Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin -Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. -Copyright (c) The Internet Society 1997. +Copyright (c) The Internet Society 1997 Copyright (c) 2004-2006 Intel Corporation Copyright (c) 2013-2017, Milosz Krajewski Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors -Copyright (c) The Internet Society (2003). Copyright (c) .NET Foundation and Contributors Copyright (c) 2011 Novell, Inc (http://www.novell.com) Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California. -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To +Portions (c) International Organization for Standardization 1986 +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass The MIT License (MIT) @@ -4851,7 +4861,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Syndication 9.0.8 - MIT +System.ServiceModel.Syndication 9.0.10 - MIT Copyright (c) 2021 @@ -4941,7 +4951,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceProcess.ServiceController 9.0.8 - MIT +System.ServiceProcess.ServiceController 9.0.10 - MIT Copyright (c) 2021 @@ -5031,7 +5041,7 @@ SOFTWARE. --------------------------------------------------------- -System.Speech 9.0.8 - MIT +System.Speech 9.0.10 - MIT Copyright (c) 2021 @@ -5121,7 +5131,7 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encoding.CodePages 9.0.8 - MIT +System.Text.Encoding.CodePages 9.0.10 - MIT Copyright (c) 2021 @@ -5211,7 +5221,7 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encodings.Web 9.0.8 - MIT +System.Text.Encodings.Web 9.0.10 - MIT Copyright (c) 2021 @@ -5301,7 +5311,7 @@ SOFTWARE. --------------------------------------------------------- -System.Threading.AccessControl 9.0.8 - MIT +System.Threading.AccessControl 9.0.10 - MIT Copyright (c) 2021 @@ -5427,7 +5437,7 @@ SOFTWARE. --------------------------------------------------------- -System.Windows.Extensions 9.0.8 - MIT +System.Windows.Extensions 9.0.10 - MIT Copyright (c) 2021 From 93cc9e6d155939c0d4899751950173935a517a96 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Fri, 17 Apr 2026 11:08:05 -0700 Subject: [PATCH 255/275] Update changelog for the v7.5.6 release (#27274) --- CHANGELOG/7.5.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index 2e34970c248..326652821cc 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -1,5 +1,54 @@ # 7.5 Changelog +## [7.5.6] + +### General Cmdlet Updates and Fixes + +- Delay update notification for one week to ensure all packages become available (#27220) + +### Tests + +- Fix the `PSNativeCommandArgumentPassing` test (#27166) + +### Build and Packaging Improvements + +<details> + +<summary> + +<p>Update to .NET SDK 9.0.313</p> + +</summary> + +<ul> +<li>Update branch for the v7.5.6 release (#27268)</li> +<li>Fix package pipeline by adding in <code>PDP-Media</code> directory (#27256)</li> +<li>Pin <code>ready-to-merge.yml</code> reusable workflow to commit SHA (#27246)</li> +<li>[StepSecurity] ci: Harden GitHub Actions tags (#27239)</li> +<li>Build, package, and create VPack for the PowerShell-LTS store package within the same <code>msixbundle-vpack</code> pipeline (#27240)</li> +<li>Add comment-based help documentation to <code>build.psm1</code> functions (#27221)</li> +<li>Separate store package creation, skip polling for store publish, clean up <code>PDP-Media</code> (#27225)</li> +<li>[StepSecurity] ci: Harden GitHub Actions tokens (#27224)</li> +<li>Change the display name of "PowerShell-LTS" package to "PowerShell LTS" (#27223)</li> +<li>Redo windows image fix to use latest image (#27222)</li> +<li>Bump <code>github/codeql-action</code> from 4.32.4 to 4.35.1 (#27159) (#27170) (#27174)</li> +<li>Select new MSIX package name (#27172)</li> +<li>Update the <code>PhoneProductId</code> to be the official LTS id used by Store (#27168)</li> +<li>release-upload-buildinfo: replace version-comparison channel gating with metadata flags (#27167)</li> +<li>Create infrastructure to create two msixs and msixbundles for LTS and Stable (#27165)</li> +<li>Move <code>_GetDependencies</code> MSBuild target from dynamic generation in <code>build.psm1</code> into <code>Microsoft.PowerShell.SDK.csproj</code> (#27164)</li> +<li>Create Linux LTS deb/rpm packages for LTS releases (#27163)</li> +<li>Fix the container image for vPack, MSIX vPack and Package pipelines (#27161)</li> +<li>Create LTS pkg and non-LTS pkg for macOS for LTS releases (#27162)</li> +<li>Bump actions/dependency-review-action from 4.8.3 to 4.9.0 (#27158)</li> +<li>Bump actions/upload-artifact from 6 to 7 (#27157)</li> +<li>Separate "Official" and "NonOfficial" templates for ADO pipelines (#27155)</li> +</ul> + +</details> + +[7.5.6]: https://github.com/PowerShell/PowerShell/compare/v7.5.5...v7.5.6 + ## [7.5.5] ### Engine Updates and Fixes From 1a9cf72ab97bc8caa3a77ca3b022cf1b53b10aca Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Tue, 21 Apr 2026 13:50:42 -0700 Subject: [PATCH 256/275] [release/v7.5.6] PMC release: Use slash instead of back-slash for Linux container (#27318) --- .pipelines/templates/release-prep-for-ev2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml index e644bece68f..f73caa10450 100644 --- a/.pipelines/templates/release-prep-for-ev2.yml +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -23,7 +23,7 @@ stages: - group: 'mscodehub-code-read-akv' - group: 'packages.microsoft.com' - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json steps: - checkout: self ## the global setting on lfs didn't work lfs: false From 44feecc08f9fc2bd95c7fc15770469ec54c8c4e1 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Wed, 22 Apr 2026 16:02:13 -0500 Subject: [PATCH 257/275] Flip Stable PublishToChannel false for v7.5.X (#27333) Co-authored-by: Justin Chung <chungjustin@microsoft.com> --- tools/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/metadata.json b/tools/metadata.json index 3d8ba1203fc..7a17e770119 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -6,5 +6,5 @@ "LTSReleaseTag" : ["v7.4.13"], "NextReleaseTag": "v7.5.0-preview.4", "LTSRelease": { "PublishToChannels": false, "Package": false }, - "StableRelease": { "PublishToChannels": true, "Package": true } + "StableRelease": { "PublishToChannels": false, "Package": true } } From 7e75c3e86c199780fb233d56b039bed471e2363e Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 22 Apr 2026 15:16:19 -0700 Subject: [PATCH 258/275] [release/v7.5.6] Download PMC Packages through `TemplateContext` (#27335) --- .../PowerShell-Release-Azure-NonOfficial.yml | 8 ++- .../PowerShell-Release-Official-Azure.yml | 2 +- .pipelines/templates/release-prep-for-ev2.yml | 46 ++++++------- .pipelines/templates/release-publish-pmc.yml | 65 ++++++++++++------- 4 files changed, 70 insertions(+), 51 deletions(-) diff --git a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml index b524cb0ff81..10dbf8aa6b8 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml @@ -67,10 +67,16 @@ extends: exactToolVersion: 4.4.2 policheck: break: true # always break the build on policheck issues. You can disable it by setting to 'false' - tsaOptionsFile: .config\tsaoptions.json + tsaOptionsFile: $(Build.SourcesDirectory)\.config\tsaoptions.json stages: - template: /.pipelines/templates/release-prep-for-ev2.yml@self parameters: skipPublish: ${{ parameters.skipPublish }} + # NonOfficial: run the publish stage to verify templateContext artifact download, + # but skip the actual Ev2 push to PMC. - template: /.pipelines/templates/release-publish-pmc.yml@self + parameters: + releaseEnvironment: Test + stagePrefix: Test + skipEv2Push: true diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index 24040a2463d..b5f57438925 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -67,7 +67,7 @@ extends: exactToolVersion: 4.4.2 policheck: break: true # always break the build on policheck issues. You can disable it by setting to 'false' - tsaOptionsFile: .config\tsaoptions.json + tsaOptionsFile: $(Build.SourcesDirectory)\.config\tsaoptions.json stages: - template: /.pipelines/templates/release-prep-for-ev2.yml@self parameters: diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml index f73caa10450..3ad716a3af4 100644 --- a/.pipelines/templates/release-prep-for-ev2.yml +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -11,6 +11,20 @@ stages: displayName: 'Copy EV2 Files to Artifact' pool: type: linux + templateContext: + inputs: + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_linux_package_deb + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_linux_package_rpm + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_linux_package_mariner_x64 + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_linux_package_mariner_arm64 variables: - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' @@ -24,6 +38,8 @@ stages: - group: 'packages.microsoft.com' - name: ob_sdl_credscan_suppressionsFile value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)/PowerShell/.config/tsaoptions.json steps: - checkout: self ## the global setting on lfs didn't work lfs: false @@ -99,39 +115,17 @@ stages: env: ob_restore_phase: true - - download: PSPackagesOfficial - artifact: 'drop_linux_package_deb' - displayName: 'Download artifact containing .deb_amd64.deb file from PSPackagesOfficial triggering pipeline' - env: - ob_restore_phase: true - - - download: PSPackagesOfficial - artifact: 'drop_linux_package_rpm' - displayName: 'Download artifact containing .rh.x64_86.rpm file from PSPackagesOfficial triggering pipeline' - env: - ob_restore_phase: true - - - download: PSPackagesOfficial - artifact: 'drop_linux_package_mariner_x64' - displayName: 'Download artifact containing .cm.x86_64.rpm file from PSPackagesOfficial triggering pipeline' - env: - ob_restore_phase: true - - - download: PSPackagesOfficial - artifact: 'drop_linux_package_mariner_arm64' - displayName: 'Download artifact containing .cm.aarch64.rpm file from PSPackagesOfficial triggering pipeline' - env: - ob_restore_phase: true - - pwsh: | Write-Verbose -Verbose "Copy ESRP signed .deb and .rpm packages" - $downloadedPipelineFolder = Join-Path '$(Pipeline.Workspace)' -ChildPath 'PSPackagesOfficial' + # templateContext.inputs places the PSPackagesOfficial pipelineArtifact files + # directly under $(Pipeline.Workspace), not in per-artifact subfolders. + $downloadedPipelineFolder = '$(Pipeline.Workspace)' $srcFilesFolder = Join-Path -Path '$(Pipeline.Workspace)' -ChildPath 'SourceFiles' New-Item -Path $srcFilesFolder -ItemType Directory $packagesFolder = Join-Path -Path $srcFilesFolder -ChildPath 'packages' New-Item -Path $packagesFolder -ItemType Directory - $packageFiles = Get-ChildItem -Path $downloadedPipelineFolder -Recurse -Directory -Filter "drop_*" | Get-ChildItem -File -Include *.deb, *.rpm + $packageFiles = Get-ChildItem -Path $downloadedPipelineFolder -File | Where-Object { $_.Extension -in '.deb', '.rpm' } foreach ($file in $packageFiles) { Write-Verbose -Verbose "copying file: $($file.FullName)" diff --git a/.pipelines/templates/release-publish-pmc.yml b/.pipelines/templates/release-publish-pmc.yml index d5454845211..dc7fc8534e3 100644 --- a/.pipelines/templates/release-publish-pmc.yml +++ b/.pipelines/templates/release-publish-pmc.yml @@ -1,37 +1,56 @@ +parameters: +- name: releaseEnvironment + type: string + default: Production + values: + - Production + - PPE + - Test +- name: approvalServiceEnvironment + type: string + default: Production + values: + - Production + - PPE + - Test +# OneBranch requires the stage name to be prefixed with the release environment. +# Official uses 'Prod' for Production; NonProd validators require '<env>' (e.g. 'Test', 'PPE'). +- name: stagePrefix + type: string + default: Prod +# When true, the Ev2 push step is skipped. Useful for NonOfficial dry-runs that +# only want to validate artifact download via templateContext.inputs. +- name: skipEv2Push + type: boolean + default: false + stages: -- stage: 'Prod_Release' +- stage: ${{ parameters.stagePrefix }}_Release displayName: 'Deploy packages to PMC with EV2' dependsOn: - PrepForEV2 variables: - name: ob_release_environment - value: "Production" + value: ${{ parameters.releaseEnvironment }} - name: repoRoot value: $(Build.SourcesDirectory) jobs: - - job: Prod_ReleaseJob + - job: ${{ parameters.stagePrefix }}_ReleaseJob displayName: Publish to PMC pool: type: release - - steps: - - task: DownloadPipelineArtifact@2 + templateContext: inputs: - targetPath: '$(Pipeline.Workspace)' - artifact: drop_PrepForEV2_CopyEv2FilesToArtifact - displayName: 'Download drop_PrepForEV2_CopyEv2FilesToArtifact artifact that has all files needed' + - input: pipelineArtifact + artifactName: drop_PrepForEV2_CopyEv2FilesToArtifact - - task: DownloadPipelineArtifact@2 - inputs: - buildType: 'current' - targetPath: '$(Pipeline.Workspace)' - displayName: 'Download to get EV2 Files' - - - task: vsrm-ev2.vss-services-ev2.adm-release-task.ExpressV2Internal@1 - displayName: 'Ev2: Push to PMC' - inputs: - UseServerMonitorTask: true - EndpointProviderType: ApprovalService - ApprovalServiceEnvironment: Production - ServiceRootPath: '$(Pipeline.Workspace)/drop_PrepForEV2_CopyEV2FilesToArtifact/EV2Specs/ServiceGroupRoot' - RolloutSpecPath: '$(Pipeline.Workspace)/drop_PrepForEV2_CopyEV2FilesToArtifact/EV2Specs/ServiceGroupRoot/RolloutSpec.json' + steps: + - ${{ if not(parameters.skipEv2Push) }}: + - task: vsrm-ev2.vss-services-ev2.adm-release-task.ExpressV2Internal@1 + displayName: 'Ev2: Push to PMC' + inputs: + UseServerMonitorTask: true + EndpointProviderType: ApprovalService + ApprovalServiceEnvironment: ${{ parameters.approvalServiceEnvironment }} + ServiceRootPath: '$(Pipeline.Workspace)/EV2Specs/ServiceGroupRoot' + RolloutSpecPath: '$(Pipeline.Workspace)/EV2Specs/ServiceGroupRoot/RolloutSpec.json' From d94e21159a2eb670dbbbd04d6acdc747592db912 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Mon, 18 May 2026 10:35:46 -0700 Subject: [PATCH 259/275] [release/v7.5.7] Fix checks for local user config file paths (#27459) Co-authored-by: Patrick Meinecke <SeeminglyScience@users.noreply.github.com> --- .../host/msh/ConsoleHost.cs | 13 ++++-- .../host/msh/UpdatesNotification.cs | 4 +- .../CoreCLR/CorePsPlatform.cs | 46 +++++++++++++++++-- .../engine/CommandDiscovery.cs | 10 +++- .../engine/Modules/AnalysisCache.cs | 7 ++- .../engine/PSConfiguration.cs | 10 +++- .../engine/hostifaces/HostUtilities.cs | 9 ++-- .../engine/hostifaces/MshHostUserInterface.cs | 5 ++ .../utils/Telemetry.cs | 5 +- 9 files changed, 90 insertions(+), 19 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index 8fc815f59e6..f454ab51e1d 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -153,13 +153,16 @@ internal static int Start( try { string profileDir = Platform.CacheDirectory; -#if !UNIX - if (!Directory.Exists(profileDir)) + if (!string.IsNullOrEmpty(profileDir)) { - Directory.CreateDirectory(profileDir); - } +#if !UNIX + if (!Directory.Exists(profileDir)) + { + Directory.CreateDirectory(profileDir); + } #endif - ProfileOptimization.SetProfileRoot(profileDir); + ProfileOptimization.SetProfileRoot(profileDir); + } } catch { diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs index d0b1ed4572c..eb4557c04d2 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs @@ -60,12 +60,12 @@ internal static class UpdatesNotification static UpdatesNotification() { s_notificationType = GetNotificationType(); - CanNotifyUpdates = s_notificationType != NotificationType.Off; + CanNotifyUpdates = s_notificationType != NotificationType.Off + && Platform.TryDeriveFromCache(PSVersionInfo.GitCommitId, out s_cacheDirectory); if (CanNotifyUpdates) { s_enumOptions = new EnumerationOptions(); - s_cacheDirectory = Path.Combine(Platform.CacheDirectory, PSVersionInfo.GitCommitId); // Build the template/pattern strings for the configured notification type. string typeNum = ((int)s_notificationType).ToString(); diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index dc5db5f2c48..530493f320a 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -167,8 +167,13 @@ public static bool IsStaSupported internal static readonly string ConfigDirectory = Platform.SelectProductNameForDirectory(Platform.XDG_Type.CONFIG); #else // Gets the location for cache and config folders. - internal static readonly string CacheDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Microsoft\PowerShell"; - internal static readonly string ConfigDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\PowerShell"; + internal static readonly string CacheDirectory = SafeDeriveFromSpecialFolder( + Environment.SpecialFolder.LocalApplicationData, + @"Microsoft\PowerShell"); + + internal static readonly string ConfigDirectory = SafeDeriveFromSpecialFolder( + Environment.SpecialFolder.Personal, + @"PowerShell"); private static readonly Lazy<bool> _isStaSupported = new Lazy<bool>(() => { @@ -189,6 +194,30 @@ public static bool IsStaSupported private static bool? _isWindowsDesktop = null; #endif + internal static bool TryDeriveFromCache(string path1, out string result) + { + if (CacheDirectory is null or []) + { + result = null; + return false; + } + + result = Path.Combine(CacheDirectory, path1); + return true; + } + + internal static bool TryDeriveFromCache(string path1, string path2, out string result) + { + if (CacheDirectory is null or []) + { + result = null; + return false; + } + + result = Path.Combine(CacheDirectory, path1, path2); + return true; + } + // format files internal static readonly string[] FormatFileNames = new string[] { @@ -218,6 +247,17 @@ internal static class CommonEnvVariableNames #endif } + private static string SafeDeriveFromSpecialFolder(Environment.SpecialFolder specialFolder, string subPath) + { + string basePath = Environment.GetFolderPath(specialFolder, Environment.SpecialFolderOption.DoNotVerify); + if (string.IsNullOrWhiteSpace(basePath)) + { + return string.Empty; + } + + return Path.Join(basePath, subPath); + } + #if UNIX private static string s_tempHome = null; @@ -360,7 +400,7 @@ internal static string GetFolderPath(Environment.SpecialFolder folder) _ => throw new NotSupportedException() }; #else - return Environment.GetFolderPath(folder); + return Environment.GetFolderPath(folder, Environment.SpecialFolderOption.DoNotVerify); #endif } diff --git a/src/System.Management.Automation/engine/CommandDiscovery.cs b/src/System.Management.Automation/engine/CommandDiscovery.cs index 561a33ccba8..e07520a1238 100644 --- a/src/System.Management.Automation/engine/CommandDiscovery.cs +++ b/src/System.Management.Automation/engine/CommandDiscovery.cs @@ -1218,11 +1218,17 @@ internal LookupPathCollection GetLookupDirectoryPaths() string tempDir = directory.TrimStart(); if (tempDir.EqualsOrdinalIgnoreCase("~")) { - tempDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + tempDir = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile, + Environment.SpecialFolderOption.DoNotVerify); } else if (tempDir.StartsWith("~" + Path.DirectorySeparatorChar)) { - tempDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + Path.DirectorySeparatorChar + tempDir.Substring(2); + tempDir = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile, + Environment.SpecialFolderOption.DoNotVerify) + + Path.DirectorySeparatorChar + + tempDir.Substring(2); } _cachedPath.Add(tempDir); diff --git a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs index a701b0745c8..39d9b586aa6 100644 --- a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs +++ b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs @@ -664,6 +664,11 @@ private static byte[] GetHeader() public void QueueSerialization() { + if (string.IsNullOrEmpty(s_cacheStoreLocation)) + { + return; + } + // We expect many modules to rapidly call for serialization. // Instead of doing it right away, we'll queue a task that starts writing // after it seems like we've stopped adding stuff to write out. This is @@ -1121,7 +1126,7 @@ static AnalysisCacheData() cacheFileName = string.Create(CultureInfo.InvariantCulture, $"{cacheFileName}-{hashString}"); } - s_cacheStoreLocation = Path.Combine(Platform.CacheDirectory, cacheFileName); + Platform.TryDeriveFromCache(cacheFileName, out s_cacheStoreLocation); } } diff --git a/src/System.Management.Automation/engine/PSConfiguration.cs b/src/System.Management.Automation/engine/PSConfiguration.cs index e321423f768..419a4cae95f 100644 --- a/src/System.Management.Automation/engine/PSConfiguration.cs +++ b/src/System.Management.Automation/engine/PSConfiguration.cs @@ -89,7 +89,10 @@ private PowerShellConfig() // Note: This directory may or may not exist depending upon the execution scenario. // Writes will attempt to create the directory if it does not already exist. perUserConfigDirectory = Platform.ConfigDirectory; - perUserConfigFile = Path.Combine(perUserConfigDirectory, ConfigFileName); + if (!string.IsNullOrEmpty(perUserConfigDirectory)) + { + perUserConfigFile = Path.Combine(perUserConfigDirectory, ConfigFileName); + } emptyConfig = new JObject(); configRoots = new JObject[2]; @@ -387,6 +390,11 @@ internal PSKeyword GetLogKeywords() private T ReadValueFromFile<T>(ConfigScope scope, string key, T defaultValue = default) { string fileName = GetConfigFilePath(scope); + if (string.IsNullOrEmpty(fileName)) + { + return defaultValue; + } + JObject configData = configRoots[(int)scope]; if (configData == null) diff --git a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs index 003625791b1..caf3c5e15d8 100644 --- a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs +++ b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs @@ -208,10 +208,11 @@ internal static string GetFullProfileFileName(string shellId, bool forCurrentUse else { basePath = GetAllUsersFolderPath(shellId); - if (string.IsNullOrEmpty(basePath)) - { - return string.Empty; - } + } + + if (string.IsNullOrEmpty(basePath)) + { + return string.Empty; } string profileName = useTestProfile ? "profile_test.ps1" : "profile.ps1"; diff --git a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs index 29fc5fa1f7f..5f51ba15751 100644 --- a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs +++ b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs @@ -1156,6 +1156,11 @@ internal static string GetTranscriptPath(string baseDirectory, bool includeDate) } } + if (string.IsNullOrEmpty(baseDirectory)) + { + return string.Empty; + } + if (includeDate) { baseDirectory = Path.Combine(baseDirectory, DateTime.Now.ToString("yyyyMMdd", CultureInfo.InvariantCulture)); diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index cffedb7c579..02851f26f9f 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -164,6 +164,8 @@ public static class ApplicationInsightsTelemetry private static readonly HashSet<string> s_knownSubsystemNames; + private static readonly string s_uuidPath; + /// <summary>Gets a value indicating whether telemetry can be sent.</summary> public static bool CanSendTelemetry { get; private set; } @@ -177,7 +179,8 @@ public static class ApplicationInsightsTelemetry static ApplicationInsightsTelemetry() { // If we can't send telemetry, there's no reason to do any of this - CanSendTelemetry = !GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false); + CanSendTelemetry = !GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false) + && Platform.TryDeriveFromCache("telemetry.uuid", out s_uuidPath); if (CanSendTelemetry) { s_sessionId = Guid.NewGuid().ToString(); From 2925a6ba69cbad93106b475936cf1813b104ae81 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Mon, 18 May 2026 10:36:00 -0700 Subject: [PATCH 260/275] [release/v7.5.7] Exclude .exe packages from publishing to GitHub (#27460) --- .pipelines/templates/release-githubNuget.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index 899e9bd572a..6d234ee50fe 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -35,6 +35,14 @@ jobs: targetType: inline script: | $Path = "$(Pipeline.Workspace)/GitHubPackages" + + # The .exe packages are for Windows Update only and should not be uploaded to GitHub release. + $exefiles = Get-ChildItem -Path $Path -Filter *.exe + if ($exefiles) { + Write-Verbose -Verbose "Remove .exe packages:" + $exefiles | Remove-Item -Force -Verbose + } + $OutputPath = Join-Path $Path 'hashes.sha256' $packages = Get-ChildItem -Path $Path -Include * -Recurse -File $checksums = $packages | From 0b2319fc5b7f93f38e58efc42cd95a4c3ab6d3a9 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Mon, 18 May 2026 10:36:12 -0700 Subject: [PATCH 261/275] [release/v7.5.7] Externalize `findMissingNotices` target framework selection with ordered Windows fallback (#27461) --- tools/findMissingNotices.ps1 | 115 +++++++++++++++++++++----- tools/findMissingNotices.targets.json | 5 ++ 2 files changed, 101 insertions(+), 19 deletions(-) create mode 100644 tools/findMissingNotices.targets.json diff --git a/tools/findMissingNotices.ps1 b/tools/findMissingNotices.ps1 index e5695fdf0d0..79a85ec0715 100644 --- a/tools/findMissingNotices.ps1 +++ b/tools/findMissingNotices.ps1 @@ -16,6 +16,45 @@ Import-Module "$PSScriptRoot\..\.github\workflows\GHWorkflowHelper" -Force . "$PSScriptRoot\..\tools\buildCommon\startNativeExecution.ps1" . "$PSScriptRoot\clearlyDefined\Find-LastHarvestedVersion.ps1" +$targetsConfigPath = Join-Path -Path $PSScriptRoot -ChildPath 'findMissingNotices.targets.json' +if (-not (Test-Path -LiteralPath $targetsConfigPath)) { + throw "Missing target framework config file '$targetsConfigPath'. Add '/tools/findMissingNotices.targets.json' with 'dotnetTargetName' and 'windowsTargetNames' entries." +} + +try { + $targetsConfig = Get-Content -LiteralPath $targetsConfigPath -Raw -ErrorAction Stop | ConvertFrom-Json -AsHashtable -ErrorAction Stop +} catch { + throw "Failed to load target framework config from '$targetsConfigPath'. Ensure the file contains valid JSON. Error: $($_.Exception.Message)" +} + +if ($targetsConfig -isnot [hashtable]) { + throw "Invalid target framework config '$targetsConfigPath': expected a JSON object with 'dotnetTargetName' and 'windowsTargetNames'." +} + +if (-not $targetsConfig.ContainsKey('dotnetTargetName') -or [string]::IsNullOrWhiteSpace($targetsConfig['dotnetTargetName'])) { + throw "Invalid target framework config '$targetsConfigPath': 'dotnetTargetName' must be a non-empty string." +} + +if (-not $targetsConfig.ContainsKey('windowsTargetNames')) { + throw "Invalid target framework config '$targetsConfigPath': 'windowsTargetNames' must be present and must be an array." +} + +if ($null -eq $targetsConfig['windowsTargetNames'] -or $targetsConfig['windowsTargetNames'] -isnot [array]) { + throw "Invalid target framework config '$targetsConfigPath': 'windowsTargetNames' must be an array (empty array is allowed)." +} + +$script:dotnetTargetName = [string]$targetsConfig['dotnetTargetName'] +$script:windowsTargetNames = @() +foreach ($windowsTargetName in $targetsConfig['windowsTargetNames']) { + if ($windowsTargetName -isnot [string] -or [string]::IsNullOrWhiteSpace($windowsTargetName)) { + throw "Invalid target framework config '$targetsConfigPath': every entry in 'windowsTargetNames' must be a non-empty string." + } + + $script:windowsTargetNames += $windowsTargetName +} + +# Empty windowsTargetNames is valid and means "use base target fallback only". + $packageSourceName = 'findMissingNoticesNugetOrg' if (!(Get-PackageSource -Name $packageSourceName -ErrorAction SilentlyContinue)) { $null = Register-PackageSource -Name $packageSourceName -Location https://www.nuget.org/api/v2 -ProviderName NuGet @@ -195,8 +234,7 @@ function Get-CGRegistrations { $registrationChanged = $false - $dotnetTargetName = 'net9.0' - $dotnetTargetNameWin7 = 'net9.0-windows8.0' + $baseTargetName = $script:dotnetTargetName $unixProjectName = 'powershell-unix' $windowsProjectName = 'powershell-win-core' $actualRuntime = $Runtime @@ -204,35 +242,30 @@ function Get-CGRegistrations { switch -regex ($Runtime) { "alpine-.*" { $folder = $unixProjectName - $target = "$dotnetTargetName|$Runtime" - $neutralTarget = "$dotnetTargetName" + $target = "$baseTargetName|$Runtime" + $neutralTarget = "$baseTargetName" } "linux-.*" { $folder = $unixProjectName - $target = "$dotnetTargetName|$Runtime" - $neutralTarget = "$dotnetTargetName" + $target = "$baseTargetName|$Runtime" + $neutralTarget = "$baseTargetName" } "osx-.*" { $folder = $unixProjectName - $target = "$dotnetTargetName|$Runtime" - $neutralTarget = "$dotnetTargetName" - } - "win-x*" { - $sdkToUse = $winDesktopSdk - $folder = $windowsProjectName - $target = "$dotnetTargetNameWin7|$Runtime" - $neutralTarget = "$dotnetTargetNameWin7" + $target = "$baseTargetName|$Runtime" + $neutralTarget = "$baseTargetName" } "win-.*" { + $sdkToUse = $winDesktopSdk $folder = $windowsProjectName - $target = "$dotnetTargetNameWin7|$Runtime" - $neutralTarget = "$dotnetTargetNameWin7" + $target = "$baseTargetName|$actualRuntime" + $neutralTarget = "$baseTargetName" } "modules" { $folder = "modules" $actualRuntime = 'linux-x64' - $target = "$dotnetTargetName|$actualRuntime" - $neutralTarget = "$dotnetTargetName" + $target = "$baseTargetName|$actualRuntime" + $neutralTarget = "$baseTargetName" } Default { throw "Invalid runtime name: $Runtime" @@ -247,6 +280,50 @@ function Get-CGRegistrations { dotnet restore --runtime $actualRuntime "/property:SDKToUse=$sdkToUse" } $null = New-PADrive -Path $PSScriptRoot\..\src\$folder\obj\project.assets.json -Name $folder + + if ($Runtime -like "win-*") { + # Windows target selection is optional and ordered: + # 1. Try full Windows TFMs from config in order. + # 2. Fall back to the base non-Windows TFM if present. + try { + $availableTargets = @(Get-ChildItem -Path "${folder}:/targets" -ErrorAction Stop | Select-Object -ExpandProperty Name) + } catch { + throw "Unable to enumerate available targets for runtime '$Runtime' in '$folder'. Ensure dotnet restore succeeded and project.assets.json contains target data. Error: $($_.Exception.Message)" + } + + $selectedTargetName = $null + + foreach ($windowsTargetName in $script:windowsTargetNames) { + if ($windowsTargetName -in $availableTargets) { + $selectedTargetName = $windowsTargetName + break + } + } + + if (-not $selectedTargetName -and $baseTargetName -in $availableTargets) { + Write-Verbose "No configured windows target matched for '$Runtime'. Falling back to base target '$baseTargetName'." -Verbose + $selectedTargetName = $baseTargetName + } + + if (-not $selectedTargetName) { + Write-Verbose "Available targets for '$folder': $($availableTargets -join ', ')" -Verbose + if ($script:windowsTargetNames.Count -eq 0) { + throw "Unable to find a target for '$Runtime'. Tried fallback base target '$baseTargetName' (no windowsTargetNames configured). Ensure project.assets.json contains this target or update dotnetTargetName in '$targetsConfigPath'." + } + + throw "Unable to find a target for '$Runtime'. Tried configured windowsTargetNames '$($script:windowsTargetNames -join "', '")' and fallback base target '$baseTargetName'. Update '$targetsConfigPath' with a valid windows target from the available list." + } + + $target = "$selectedTargetName|$actualRuntime" + $neutralTarget = $selectedTargetName + } + + # Defensive check: non-Windows paths set targets in the switch block, + # Windows path may override them after inspecting available assets targets. + if (-not $target -or -not $neutralTarget) { + throw "Unable to determine restore targets for runtime '$Runtime'." + } + try { $targets = Get-ChildItem -Path "${folder}:/targets/$target" -ErrorAction Stop | Where-Object { $_.Type -eq 'package' } | select-object -ExpandProperty name $targets += Get-ChildItem -Path "${folder}:/targets/$neutralTarget" -ErrorAction Stop | Where-Object { $_.Type -eq 'project' } | select-object -ExpandProperty name @@ -582,4 +659,4 @@ if (!$Fix -and $registrationChanged) { throw "cgmanifest is out of date. run ./tools/findMissingNotices.ps1 -Fix. Generated cgmanifest is here: $tempJson" } -Write-Verbose "$count registrations created!" -Verbose +Write-Verbose "$count registrations created!" -Verbose \ No newline at end of file diff --git a/tools/findMissingNotices.targets.json b/tools/findMissingNotices.targets.json new file mode 100644 index 00000000000..fdef552c603 --- /dev/null +++ b/tools/findMissingNotices.targets.json @@ -0,0 +1,5 @@ +{ + "dotnetTargetName": "net9.0", + "windowsTargetNames": [ + ] +} From 59d0306f131448db5b51c4d82e57411a7c2c8264 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Mon, 18 May 2026 10:36:26 -0700 Subject: [PATCH 262/275] [release/v7.5.7] Correct Variable Template Reference in NonOfficial Pipeline Templates (#27462) --- .github/agents/SplitADOPipelines.agent.md | 52 ++++++++++++------- ...Shell-Coordinated_Packages-NonOfficial.yml | 5 +- .../PowerShell-Packages-NonOfficial.yml | 4 +- .../PowerShell-Release-Azure-NonOfficial.yml | 2 +- .../PowerShell-Release-NonOfficial.yml | 4 +- .../PowerShell-vPack-NonOfficial.yml | 4 +- .../stages/PowerShell-vPack-Stages.yml | 2 +- 7 files changed, 45 insertions(+), 28 deletions(-) diff --git a/.github/agents/SplitADOPipelines.agent.md b/.github/agents/SplitADOPipelines.agent.md index 8322f473e7b..9454670061f 100644 --- a/.github/agents/SplitADOPipelines.agent.md +++ b/.github/agents/SplitADOPipelines.agent.md @@ -6,7 +6,7 @@ tools: ['vscode', 'execute', 'read', 'agent', 'edit', 'search', 'todo'] This agent will implement and restructure the repository's existing ADO pipelines into Official and NonOfficial pipelines. -A repository will have under the ./pipelines directory a series of yaml files that define the ADO pipelines for the repository. +A repository will have under the .pipelines directory a series of yaml files that define the ADO pipelines for the repository. First confirm if the pipelines are using a toggle switch for Official and NonOfficial. This will look something like this @@ -25,15 +25,31 @@ extends: This is an indicator that this work needs to be done. This toggle switch is no longer allowed and the templates need to be hard coded. +## Template Reference Convention (MUST follow) + +All `- template:` references to files **inside this repo** must use the **absolute** form anchored at the repo root, with the `@self` suffix: + +```yaml +- template: /.pipelines/templates/<path>/<file>.yml@self +``` + +Do **not** use relative paths such as `templates/...`, `../templates/...`, or bare filenames. Rationale: + +- Absolute paths resolve identically regardless of where the referring file lives, so moving a pipeline file between directories (for example, into `.pipelines/NonOfficial/`) does not silently break includes. +- Relative paths are resolved by Azure DevOps against the directory of the referring file, which has caused real outages in this repo when a relative include was composed into a nonexistent nested path like `.pipelines/templates/stages/.pipelines/templates/...`. +- The majority of existing includes already use the absolute form; keeping new work consistent reduces review burden. + +The only acceptable non-absolute references are to external repositories resolved via the `resources.repositories` block, for example `v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates`. + ## Refactoring Steps ### Step 1: Extract Shared Templates -For each pipeline file that uses the toggle switch pattern (e.g., `PowerShell-Packages.yml`): +For each pipeline file that uses the toggle switch pattern (e.g., `PowerShell-Packages-Official.yml`): -1. Create a `./pipelines/templates` directory if it doesn't exist -2. Extract the **variables section** into `./pipelines/templates/PowerShell-Packages-Variables.yml` -3. Extract the **stages section** into `./pipelines/templates/PowerShell-Packages-Stages.yml` +1. Create the `.pipelines/templates/variables` and `.pipelines/templates/stages` directories if they don't exist +2. Extract the **variables section** into `.pipelines/templates/variables/PowerShell-Packages-Variables.yml` +3. Extract the **stages section** into `.pipelines/templates/stages/PowerShell-Packages-Stages.yml` **IMPORTANT**: Only extract the `variables:` and `stages:` sections. All other sections (parameters, resources, extends, etc.) remain in the pipeline files. @@ -41,7 +57,7 @@ For each pipeline file that uses the toggle switch pattern (e.g., `PowerShell-Pa The original toggle-based file becomes the Official pipeline: -1. **Keep the file in its original location** (e.g., `./pipelines/PowerShell-Packages.yml` stays where it is) +1. **Keep the file in its original location** (e.g., `.pipelines/PowerShell-Packages-Official.yml` stays where it is) 2. Remove the toggle switch parameter (`templateFile` parameter) 3. Hard-code the Official template reference: ```yaml @@ -51,18 +67,18 @@ The original toggle-based file becomes the Official pipeline: 4. Replace the `variables:` section with a template reference: ```yaml variables: - - template: templates/PowerShell-Packages-Variables.yml + - template: /.pipelines/templates/variables/PowerShell-Packages-Variables.yml@self ``` 5. Replace the `stages:` section with a template reference: ```yaml stages: - - template: templates/PowerShell-Packages-Stages.yml + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self ``` ### Step 3: Create NonOfficial Pipeline -1. Create `./pipelines/NonOfficial` directory if it doesn't exist -2. Create the NonOfficial pipeline file (e.g., `./pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`) +1. Create `.pipelines/NonOfficial` directory if it doesn't exist +2. Create the NonOfficial pipeline file (e.g., `.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`) 3. Copy the structure from the refactored Official pipeline 4. Hard-code the NonOfficial template reference: ```yaml @@ -72,13 +88,13 @@ The original toggle-based file becomes the Official pipeline: 5. Reference the same shared templates: ```yaml variables: - - template: ../templates/PowerShell-Packages-Variables.yml + - template: /.pipelines/templates/variables/PowerShell-Packages-Variables.yml@self stages: - - template: ../templates/PowerShell-Packages-Stages.yml + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self ``` -**Note**: The NonOfficial pipeline uses `../templates/` because it's one directory deeper than the Official pipeline. +**Note**: Always use **absolute** template paths of the form `/.pipelines/templates/...@self`. Do not use relative paths like `templates/...` or `../templates/...`. Absolute paths are anchored at the repo root and resolve consistently from any referring file, preventing breakage when files are moved between directories. ### Step 4: Link NonOfficial Pipelines to NonOfficial Dependencies @@ -124,29 +140,29 @@ Then you must configure the `ob_release_environment` parameter when referencing #### Official Pipeline Configuration -In the Official pipeline (e.g., `./pipelines/PowerShell-Packages.yml`): +In the Official pipeline (e.g., `.pipelines/PowerShell-Packages-Official.yml`): ```yaml stages: - - template: templates/PowerShell-Packages-Stages.yml + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self parameters: ob_release_environment: Production ``` #### NonOfficial Pipeline Configuration -In the NonOfficial pipeline (e.g., `./pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`): +In the NonOfficial pipeline (e.g., `.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`): ```yaml stages: - - template: ../templates/PowerShell-Packages-Stages.yml + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self parameters: ob_release_environment: Test ``` #### Update Stages Template to Accept Parameter -The extracted stages template (e.g., `./pipelines/templates/PowerShell-Packages-Stages.yml`) must declare the parameter at the top: +The extracted stages template (e.g., `.pipelines/templates/stages/PowerShell-Packages-Stages.yml`) must declare the parameter at the top: ```yaml parameters: diff --git a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml index 0b417df5c05..69506750c34 100644 --- a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml @@ -45,7 +45,7 @@ resources: ref: refs/heads/main variables: - - template: ./pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml@self parameters: InternalSDKBlobURL: ${{ parameters.InternalSDKBlobURL }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -61,6 +61,7 @@ extends: LinuxHostVersion: Network: KS3 WindowsHostVersion: + Version: 2022 Network: KS3 incrementalSDLBinaryAnalysis: true globalSdl: @@ -90,7 +91,7 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - template: ./pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml@self + - template: /.pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml@self parameters: RUN_WINDOWS: ${{ parameters.RUN_WINDOWS }} RUN_TEST_AND_RELEASE: ${{ parameters.RUN_TEST_AND_RELEASE }} diff --git a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml index 9419d3f29b5..0993cd69546 100644 --- a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml @@ -31,7 +31,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: pkgs-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ./pipelines/templates/variables/PowerShell-Packages-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-Packages-Variables.yml@self parameters: debug: ${{ parameters.debug }} ForceAzureBlobDelete: ${{ parameters.ForceAzureBlobDelete }} @@ -92,6 +92,6 @@ extends: enabled: false tsaOptionsFile: .config\tsaoptions.json stages: - - template: ./pipelines/templates/stages/PowerShell-Packages-Stages.yml@self + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self parameters: OfficialBuild: false diff --git a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml index 10dbf8aa6b8..b0bb4d79b39 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml @@ -17,7 +17,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: ev2-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ./pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml index 7864513fc2c..ebfc599e42a 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml @@ -33,7 +33,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: release-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ./pipelines/templates/variables/PowerShell-Release-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-Release-Variables.yml@self parameters: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -98,7 +98,7 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - template: ./pipelines/templates/stages/PowerShell-Release-Stages.yml@self + - template: /.pipelines/templates/stages/PowerShell-Release-Stages.yml@self parameters: releaseEnvironment: Test SkipPublish: ${{ parameters.SkipPublish }} diff --git a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml index f1f4211ca8f..071db02cff8 100644 --- a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml @@ -33,7 +33,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: vPack_$(Build.SourceBranchName)_NonOfficial_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - - template: ./pipelines/templates/variables/PowerShell-vPack-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-vPack-Variables.yml@self parameters: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -82,7 +82,7 @@ extends: enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - - template: ./pipelines/templates/stages/PowerShell-vPack-Stages.yml@self + - template: /.pipelines/templates/stages/PowerShell-vPack-Stages.yml@self parameters: createVPack: ${{ parameters.createVPack }} vPackName: ${{ parameters.vPackName }} diff --git a/.pipelines/templates/stages/PowerShell-vPack-Stages.yml b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml index f0d49e8b489..01a83a5b161 100644 --- a/.pipelines/templates/stages/PowerShell-vPack-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml @@ -50,7 +50,7 @@ stages: env: ob_restore_phase: true - - template: .pipelines/templates/SetVersionVariables.yml@self + - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes From a489d2f1f712f0fe157ea04d1f27ca08bee4883c Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Mon, 18 May 2026 10:36:39 -0700 Subject: [PATCH 263/275] [release/v7.5.7] Remove package verification from the notice pipeline (#27463) --- .pipelines/apiscan-gen-notice.yml | 4 ---- .pipelines/templates/compliance/generateNotice.yml | 7 ------- 2 files changed, 11 deletions(-) diff --git a/.pipelines/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml index a93f98a2e53..1761810b2aa 100644 --- a/.pipelines/apiscan-gen-notice.yml +++ b/.pipelines/apiscan-gen-notice.yml @@ -8,9 +8,6 @@ parameters: displayName: Debugging - Enable CodeQL and set cadence to 1 hour type: boolean default: false - - name: SkipVerifyPackages - type: boolean - default: false variables: # PAT permissions NOTE: Declare a SymbolServerPAT variable in this group with a 'microsoft' organizanization scoped PAT with 'Symbols' Read permission. @@ -109,4 +106,3 @@ extends: - template: /.pipelines/templates/compliance/generateNotice.yml@self parameters: parentJobs: [] - SkipVerifyPackages: ${{ parameters.SkipVerifyPackages }} diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml index 90fd08dd8d9..aec44b9b8f6 100644 --- a/.pipelines/templates/compliance/generateNotice.yml +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -4,8 +4,6 @@ parameters: - name: parentJobs type: jobList - - name: SkipVerifyPackages - type: boolean jobs: - job: generateNotice @@ -57,11 +55,6 @@ jobs: inputs: sourceScanPath: '$(repoRoot)\tools\cgmanifest\tpn' - - pwsh: | - $(repoRoot)/tools/clearlyDefined/ClearlyDefined.ps1 -TestAndHarvest - displayName: Verify that packages have license data - condition: eq(${{ parameters.SkipVerifyPackages }}, false) - - task: msospo.ospo-extension.8d7f9abb-6896-461d-9e25-4f74ed65ddb2.notice@0 displayName: 'NOTICE File Generator' inputs: From 6c26fb74ed34649449b34b8cd951facb6e8d82b9 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Mon, 18 May 2026 10:36:51 -0700 Subject: [PATCH 264/275] [release/v7.5.7] Update the MSIXBundle-VPack pipeline to create VPack for both LTS and Stable channel packages (#27464) --- .pipelines/MSIXBundle-vPack-Official.yml | 199 +++++------------- .../templates/create-msixbundle-vpack.yml | 178 ++++++++++++++++ 2 files changed, 230 insertions(+), 147 deletions(-) create mode 100644 .pipelines/templates/create-msixbundle-vpack.yml diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 08edd0367bd..2461d3cd310 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -138,12 +138,6 @@ extends: if (-not $matched) { throw "Release tag must be in the format v#.#.#, such as 'v7.4.3'. Current version: $releaseTag" } - - # Extract minor version and verify it's even (LTS versions only) - $minorVersion = [int]$Matches[1] - if($minorVersion % 2 -ne 0) { - throw "Only release msixbundle vpack for LTS releases. Current version: $releaseTag" - } displayName: Stop any preview release env: ob_restore_phase: true @@ -270,7 +264,7 @@ extends: Write-Verbose -Message "checking pwsh exists in $signedFilesPath" -Verbose if (-not (Test-Path $signedFilesPath\pwsh.exe)) { - throw "pwsh.exe not found in $signedFilesPath" + throw "pwsh.exe not found in $signedFilesPath" } Write-Verbose -Message "Restoring PSOptions from $psoptionsFilePath" -Verbose @@ -278,166 +272,77 @@ extends: Restore-PSOptions -PSOptionsPath "$psoptionsFilePath" Get-PSOptions | Write-Verbose -Verbose - ## Generated packages are placed in the current directory by default. - Set-Location $repoRoot - Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $runtime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS - - $msixPkgNameFilter = "PowerShell*.msix" - $msixPkgFile = Get-ChildItem -Path $repoRoot -Filter $msixPkgNameFilter -File - $msixPkgPath = $msixPkgFile.FullName - Write-Verbose -Verbose "Unsigned msix package: $msixPkgPath" - - $pkgDir = '$(ob_outputDirectory)\pkgs' - $null = New-Item -ItemType Directory -Path $pkgDir -Force - Copy-Item -Path $msixPkgPath -Destination $pkgDir -Force -Verbose - displayName: 'Build MSIX Package (Unsigned)' - - ### END OF Packaging ### - - - pwsh: | - Get-ChildItem -Path '$(ob_outputDirectory)\pkgs' -Recurse - displayName: 'List Unsigned Package' - - - stage: Pack_MSIXBundle_And_Sign - displayName: 'Pack and sign MSIXBundle' - dependsOn: [Build_MSIX_Package] - jobs: - - job: Bundle - pool: - type: windows - variables: - ArtifactPlatform: 'windows' - ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' - ob_artifactBaseName: drop_pack_msixbundle - ob_createvpack_enabled: ${{ parameters.createVPack }} - ob_createvpack_packagename: 'PowerShell7.Store.app' - ob_createvpack_owneralias: 'dongbow' - ob_createvpack_description: 'VPack for the PowerShell 7 Store Application' - ob_createvpack_targetDestinationDirectory: '$(Destination)' ## The value is from the 'CreateVpack' task, used when pulling the generated VPack. - ob_createvpack_propsFile: false - ob_createvpack_provData: true - ob_createvpack_metadata: '$(Build.SourceVersion)' - ob_createvpack_versionAs: string - ob_createvpack_version: '$(Version)' - ob_createvpack_verbose: true - - steps: - - checkout: self - displayName: Checkout source code - during restore - clean: true - path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. - env: - ob_restore_phase: true + $metadata = Get-Content "$repoRoot\tools\metadata.json" -Raw | ConvertFrom-Json + Write-Verbose -Verbose "metadata:" + $metadata | Out-String | Write-Verbose -Verbose - - template: /.pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: no + $publishLTS = $metadata.LTSRelease.PublishToChannels + $publishStable = $metadata.StableRelease.PublishToChannels - - template: /.pipelines/templates/shouldSign.yml@self + Write-Verbose -Verbose "Publish LTS: $publishLTS" + Write-Verbose -Verbose "Publish Stable: $publishStable" - - task: DownloadPipelineArtifact@2 - inputs: - artifactName: drop_build_x64 - itemPattern: | - **/*.msix - targetPath: '$(Build.ArtifactStagingDirectory)\downloads' - displayName: Download msix for x64 + if (-not $publishLTS -and -not $publishStable) { + throw "metadata.json indicates no channels to publish to." + } - - task: DownloadPipelineArtifact@2 - inputs: - artifactName: drop_build_arm64 - itemPattern: | - **/*.msix - targetPath: '$(Build.ArtifactStagingDirectory)\downloads' - displayName: Download msix for arm64 + ## Generated packages are placed in the current directory by default. + Set-Location $repoRoot + Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $runtime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$publishLTS - # Finds the makeappx tool on the machine. - - pwsh: | - Write-Verbose -Verbose 'PowerShell Version: $(Version)' - $cmd = Get-Command makeappx.exe -ErrorAction Ignore - if ($cmd) { - Write-Verbose -Verbose 'makeappx available in PATH' - $exePath = $cmd.Source - } else { - $makeappx = Get-ChildItem -Recurse 'C:\Program Files (x86)\Windows Kits\10\makeappx.exe' | - Where-Object { $_.DirectoryName -match 'x64' } | - Select-Object -Last 1 - $exePath = $makeappx.FullName - Write-Verbose -Verbose "makeappx was found: $exePath" + if ($publishLTS -and $publishStable) { + $enabledChannels = "LTS,Stable" + Write-Verbose -Verbose "Publish to both LTS and Stable channels. Building additional Stable MSIX." + Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $runtime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath } - $vstsCommandString = "vso[task.setvariable variable=MakeAppxPath]$exePath" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Find makeappx tool - retryCountOnTaskFailure: 1 - - pwsh: | - $sourceDir = '$(Pipeline.Workspace)\releasePipeline\msix' - $null = New-Item -Path $sourceDir -ItemType Directory -Force + $msixPkgNameFilter = "PowerShell*.msix" + $msixPkgFile = Get-ChildItem -Path $repoRoot -Filter $msixPkgNameFilter -Recurse -File | ForEach-Object FullName + Write-Verbose -Verbose "Unsigned msix package(s): $msixPkgFile" - $msixFiles = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse - foreach ($msixFile in $msixFiles) { - $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose - } + $pkgDir = '$(ob_outputDirectory)\pkgs' + $null = New-Item -ItemType Directory -Path $pkgDir -Force + Copy-Item -Path $msixPkgFile -Destination $pkgDir -Force -Verbose - $file = Get-ChildItem $sourceDir | Select-Object -First 1 - $prefix = ($file.BaseName -split "-win")[0] - $pkgName = "$prefix.msixbundle" - Write-Verbose -Verbose "Creating $pkgName" - - $makeappx = '$(MakeAppxPath)' - $outputDir = "$sourceDir\output" - New-Item $outputDir -Type Directory -Force > $null - & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" - if ($LASTEXITCODE -ne 0) { - throw "makeappx bundle failed with exit code $LASTEXITCODE" + if (-not $enabledChannels) { + $enabledChannels = $publishLTS ? 'LTS' : ($publishStable ? 'Stable' : 'None') } - Get-ChildItem -Path $sourceDir -Recurse | Out-String -Width 200 - $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" + ## Create an output variable for the enabled channels so that downstream stages can use it. + $vstsCommandString = "vso[task.setvariable variable=EnabledChannels;isOutput=true]$enabledChannels" Write-Host ("sending " + $vstsCommandString) Write-Host "##$vstsCommandString" - displayName: Create MsixBundle - retryCountOnTaskFailure: 1 + name: BuildMSIXPackage + displayName: 'Build MSIX Package (Unsigned)' - - task: onebranch.pipeline.signing@1 - displayName: Sign MsixBundle - inputs: - command: 'sign' - signing_profile: $(MSIXProfile) - files_to_sign: '**/*.msixbundle' - search_root: '$(BundleDir)' + ### END OF Packaging ### - pwsh: | - $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File - Write-Verbose -Verbose "Signed bundle: $signedBundle" - - $signature = Get-AuthenticodeSignature -FilePath $signedBundle.FullName - if ($signature.Status -ne 'Valid') { - throw "The bundle file doesn't have a valid signature. Signature status: $($signature.Status)" - } + Get-ChildItem -Path '$(ob_outputDirectory)\pkgs' -Recurse + displayName: 'List Unsigned Package' - if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { - $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop - } + - pwsh: | + $signedFilesPath = '$(ob_outputDirectory)\Signed-$(Runtime)' + Remove-Item -Path $signedFilesPath -Recurse -Force -Verbose + displayName: 'Remove Signed-$(Runtime) folder' - $targetPath = Join-Path '$(ob_outputDirectory)' 'Microsoft.PowerShell-LTS_8wekyb3d8bbwe.msixbundle' - Copy-Item -Verbose -Path $signedBundle.FullName -Destination $targetPath + - stage: Pack_MSIXBundle_And_Sign + displayName: 'Pack and sign MSIXBundle' + dependsOn: [Build_MSIX_Package] - Write-Verbose -Verbose "Uploaded Bundle:" - Get-ChildItem -Path $(ob_outputDirectory) | Out-String -Width 200 -Stream | Write-Verbose -Verbose - displayName: 'Stage msixbundle for VPack' + variables: + EnabledChannels: $[ stageDependencies.Build_MSIX_Package.Build.outputs['x64.BuildMSIXPackage.EnabledChannels'] ] - - pwsh: | - Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose - $vpackFiles = Get-ChildItem -Path '$(ob_outputDirectory)\*' -Recurse - if($vpackFiles.Count -eq 0) { - throw "No files found in $(ob_outputDirectory)" - } - $vpackFiles | Out-String -Width 200 - displayName: Debug Output Directory and Version - condition: succeededOrFailed() + jobs: + - template: /.pipelines/templates/create-msixbundle-vpack.yml@self + parameters: + Channel: 'LTS' + createVPack: ${{ parameters.createVPack }} + + - template: /.pipelines/templates/create-msixbundle-vpack.yml@self + parameters: + Channel: 'Stable' + createVPack: ${{ parameters.createVPack }} - stage: Publish_Symbols displayName: 'Publish Symbols' diff --git a/.pipelines/templates/create-msixbundle-vpack.yml b/.pipelines/templates/create-msixbundle-vpack.yml new file mode 100644 index 00000000000..df46523675f --- /dev/null +++ b/.pipelines/templates/create-msixbundle-vpack.yml @@ -0,0 +1,178 @@ +parameters: + - name: Channel + type: string + - name: createVPack + type: boolean + +jobs: +- job: Bundle_${{ parameters.Channel }} + condition: contains(variables['EnabledChannels'], '${{ parameters.Channel }}') + pool: + type: windows + + variables: + ArtifactPlatform: 'windows' + Channel: ${{ parameters.Channel }} + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_artifactBaseName: 'drop_pack_$(Channel)' + ob_createvpack_enabled: ${{ parameters.createVPack }} + ob_createvpack_packagename: 'PowerShell7-$(Channel).Store.app' + ob_createvpack_owneralias: 'dongbow' + ob_createvpack_description: 'VPack for the PowerShell 7 Store Application ($(Channel))' + ob_createvpack_targetDestinationDirectory: '$(Destination)' ## The value is from the 'CreateVpack' task, used when pulling the generated VPack. + ob_createvpack_propsFile: false + ob_createvpack_provData: true + ob_createvpack_metadata: '$(Build.SourceVersion)' + ob_createvpack_versionAs: string + ob_createvpack_version: '$(Version)' + ob_createvpack_verbose: true + + steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. + env: + ob_restore_phase: true + + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no + + - template: /.pipelines/templates/shouldSign.yml@self + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_x64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download msix for x64 + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_arm64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download msix for arm64 + + # Finds the makeappx tool on the machine. + - pwsh: | + Write-Verbose -Verbose 'PowerShell Version: $(Version)' + $cmd = Get-Command makeappx.exe -ErrorAction Ignore + if ($cmd) { + Write-Verbose -Verbose 'makeappx available in PATH' + $exePath = $cmd.Source + } else { + $makeappx = Get-ChildItem -Recurse 'C:\Program Files (x86)\Windows Kits\10\makeappx.exe' | + Where-Object { $_.DirectoryName -match 'x64' } | + Select-Object -Last 1 + $exePath = $makeappx.FullName + Write-Verbose -Verbose "makeappx was found: $exePath" + } + $vstsCommandString = "vso[task.setvariable variable=MakeAppxPath]$exePath" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Find makeappx tool + retryCountOnTaskFailure: 1 + + - pwsh: | + $sourceDir = '$(Pipeline.Workspace)\releasePipeline\msix' + $null = New-Item -Path $sourceDir -ItemType Directory -Force + + $channel = '$(Channel)' + if ($channel -eq 'LTS') { + Write-Verbose -Verbose "LTS channel. Remove Stable MSIX packages" + $stablePkgs = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse | + Where-Object { $_.FullName -notlike '*-LTS-*.msix' } | ForEach-Object FullName + + if ($stablePkgs) { + Remove-Item -Path $stablePkgs -Force -Verbose -ErrorAction Stop + } else { + Write-Verbose -Verbose "No Stable MSIX package was found." + } + } + else { + Write-Verbose -Verbose "Stable channel. Remove LTS MSIX packages" + $ltsPkgs = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse | + Where-Object { $_.FullName -like '*-LTS-*.msix' } | ForEach-Object FullName + + if ($ltsPkgs) { + Remove-Item -Path $ltsPkgs -Force -Verbose -ErrorAction Stop + } else { + Write-Verbose -Verbose "No LTS MSIX package was found." + } + } + + $msixFiles = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse + foreach ($msixFile in $msixFiles) { + $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose + } + + $file = Get-ChildItem $sourceDir | Select-Object -First 1 + $prefix = ($file.BaseName -split "-win")[0] + $pkgName = "$prefix.msixbundle" + Write-Verbose -Verbose "Creating $pkgName" + + $makeappx = '$(MakeAppxPath)' + $outputDir = "$sourceDir\output" + New-Item $outputDir -Type Directory -Force > $null + & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" + if ($LASTEXITCODE -ne 0) { + throw "makeappx bundle failed with exit code $LASTEXITCODE" + } + + Get-ChildItem -Path $sourceDir -Recurse | Out-String -Width 200 + $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Create MsixBundle + retryCountOnTaskFailure: 1 + + - task: onebranch.pipeline.signing@1 + displayName: Sign MsixBundle + inputs: + command: 'sign' + signing_profile: $(MSIXProfile) + files_to_sign: '**/*.msixbundle' + search_root: '$(BundleDir)' + + - pwsh: | + $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File + Write-Verbose -Verbose "Signed bundle: $signedBundle" + + $signature = Get-AuthenticodeSignature -FilePath $signedBundle.FullName + if ($signature.Status -ne 'Valid') { + throw "The bundle file doesn't have a valid signature. Signature status: $($signature.Status)" + } + + if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { + $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop + } + + $channel = '$(Channel)' + $targetFileName = if ($channel -eq 'LTS') { + 'Microsoft.PowerShell-LTS_8wekyb3d8bbwe.msixbundle' + } else { + 'Microsoft.PowerShell_8wekyb3d8bbwe.msixbundle' + } + $targetPath = Join-Path '$(ob_outputDirectory)' $targetFileName + Copy-Item -Verbose -Path $signedBundle.FullName -Destination $targetPath + + Write-Verbose -Verbose "Uploaded Bundle:" + Get-ChildItem -Path $(ob_outputDirectory) | Out-String -Width 200 -Stream | Write-Verbose -Verbose + displayName: 'Stage msixbundle for VPack' + + - pwsh: | + Write-Verbose "VPack enabled: $(ob_createvpack_enabled)" -Verbose + Write-Verbose "VPack Name: $(ob_createvpack_packagename)" -Verbose + Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose + + $vpackFiles = Get-ChildItem -Path '$(ob_outputDirectory)\*' -Recurse + if($vpackFiles.Count -eq 0) { + throw "No files found in $(ob_outputDirectory)" + } + $vpackFiles | Out-String -Width 200 + displayName: Debug Output Directory and Version From 1add955f4ca40952f0d3d37940ce604e52c6a36d Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Mon, 18 May 2026 10:37:04 -0700 Subject: [PATCH 265/275] [release/v7.5.7] Update `Microsoft.PowerShell.Native` to the latest GA version (#27465) --- .../System.Management.Automation.csproj | 4 ++-- tools/packaging/boms/windows.json | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index c82609b1605..cb9734e1469 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -47,7 +47,7 @@ <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> <!-- the following package(s) are from the powershell org --> <PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" /> - <PackageReference Include="Microsoft.PowerShell.Native" Version="7.4.0" /> + <PackageReference Include="Microsoft.PowerShell.Native" Version="700.0.0" /> <!-- Signing APIs --> <PackageReference Include="Microsoft.Security.Extensions" Version="1.4.0" /> <PackageReference Include="System.Windows.Extensions" Version="9.0.15" /> @@ -102,4 +102,4 @@ <ItemGroup Condition=" '$(IsWindows)' == 'true' "> <Compile Remove="engine\Interop\Unix\**\*.cs" /> </ItemGroup> -</Project> +</Project> \ No newline at end of file diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index c9fd280930f..1ad76f32ec1 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -1,14 +1,14 @@ [ { - "Pattern": "_manifest\\spdx_2.2\\bsi.json", + "Pattern": "Accessibility.dll", "FileType": "NonProduct" }, { - "Pattern": "_manifest\\spdx_2.2\\manifest.cat", + "Pattern": "build.manifest", "FileType": "NonProduct" }, { - "Pattern": "Accessibility.dll", + "Pattern": "build.manifest.sig", "FileType": "NonProduct" }, { From 7472c7067033c57bf7c0c41cfb167bf02f63da2e Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Mon, 18 May 2026 10:37:17 -0700 Subject: [PATCH 266/275] [release/v7.5.7] Add `appLicensing` capability to Appx manifest (#27466) --- assets/AppxManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/AppxManifest.xml b/assets/AppxManifest.xml index 50a8c7af45d..dfcd95935d9 100644 --- a/assets/AppxManifest.xml +++ b/assets/AppxManifest.xml @@ -43,6 +43,7 @@ <Capabilities> <Capability Name="internetClient" /> + <rescap:Capability Name="appLicensing" /> <rescap:Capability Name="runFullTrust" /> <rescap:Capability Name="unvirtualizedResources" /> <rescap:Capability Name="packageManagement" /> From b4905a1debf900dbfdac3ce4f6ed7722963b0f8b Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Mon, 18 May 2026 10:37:28 -0700 Subject: [PATCH 267/275] [release/v7.5.7] Add macOS binary code signing and package notarization (#27467) --- .pipelines/templates/mac-package-build.yml | 65 ++++++++++++++++++---- .pipelines/templates/mac.yml | 40 +++++++++++++ assets/macos-entitlements.plist | 14 +++++ tools/packaging/packaging.psd1 | 1 + 4 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 assets/macos-entitlements.plist diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 4326166cb0c..d0d75a3ba6e 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -76,6 +76,14 @@ jobs: # Diagnostics is not critical it passes every time it runs continueOnError: true + - pwsh: | + $signedDir = "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/drop_macos_sign_${{ parameters.buildArchitecture }}/Signed-${{ parameters.buildArchitecture }}" + Get-ChildItem $signedDir -Recurse -Include 'pwsh', '*.dylib' | ForEach-Object { + codesign --verify --deep --strict --verbose=4 $_.FullName + if ($LASTEXITCODE -ne 0) { throw "codesign verification failed for $($_.FullName)" } + } + displayName: 'Verify Apple codesign on signed binaries' + - pwsh: | # Add -SkipReleaseChecks as a mitigation to unblock release. # macos-10.15 does not allow creating a folder under root. Hence, moving the folder. @@ -158,7 +166,12 @@ jobs: Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$file" } + $packageInfo = Get-MacOSPackageIdentifierInfo -Version '$(Version)' -LTS:$LTS + Write-Verbose -Verbose "BundleId: $($packageInfo.PackageIdentifier)" + Write-Host "##vso[task.setvariable variable=BundleId;isOutput=true]$($packageInfo.PackageIdentifier)" + displayName: 'Package ${{ parameters.buildArchitecture}}' + name: packageStep env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) @@ -178,7 +191,8 @@ jobs: value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json - name: BuildArch value: ${{ parameters.buildArchitecture }} - - group: mscodehub-macos-package-signing + - name: BundleId + value: $[ dependencies.package_macOS_${{ parameters.buildArchitecture }}.outputs['packageStep.BundleId'] ] steps: - download: current @@ -216,32 +230,59 @@ jobs: inline_operation: | [ { - "KeyCode": "$(KeyCode)", + "KeyCode": "CP-401337-Apple", "OperationCode": "MacAppDeveloperSign", "ToolName": "sign", "ToolVersion": "1.0", "Parameters": { - "Hardening": "Enable", - "OpusInfo": "http://microsoft.com" + "Hardening": "--options=runtime" } } ] + - task: onebranch.pipeline.signing@1 + displayName: 'OneBranch Notarize Package' + inputs: + command: 'sign' + files_to_sign: '**/*-osx-*.zip' + search_root: '$(Pipeline.Workspace)' + inline_operation: | + [ + { + "KeyCode": "CP-401337-Apple", + "OperationCode": "MacAppNotarize", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": { + "BundleId": "$(BundleId)" + } + } + ] + timeoutInMinutes: 120 + - pwsh: | $signedPkg = Get-ChildItem -Path $(Pipeline.Workspace) -Filter "*osx*.zip" -File + if (-not (Test-Path $(ob_outputDirectory))) { + $null = New-Item -Path $(ob_outputDirectory) -ItemType Directory + } + + $expandDir = "$(Pipeline.Workspace)/pkgExpand" + $null = New-Item -Path $expandDir -ItemType Directory -Force + $signedPkg | ForEach-Object { Write-Verbose -Verbose "Signed package zip: $_" + Expand-Archive -Path $_ -DestinationPath $expandDir -Verbose + } - if (-not (Test-Path $_)) { - throw "Package not found: $_" - } - - if (-not (Test-Path $(ob_outputDirectory))) { - $null = New-Item -Path $(ob_outputDirectory) -ItemType Directory - } + # ESRP's signing pipeline nests the PKG inside a '<hash>.zip.unzipped' subfolder + $pkgFile = Get-ChildItem -Path $expandDir -Filter '*.pkg' -Recurse -File + if (-not $pkgFile) { + throw "Package not found in: $signedPkg" + } - Expand-Archive -Path $_ -DestinationPath $(ob_outputDirectory) -Verbose + $pkgFile | ForEach-Object { + Move-Item -Path $_ -Destination $(ob_outputDirectory) -Verbose } Write-Verbose -Verbose "Expanded pkg file:" diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index 1699207c657..b22149d5e46 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -69,6 +69,14 @@ jobs: $psOptPath = "$(OB_OUTPUTDIRECTORY)/psoptions.json" Save-PSOptions -PSOptionsPath $psOptPath + $entitlements = "$(PowerShellRoot)/assets/macos-entitlements.plist" + $pwshBin = "$(OB_OUTPUTDIRECTORY)/pwsh" + Write-Verbose -Verbose "Applying entitlements to $pwshBin" + codesign --sign - --force --options runtime --entitlements $entitlements $pwshBin + if ($LASTEXITCODE -ne 0) { + throw "codesign failed with exit code $LASTEXITCODE" + } + # Since we are using custom pool for macOS, we need to use artifact.upload to publish the artifacts Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName]$(OB_OUTPUTDIRECTORY)" @@ -144,4 +152,36 @@ jobs: binPath: $(DropRootPath) OfficialBuild: $(ps_official_build) + # Apple-sign the Mach-O binaries inside the signed output. + - pwsh: | + $signedDir = "$(ob_outputDirectory)/Signed-$(Runtime)" + $zipFile = "$(Pipeline.Workspace)/macho-$(BuildArchitecture).zip" + Compress-Archive -Path "$signedDir/*" -DestinationPath $zipFile -Force + displayName: Compress signed folder for Apple signing + + - task: onebranch.pipeline.signing@1 + displayName: Apple CodeSign Mach-O binaries + inputs: + command: 'sign' + files_to_sign: 'macho-$(BuildArchitecture).zip' + search_root: '$(Pipeline.Workspace)' + inline_operation: | + [ + { + "KeyCode": "CP-401337-Apple", + "OperationCode": "MacAppDeveloperSign", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": { + "Hardening": "--options=runtime" + } + } + ] + + - pwsh: | + $signedDir = "$(ob_outputDirectory)/Signed-$(Runtime)" + $zipFile = "$(Pipeline.Workspace)/macho-$(BuildArchitecture).zip" + Expand-Archive -Path $zipFile -DestinationPath $signedDir -Force -Verbose + displayName: Expand Apple-signed Mach-O binaries into signed output + - template: /.pipelines/templates/step/finalize.yml@self diff --git a/assets/macos-entitlements.plist b/assets/macos-entitlements.plist new file mode 100644 index 00000000000..9d534f4f4bf --- /dev/null +++ b/assets/macos-entitlements.plist @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.security.cs.allow-jit</key> + <true/> + <key>com.apple.security.cs.allow-unsigned-executable-memory</key> + <true/> + <key>com.apple.security.cs.allow-dyld-environment-variables</key> + <true/> + <key>com.apple.security.cs.disable-library-validation</key> + <true/> +</dict> +</plist> diff --git a/tools/packaging/packaging.psd1 b/tools/packaging/packaging.psd1 index 0053428a481..e5b7fb84dfc 100644 --- a/tools/packaging/packaging.psd1 +++ b/tools/packaging/packaging.psd1 @@ -26,6 +26,7 @@ 'Test-PackageManifest' 'Update-PSSignedBuildFolder' 'Test-Bom' + 'Get-MacOSPackageIdentifierInfo' ) RootModule = "packaging.psm1" RequiredModules = @("build") From 15add5709b1b1b0302745707f8cb8df62e55de4e Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Mon, 18 May 2026 14:07:01 -0700 Subject: [PATCH 268/275] Add the `windowsTargetName` for .NET 9 (#27474) --- tools/findMissingNotices.targets.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/findMissingNotices.targets.json b/tools/findMissingNotices.targets.json index fdef552c603..4da557d1982 100644 --- a/tools/findMissingNotices.targets.json +++ b/tools/findMissingNotices.targets.json @@ -1,5 +1,6 @@ { "dotnetTargetName": "net9.0", "windowsTargetNames": [ + "net9.0-windows8.0" ] } From 948ffc0c48684ce84868d80cd3b9c9eee2125a5d Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Mon, 18 May 2026 18:05:38 -0700 Subject: [PATCH 269/275] [release/v7.5.7] Fix *nix permissions and use `certificate_logical_to_actual` (#27468) --- .pipelines/templates/linux-package-build.yml | 23 ++++++++++++++---- .pipelines/templates/mac-package-build.yml | 10 ++++++-- .pipelines/templates/mac.yml | 2 +- .pipelines/templates/nupkg.yml | 5 ++-- .pipelines/templates/shouldSign.yml | 6 ++--- .../stages/PowerShell-Packages-Stages.yml | 2 -- .pipelines/templates/windows-hosted-build.yml | 2 +- tools/packaging/packaging.psm1 | 24 ++++++++++++++++++- 8 files changed, 58 insertions(+), 16 deletions(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index f0017c63d2e..6cc536e7779 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -1,9 +1,8 @@ parameters: unsignedDrop: 'drop_linux_build_linux_x64' - signedeDrop: 'drop_linux_sign_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' packageType: deb jobName: 'deb' - signingProfile: 'CP-450779-pgpdetached' jobs: - job: ${{ parameters.jobName }} @@ -20,6 +19,7 @@ jobs: - name: skipNugetSecurityAnalysis value: true - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled @@ -34,8 +34,16 @@ jobs: value: $(Build.SourcesDirectory)/PowerShell/.config/tsaoptions.json - name: ob_sdl_credscan_suppressionsFile value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json - - name: SigningProfile - value: ${{ parameters.signingProfile }} + # PGP signing profile selection: Mariner (Azure Linux) packages ship through + # a different distribution channel and must be signed with the Mariner release + # key; all other Linux packages use the standard PowerShell Linux key. Both + # key codes come from the `certificate_logical_to_actual` variable group. + - ${{ if startsWith(parameters.jobName, 'mariner') }}: + - name: SigningProfile + value: $(pgp_release_cert_id) + - ${{ else }}: + - name: SigningProfile + value: $(pgp_linux_cert_id) steps: - checkout: self @@ -192,6 +200,13 @@ jobs: $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgFilter -Recurse -File | Select-Object -ExpandProperty FullName Write-Verbose -Verbose "pkgPath: $pkgPath" Copy-Item -Path $pkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + + if ($pkgPath -like '*.tar.gz') { + $entry = & tar -tzvf $pkgPath | Where-Object { $_ -match '\spwsh$' } | Select-Object -First 1 + if ($entry -notmatch '^-..x') { + throw "pwsh is not executable in $pkgPath : $entry" + } + } displayName: 'Copy artifacts to output directory' env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index d0d75a3ba6e..8adf2d74418 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -22,6 +22,7 @@ jobs: - name: skipNugetSecurityAnalysis value: true - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled @@ -162,6 +163,10 @@ jobs: foreach($t in $tarPkgPath) { $file = $t.FullName + $entry = & tar -tzvf $file | Where-Object { $_ -match '\spwsh$' } | Select-Object -First 1 + if ($entry -notmatch '^-..x') { + throw "pwsh is not executable in $file : $entry" + } Write-Verbose -verbose "Uploading $file to macos-pkgs" Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$file" } @@ -183,6 +188,7 @@ jobs: type: windows variables: + - group: certificate_logical_to_actual - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled @@ -230,7 +236,7 @@ jobs: inline_operation: | [ { - "KeyCode": "CP-401337-Apple", + "KeyCode": "$(apple_cert_id)", "OperationCode": "MacAppDeveloperSign", "ToolName": "sign", "ToolVersion": "1.0", @@ -249,7 +255,7 @@ jobs: inline_operation: | [ { - "KeyCode": "CP-401337-Apple", + "KeyCode": "$(apple_cert_id)", "OperationCode": "MacAppNotarize", "ToolName": "sign", "ToolVersion": "1.0", diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index b22149d5e46..cd492994617 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -168,7 +168,7 @@ jobs: inline_operation: | [ { - "KeyCode": "CP-401337-Apple", + "KeyCode": "$(apple_cert_id)", "OperationCode": "MacAppDeveloperSign", "ToolName": "sign", "ToolVersion": "1.0", diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index 8925fcba5ff..8dcfa2e665d 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -23,6 +23,7 @@ jobs: - group: mscodehub-feed-read-general - group: mscodehub-feed-read-akv - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual steps: - checkout: self @@ -208,7 +209,7 @@ jobs: displayName: Sign nupkg files inputs: command: 'sign' - cp_code: 'CP-401405' + cp_code: '$(nuget_cert_id)' files_to_sign: '**\*.nupkg' search_root: '$(Pipeline.Workspace)\nupkg' @@ -268,7 +269,7 @@ jobs: displayName: Sign nupkg files inputs: command: 'sign' - cp_code: 'CP-401405' + cp_code: '$(nuget_cert_id)' files_to_sign: '**\*.nupkg' search_root: '$(Pipeline.Workspace)\globaltools' diff --git a/.pipelines/templates/shouldSign.yml b/.pipelines/templates/shouldSign.yml index 551297f3aaa..f3701acbc97 100644 --- a/.pipelines/templates/shouldSign.yml +++ b/.pipelines/templates/shouldSign.yml @@ -6,11 +6,11 @@ parameters: steps: - powershell: | $shouldSign = $true - $authenticodeCert = 'CP-230012' - $msixCert = 'CP-230012' + $authenticodeCert = '$(authenticode_cert_id)' + $msixCert = '$(authenticode_cert_id)' if($env:IS_DAILY -eq 'true') { - $authenticodeCert = 'CP-460906' + $authenticodeCert = '$(authenticode_test_cert_id)' } if($env:SKIP_SIGNING -eq 'Yes') { diff --git a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml index b1efb2a8097..b88a8ec94fc 100644 --- a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml @@ -93,7 +93,6 @@ stages: signedDrop: 'drop_linux_sign_linux_fxd_x64_mariner' packageType: rpm-fxdependent #mariner-x64 jobName: mariner_x64 - signingProfile: 'CP-459159-pgpdetached' - template: /.pipelines/templates/linux-package-build.yml@self parameters: @@ -101,7 +100,6 @@ stages: signedDrop: 'drop_linux_sign_linux_fxd_arm64_mariner' packageType: rpm-fxdependent-arm64 #mariner-arm64 jobName: mariner_arm64 - signingProfile: 'CP-459159-pgpdetached' - template: /.pipelines/templates/linux-package-build.yml@self parameters: diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index e21d2253887..b5e57ce58e1 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -313,7 +313,7 @@ jobs: displayName: Sign nupkg files inputs: command: 'sign' - cp_code: 'CP-401405' + cp_code: '$(nuget_cert_id)' files_to_sign: '**\*.nupkg' search_root: '$(ob_outputDirectory)\globaltool' condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index d75688e3921..456b459504b 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -792,6 +792,18 @@ function New-TarballPackage { $Staging = "$PSScriptRoot/staging" New-StagingFolder -StagingPath $Staging -PackageSourcePath $PackageSourcePath -R2RVerification $R2RVerification + # Ensure PowerShell executable has correct permissions in tarball + $pwshInStaging = Join-Path $Staging 'pwsh' + if (Test-Path -LiteralPath $pwshInStaging) { + Start-NativeExecution { chmod 755 $pwshInStaging } + } + + # Included .NET executable for producing crash dumps + $createdumpInStaging = Join-Path $Staging 'createdump' + if (Test-Path -LiteralPath $createdumpInStaging) { + Start-NativeExecution { chmod 755 $createdumpInStaging } + } + if (Get-Command -Name tar -CommandType Application -ErrorAction Ignore) { if ($Force -or $PSCmdlet.ShouldProcess("Create tarball package")) { $options = "-czf" @@ -1210,7 +1222,11 @@ function New-UnixPackage { find $Staging -type f | xargs chmod 644 chmod 644 $ManGzipInfo.GzipFile # refers to executable, does not vary by channel - chmod 755 "$Staging/pwsh" #only the executable file should be granted the execution permission + chmod 755 "$Staging/pwsh" # only the executable file should be granted the execution permission + # Included .NET executable for producing crash dumps + if (Test-Path "$Staging/createdump") { + chmod 755 "$Staging/createdump" + } } } @@ -1890,6 +1906,12 @@ $(if ($extendedDescription) { $extendedDescription + "`n" }) Start-NativeExecution { chmod 755 $pwshPath } } + # Included .NET executable for producing crash dumps + $createdumpPath = "$targetPath/createdump" + if (Test-Path $createdumpPath) { + Start-NativeExecution { chmod 755 $createdumpPath } + } + # Calculate md5sums for all files in data directory (excluding symlinks) $md5sumsFile = Join-Path $debianDir "md5sums" $md5Content = "" From 3122d06b5e8cd6f1a1df22c74d0cd31045381219 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Tue, 19 May 2026 08:08:16 -0700 Subject: [PATCH 270/275] Revert "[release/v7.5.7] Fix checks for local user config file paths" (#27476) --- .../host/msh/ConsoleHost.cs | 13 ++---- .../host/msh/UpdatesNotification.cs | 4 +- .../CoreCLR/CorePsPlatform.cs | 46 ++----------------- .../engine/CommandDiscovery.cs | 10 +--- .../engine/Modules/AnalysisCache.cs | 7 +-- .../engine/PSConfiguration.cs | 10 +--- .../engine/hostifaces/HostUtilities.cs | 9 ++-- .../engine/hostifaces/MshHostUserInterface.cs | 5 -- .../utils/Telemetry.cs | 5 +- 9 files changed, 19 insertions(+), 90 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index f454ab51e1d..8fc815f59e6 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -153,16 +153,13 @@ internal static int Start( try { string profileDir = Platform.CacheDirectory; - if (!string.IsNullOrEmpty(profileDir)) - { #if !UNIX - if (!Directory.Exists(profileDir)) - { - Directory.CreateDirectory(profileDir); - } -#endif - ProfileOptimization.SetProfileRoot(profileDir); + if (!Directory.Exists(profileDir)) + { + Directory.CreateDirectory(profileDir); } +#endif + ProfileOptimization.SetProfileRoot(profileDir); } catch { diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs index eb4557c04d2..d0b1ed4572c 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs @@ -60,12 +60,12 @@ internal static class UpdatesNotification static UpdatesNotification() { s_notificationType = GetNotificationType(); - CanNotifyUpdates = s_notificationType != NotificationType.Off - && Platform.TryDeriveFromCache(PSVersionInfo.GitCommitId, out s_cacheDirectory); + CanNotifyUpdates = s_notificationType != NotificationType.Off; if (CanNotifyUpdates) { s_enumOptions = new EnumerationOptions(); + s_cacheDirectory = Path.Combine(Platform.CacheDirectory, PSVersionInfo.GitCommitId); // Build the template/pattern strings for the configured notification type. string typeNum = ((int)s_notificationType).ToString(); diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 530493f320a..dc5db5f2c48 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -167,13 +167,8 @@ public static bool IsStaSupported internal static readonly string ConfigDirectory = Platform.SelectProductNameForDirectory(Platform.XDG_Type.CONFIG); #else // Gets the location for cache and config folders. - internal static readonly string CacheDirectory = SafeDeriveFromSpecialFolder( - Environment.SpecialFolder.LocalApplicationData, - @"Microsoft\PowerShell"); - - internal static readonly string ConfigDirectory = SafeDeriveFromSpecialFolder( - Environment.SpecialFolder.Personal, - @"PowerShell"); + internal static readonly string CacheDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Microsoft\PowerShell"; + internal static readonly string ConfigDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\PowerShell"; private static readonly Lazy<bool> _isStaSupported = new Lazy<bool>(() => { @@ -194,30 +189,6 @@ public static bool IsStaSupported private static bool? _isWindowsDesktop = null; #endif - internal static bool TryDeriveFromCache(string path1, out string result) - { - if (CacheDirectory is null or []) - { - result = null; - return false; - } - - result = Path.Combine(CacheDirectory, path1); - return true; - } - - internal static bool TryDeriveFromCache(string path1, string path2, out string result) - { - if (CacheDirectory is null or []) - { - result = null; - return false; - } - - result = Path.Combine(CacheDirectory, path1, path2); - return true; - } - // format files internal static readonly string[] FormatFileNames = new string[] { @@ -247,17 +218,6 @@ internal static class CommonEnvVariableNames #endif } - private static string SafeDeriveFromSpecialFolder(Environment.SpecialFolder specialFolder, string subPath) - { - string basePath = Environment.GetFolderPath(specialFolder, Environment.SpecialFolderOption.DoNotVerify); - if (string.IsNullOrWhiteSpace(basePath)) - { - return string.Empty; - } - - return Path.Join(basePath, subPath); - } - #if UNIX private static string s_tempHome = null; @@ -400,7 +360,7 @@ internal static string GetFolderPath(Environment.SpecialFolder folder) _ => throw new NotSupportedException() }; #else - return Environment.GetFolderPath(folder, Environment.SpecialFolderOption.DoNotVerify); + return Environment.GetFolderPath(folder); #endif } diff --git a/src/System.Management.Automation/engine/CommandDiscovery.cs b/src/System.Management.Automation/engine/CommandDiscovery.cs index e07520a1238..561a33ccba8 100644 --- a/src/System.Management.Automation/engine/CommandDiscovery.cs +++ b/src/System.Management.Automation/engine/CommandDiscovery.cs @@ -1218,17 +1218,11 @@ internal LookupPathCollection GetLookupDirectoryPaths() string tempDir = directory.TrimStart(); if (tempDir.EqualsOrdinalIgnoreCase("~")) { - tempDir = Environment.GetFolderPath( - Environment.SpecialFolder.UserProfile, - Environment.SpecialFolderOption.DoNotVerify); + tempDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); } else if (tempDir.StartsWith("~" + Path.DirectorySeparatorChar)) { - tempDir = Environment.GetFolderPath( - Environment.SpecialFolder.UserProfile, - Environment.SpecialFolderOption.DoNotVerify) - + Path.DirectorySeparatorChar - + tempDir.Substring(2); + tempDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + Path.DirectorySeparatorChar + tempDir.Substring(2); } _cachedPath.Add(tempDir); diff --git a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs index 39d9b586aa6..a701b0745c8 100644 --- a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs +++ b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs @@ -664,11 +664,6 @@ private static byte[] GetHeader() public void QueueSerialization() { - if (string.IsNullOrEmpty(s_cacheStoreLocation)) - { - return; - } - // We expect many modules to rapidly call for serialization. // Instead of doing it right away, we'll queue a task that starts writing // after it seems like we've stopped adding stuff to write out. This is @@ -1126,7 +1121,7 @@ static AnalysisCacheData() cacheFileName = string.Create(CultureInfo.InvariantCulture, $"{cacheFileName}-{hashString}"); } - Platform.TryDeriveFromCache(cacheFileName, out s_cacheStoreLocation); + s_cacheStoreLocation = Path.Combine(Platform.CacheDirectory, cacheFileName); } } diff --git a/src/System.Management.Automation/engine/PSConfiguration.cs b/src/System.Management.Automation/engine/PSConfiguration.cs index 419a4cae95f..e321423f768 100644 --- a/src/System.Management.Automation/engine/PSConfiguration.cs +++ b/src/System.Management.Automation/engine/PSConfiguration.cs @@ -89,10 +89,7 @@ private PowerShellConfig() // Note: This directory may or may not exist depending upon the execution scenario. // Writes will attempt to create the directory if it does not already exist. perUserConfigDirectory = Platform.ConfigDirectory; - if (!string.IsNullOrEmpty(perUserConfigDirectory)) - { - perUserConfigFile = Path.Combine(perUserConfigDirectory, ConfigFileName); - } + perUserConfigFile = Path.Combine(perUserConfigDirectory, ConfigFileName); emptyConfig = new JObject(); configRoots = new JObject[2]; @@ -390,11 +387,6 @@ internal PSKeyword GetLogKeywords() private T ReadValueFromFile<T>(ConfigScope scope, string key, T defaultValue = default) { string fileName = GetConfigFilePath(scope); - if (string.IsNullOrEmpty(fileName)) - { - return defaultValue; - } - JObject configData = configRoots[(int)scope]; if (configData == null) diff --git a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs index caf3c5e15d8..003625791b1 100644 --- a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs +++ b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs @@ -208,11 +208,10 @@ internal static string GetFullProfileFileName(string shellId, bool forCurrentUse else { basePath = GetAllUsersFolderPath(shellId); - } - - if (string.IsNullOrEmpty(basePath)) - { - return string.Empty; + if (string.IsNullOrEmpty(basePath)) + { + return string.Empty; + } } string profileName = useTestProfile ? "profile_test.ps1" : "profile.ps1"; diff --git a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs index 5f51ba15751..29fc5fa1f7f 100644 --- a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs +++ b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs @@ -1156,11 +1156,6 @@ internal static string GetTranscriptPath(string baseDirectory, bool includeDate) } } - if (string.IsNullOrEmpty(baseDirectory)) - { - return string.Empty; - } - if (includeDate) { baseDirectory = Path.Combine(baseDirectory, DateTime.Now.ToString("yyyyMMdd", CultureInfo.InvariantCulture)); diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index 02851f26f9f..cffedb7c579 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -164,8 +164,6 @@ public static class ApplicationInsightsTelemetry private static readonly HashSet<string> s_knownSubsystemNames; - private static readonly string s_uuidPath; - /// <summary>Gets a value indicating whether telemetry can be sent.</summary> public static bool CanSendTelemetry { get; private set; } @@ -179,8 +177,7 @@ public static class ApplicationInsightsTelemetry static ApplicationInsightsTelemetry() { // If we can't send telemetry, there's no reason to do any of this - CanSendTelemetry = !GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false) - && Platform.TryDeriveFromCache("telemetry.uuid", out s_uuidPath); + CanSendTelemetry = !GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false); if (CanSendTelemetry) { s_sessionId = Guid.NewGuid().ToString(); From d648dd17dac2fa5d9df9e9de6c31257e0f717594 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Tue, 19 May 2026 10:25:19 -0700 Subject: [PATCH 271/275] [release/v7.5.7] Fix checks for local user config file paths (#27479) --- .../host/msh/ConsoleHost.cs | 13 +- .../host/msh/UpdatesNotification.cs | 4 +- .../CoreCLR/CorePsPlatform.cs | 46 +- .../engine/CommandDiscovery.cs | 10 +- .../engine/Modules/AnalysisCache.cs | 7 +- .../engine/PSConfiguration.cs | 10 +- .../engine/hostifaces/HostUtilities.cs | 9 +- .../engine/hostifaces/MshHostUserInterface.cs | 5 + .../utils/Telemetry.cs | 926 +++++++++--------- 9 files changed, 552 insertions(+), 478 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index 8fc815f59e6..f454ab51e1d 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -153,13 +153,16 @@ internal static int Start( try { string profileDir = Platform.CacheDirectory; -#if !UNIX - if (!Directory.Exists(profileDir)) + if (!string.IsNullOrEmpty(profileDir)) { - Directory.CreateDirectory(profileDir); - } +#if !UNIX + if (!Directory.Exists(profileDir)) + { + Directory.CreateDirectory(profileDir); + } #endif - ProfileOptimization.SetProfileRoot(profileDir); + ProfileOptimization.SetProfileRoot(profileDir); + } } catch { diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs index d0b1ed4572c..eb4557c04d2 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs @@ -60,12 +60,12 @@ internal static class UpdatesNotification static UpdatesNotification() { s_notificationType = GetNotificationType(); - CanNotifyUpdates = s_notificationType != NotificationType.Off; + CanNotifyUpdates = s_notificationType != NotificationType.Off + && Platform.TryDeriveFromCache(PSVersionInfo.GitCommitId, out s_cacheDirectory); if (CanNotifyUpdates) { s_enumOptions = new EnumerationOptions(); - s_cacheDirectory = Path.Combine(Platform.CacheDirectory, PSVersionInfo.GitCommitId); // Build the template/pattern strings for the configured notification type. string typeNum = ((int)s_notificationType).ToString(); diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index dc5db5f2c48..530493f320a 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -167,8 +167,13 @@ public static bool IsStaSupported internal static readonly string ConfigDirectory = Platform.SelectProductNameForDirectory(Platform.XDG_Type.CONFIG); #else // Gets the location for cache and config folders. - internal static readonly string CacheDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Microsoft\PowerShell"; - internal static readonly string ConfigDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\PowerShell"; + internal static readonly string CacheDirectory = SafeDeriveFromSpecialFolder( + Environment.SpecialFolder.LocalApplicationData, + @"Microsoft\PowerShell"); + + internal static readonly string ConfigDirectory = SafeDeriveFromSpecialFolder( + Environment.SpecialFolder.Personal, + @"PowerShell"); private static readonly Lazy<bool> _isStaSupported = new Lazy<bool>(() => { @@ -189,6 +194,30 @@ public static bool IsStaSupported private static bool? _isWindowsDesktop = null; #endif + internal static bool TryDeriveFromCache(string path1, out string result) + { + if (CacheDirectory is null or []) + { + result = null; + return false; + } + + result = Path.Combine(CacheDirectory, path1); + return true; + } + + internal static bool TryDeriveFromCache(string path1, string path2, out string result) + { + if (CacheDirectory is null or []) + { + result = null; + return false; + } + + result = Path.Combine(CacheDirectory, path1, path2); + return true; + } + // format files internal static readonly string[] FormatFileNames = new string[] { @@ -218,6 +247,17 @@ internal static class CommonEnvVariableNames #endif } + private static string SafeDeriveFromSpecialFolder(Environment.SpecialFolder specialFolder, string subPath) + { + string basePath = Environment.GetFolderPath(specialFolder, Environment.SpecialFolderOption.DoNotVerify); + if (string.IsNullOrWhiteSpace(basePath)) + { + return string.Empty; + } + + return Path.Join(basePath, subPath); + } + #if UNIX private static string s_tempHome = null; @@ -360,7 +400,7 @@ internal static string GetFolderPath(Environment.SpecialFolder folder) _ => throw new NotSupportedException() }; #else - return Environment.GetFolderPath(folder); + return Environment.GetFolderPath(folder, Environment.SpecialFolderOption.DoNotVerify); #endif } diff --git a/src/System.Management.Automation/engine/CommandDiscovery.cs b/src/System.Management.Automation/engine/CommandDiscovery.cs index 561a33ccba8..e07520a1238 100644 --- a/src/System.Management.Automation/engine/CommandDiscovery.cs +++ b/src/System.Management.Automation/engine/CommandDiscovery.cs @@ -1218,11 +1218,17 @@ internal LookupPathCollection GetLookupDirectoryPaths() string tempDir = directory.TrimStart(); if (tempDir.EqualsOrdinalIgnoreCase("~")) { - tempDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + tempDir = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile, + Environment.SpecialFolderOption.DoNotVerify); } else if (tempDir.StartsWith("~" + Path.DirectorySeparatorChar)) { - tempDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + Path.DirectorySeparatorChar + tempDir.Substring(2); + tempDir = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile, + Environment.SpecialFolderOption.DoNotVerify) + + Path.DirectorySeparatorChar + + tempDir.Substring(2); } _cachedPath.Add(tempDir); diff --git a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs index a701b0745c8..39d9b586aa6 100644 --- a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs +++ b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs @@ -664,6 +664,11 @@ private static byte[] GetHeader() public void QueueSerialization() { + if (string.IsNullOrEmpty(s_cacheStoreLocation)) + { + return; + } + // We expect many modules to rapidly call for serialization. // Instead of doing it right away, we'll queue a task that starts writing // after it seems like we've stopped adding stuff to write out. This is @@ -1121,7 +1126,7 @@ static AnalysisCacheData() cacheFileName = string.Create(CultureInfo.InvariantCulture, $"{cacheFileName}-{hashString}"); } - s_cacheStoreLocation = Path.Combine(Platform.CacheDirectory, cacheFileName); + Platform.TryDeriveFromCache(cacheFileName, out s_cacheStoreLocation); } } diff --git a/src/System.Management.Automation/engine/PSConfiguration.cs b/src/System.Management.Automation/engine/PSConfiguration.cs index e321423f768..419a4cae95f 100644 --- a/src/System.Management.Automation/engine/PSConfiguration.cs +++ b/src/System.Management.Automation/engine/PSConfiguration.cs @@ -89,7 +89,10 @@ private PowerShellConfig() // Note: This directory may or may not exist depending upon the execution scenario. // Writes will attempt to create the directory if it does not already exist. perUserConfigDirectory = Platform.ConfigDirectory; - perUserConfigFile = Path.Combine(perUserConfigDirectory, ConfigFileName); + if (!string.IsNullOrEmpty(perUserConfigDirectory)) + { + perUserConfigFile = Path.Combine(perUserConfigDirectory, ConfigFileName); + } emptyConfig = new JObject(); configRoots = new JObject[2]; @@ -387,6 +390,11 @@ internal PSKeyword GetLogKeywords() private T ReadValueFromFile<T>(ConfigScope scope, string key, T defaultValue = default) { string fileName = GetConfigFilePath(scope); + if (string.IsNullOrEmpty(fileName)) + { + return defaultValue; + } + JObject configData = configRoots[(int)scope]; if (configData == null) diff --git a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs index 003625791b1..caf3c5e15d8 100644 --- a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs +++ b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs @@ -208,10 +208,11 @@ internal static string GetFullProfileFileName(string shellId, bool forCurrentUse else { basePath = GetAllUsersFolderPath(shellId); - if (string.IsNullOrEmpty(basePath)) - { - return string.Empty; - } + } + + if (string.IsNullOrEmpty(basePath)) + { + return string.Empty; } string profileName = useTestProfile ? "profile_test.ps1" : "profile.ps1"; diff --git a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs index 29fc5fa1f7f..5f51ba15751 100644 --- a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs +++ b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs @@ -1156,6 +1156,11 @@ internal static string GetTranscriptPath(string baseDirectory, bool includeDate) } } + if (string.IsNullOrEmpty(baseDirectory)) + { + return string.Empty; + } + if (includeDate) { baseDirectory = Path.Combine(baseDirectory, DateTime.Now.ToString("yyyyMMdd", CultureInfo.InvariantCulture)); diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index cffedb7c579..0fb3b9d94a2 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -164,6 +164,8 @@ public static class ApplicationInsightsTelemetry private static readonly HashSet<string> s_knownSubsystemNames; + private static readonly string s_uuidPath; + /// <summary>Gets a value indicating whether telemetry can be sent.</summary> public static bool CanSendTelemetry { get; private set; } @@ -177,469 +179,474 @@ public static class ApplicationInsightsTelemetry static ApplicationInsightsTelemetry() { // If we can't send telemetry, there's no reason to do any of this - CanSendTelemetry = !GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false); - if (CanSendTelemetry) + CanSendTelemetry = !GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false) + && Platform.TryDeriveFromCache("telemetry.uuid", out s_uuidPath); + + if (!CanSendTelemetry) { - s_sessionId = Guid.NewGuid().ToString(); - TelemetryConfiguration configuration = TelemetryConfiguration.CreateDefault(); - configuration.ConnectionString = "InstrumentationKey=" + _psCoreTelemetryKey; + return; + } - // Set this to true to reduce latency during development - configuration.TelemetryChannel.DeveloperMode = false; + s_sessionId = Guid.NewGuid().ToString(); + TelemetryConfiguration configuration = TelemetryConfiguration.CreateDefault(); + configuration.ConnectionString = "InstrumentationKey=" + _psCoreTelemetryKey; - // Be sure to obscure any information about the client node name. - configuration.TelemetryInitializers.Add(new NameObscurerTelemetryInitializer()); + // Set this to true to reduce latency during development + configuration.TelemetryChannel.DeveloperMode = false; - s_telemetryClient = new TelemetryClient(configuration); + // Be sure to obscure any information about the client node name. + configuration.TelemetryInitializers.Add(new NameObscurerTelemetryInitializer()); - // use a hashset when looking for module names, it should be quicker than a string comparison - s_knownModules = new HashSet<string>(StringComparer.OrdinalIgnoreCase) - { - "AADRM", - "activedirectory", - "adcsadministration", - "adcsdeployment", - "addsadministration", - "addsdeployment", - "adfs", - "adrms", - "adrmsadmin", - "agpm", - "appbackgroundtask", - "applocker", - "appv", - "appvclient", - "appvsequencer", - "appvserver", - "appx", - "assignedaccess", - "Az", - "Az.Accounts", - "Az.Advisor", - "Az.Aks", - "Az.AlertsManagement", - "Az.AnalysisServices", - "Az.ApiManagement", - "Az.ApplicationInsights", - "Az.Attestation", - "Az.Automation", - "Az.Batch", - "Az.Billing", - "Az.Blueprint", - "Az.Cdn", - "Az.CognitiveServices", - "Az.Compute", - "Az.ContainerInstance", - "Az.ContainerRegistry", - "Az.DataBox", - "Az.DataFactory", - "Az.DataLakeAnalytics", - "Az.DataLakeStore", - "Az.DataMigration", - "Az.DataShare", - "Az.DeploymentManager", - "Az.DeviceProvisioningServices", - "Az.DevSpaces", - "Az.DevTestLabs", - "Az.Dns", - "Az.EventGrid", - "Az.EventHub", - "Az.FrontDoor", - "Az.GuestConfiguration", - "Az.HDInsight", - "Az.HealthcareApis", - "Az.IotCentral", - "Az.IotHub", - "Az.KeyVault", - "Az.Kusto", - "Az.LogicApp", - "Az.MachineLearning", - "Az.ManagedServiceIdentity", - "Az.ManagedServices", - "Az.ManagementPartner", - "Az.Maps", - "Az.MarketplaceOrdering", - "Az.Media", - "Az.MixedReality", - "Az.Monitor", - "Az.NetAppFiles", - "Az.Network", - "Az.NotificationHubs", - "Az.OperationalInsights", - "Az.Peering", - "Az.PolicyInsights", - "Az.PowerBIEmbedded", - "Az.PrivateDns", - "Az.RecoveryServices", - "Az.RedisCache", - "Az.Relay", - "Az.Reservations", - "Az.ResourceGraph", - "Az.Resources", - "Az.Search", - "Az.Security", - "Az.ServiceBus", - "Az.ServiceFabric", - "Az.SignalR", - "Az.Sql", - "Az.Storage", - "Az.StorageSync", - "Az.StorageTable", - "Az.StreamAnalytics", - "Az.Subscription", - "Az.Tools.Predictor", - "Az.TrafficManager", - "Az.Websites", - "Azs.Azurebridge.Admin", - "Azs.Backup.Admin", - "Azs.Commerce.Admin", - "Azs.Compute.Admin", - "Azs.Fabric.Admin", - "Azs.Gallery.Admin", - "Azs.Infrastructureinsights.Admin", - "Azs.Keyvault.Admin", - "Azs.Network.Admin", - "Azs.Storage.Admin", - "Azs.Subscriptions", - "Azs.Subscriptions.Admin", - "Azs.Update.Admin", - "AzStorageTable", - "Azure", - "Azure.AnalysisServices", - "Azure.Storage", - "AzureAD", - "AzureInformationProtection", - "AzureRM.Aks", - "AzureRM.AnalysisServices", - "AzureRM.ApiManagement", - "AzureRM.ApplicationInsights", - "AzureRM.Automation", - "AzureRM.Backup", - "AzureRM.Batch", - "AzureRM.Billing", - "AzureRM.Cdn", - "AzureRM.CognitiveServices", - "AzureRm.Compute", - "AzureRM.Compute.ManagedService", - "AzureRM.Consumption", - "AzureRM.ContainerInstance", - "AzureRM.ContainerRegistry", - "AzureRM.DataFactories", - "AzureRM.DataFactoryV2", - "AzureRM.DataLakeAnalytics", - "AzureRM.DataLakeStore", - "AzureRM.DataMigration", - "AzureRM.DeploymentManager", - "AzureRM.DeviceProvisioningServices", - "AzureRM.DevSpaces", - "AzureRM.DevTestLabs", - "AzureRm.Dns", - "AzureRM.EventGrid", - "AzureRM.EventHub", - "AzureRM.FrontDoor", - "AzureRM.HDInsight", - "AzureRm.Insights", - "AzureRM.IotCentral", - "AzureRM.IotHub", - "AzureRm.Keyvault", - "AzureRM.LocationBasedServices", - "AzureRM.LogicApp", - "AzureRM.MachineLearning", - "AzureRM.MachineLearningCompute", - "AzureRM.ManagedServiceIdentity", - "AzureRM.ManagementPartner", - "AzureRM.Maps", - "AzureRM.MarketplaceOrdering", - "AzureRM.Media", - "AzureRM.Network", - "AzureRM.NotificationHubs", - "AzureRM.OperationalInsights", - "AzureRM.PolicyInsights", - "AzureRM.PowerBIEmbedded", - "AzureRM.Profile", - "AzureRM.RecoveryServices", - "AzureRM.RecoveryServices.Backup", - "AzureRM.RecoveryServices.SiteRecovery", - "AzureRM.RedisCache", - "AzureRM.Relay", - "AzureRM.Reservations", - "AzureRM.ResourceGraph", - "AzureRM.Resources", - "AzureRM.Scheduler", - "AzureRM.Search", - "AzureRM.Security", - "AzureRM.ServerManagement", - "AzureRM.ServiceBus", - "AzureRM.ServiceFabric", - "AzureRM.SignalR", - "AzureRM.SiteRecovery", - "AzureRM.Sql", - "AzureRm.Storage", - "AzureRM.StorageSync", - "AzureRM.StreamAnalytics", - "AzureRM.Subscription", - "AzureRM.Subscription.Preview", - "AzureRM.Tags", - "AzureRM.TrafficManager", - "AzureRm.UsageAggregates", - "AzureRm.Websites", - "AzureRmStorageTable", - "bestpractices", - "bitlocker", - "bitstransfer", - "booteventcollector", - "branchcache", - "CimCmdlets", - "clusterawareupdating", - "CompatPowerShellGet", - "configci", - "ConfigurationManager", - "CompletionPredictor", - "DataProtectionManager", - "dcbqos", - "deduplication", - "defender", - "devicehealthattestation", - "dfsn", - "dfsr", - "dhcpserver", - "directaccessclient", - "directaccessclientcomponent", - "directaccessclientcomponents", - "dism", - "dnsclient", - "dnsserver", - "ElasticDatabaseJobs", - "EventTracingManagement", - "failoverclusters", - "fileserverresourcemanager", - "FIMAutomation", - "GPRegistryPolicy", - "grouppolicy", - "hardwarecertification", - "hcs", - "hgsattestation", - "hgsclient", - "hgsdiagnostics", - "hgskeyprotection", - "hgsserver", - "hnvdiagnostics", - "hostcomputeservice", - "hpc", - "HPC.ACM", - "HPC.ACM.API.PS", - "HPCPack2016", - "hyper-v", - "IISAdministration", - "international", - "ipamserver", - "iscsi", - "iscsitarget", - "ISE", - "kds", - "Microsoft.MBAM", - "Microsoft.MEDV", - "MgmtSvcAdmin", - "MgmtSvcConfig", - "MgmtSvcMySql", - "MgmtSvcSqlServer", - "Microsoft.AzureStack.ReadinessChecker", - "Microsoft.Crm.PowerShell", - "Microsoft.DiagnosticDataViewer", - "Microsoft.DirectoryServices.MetadirectoryServices.Config", - "Microsoft.Dynamics.Nav.Apps.Management", - "Microsoft.Dynamics.Nav.Apps.Tools", - "Microsoft.Dynamics.Nav.Ide", - "Microsoft.Dynamics.Nav.Management", - "Microsoft.Dynamics.Nav.Model.Tools", - "Microsoft.Dynamics.Nav.Model.Tools.Crm", - "Microsoft.EnterpriseManagement.Warehouse.Cmdlets", - "Microsoft.Medv.Administration.Commands.WorkspacePackager", - "Microsoft.PowerApps.Checker.PowerShell", - "Microsoft.PowerShell.Archive", - "Microsoft.PowerShell.ConsoleGuiTools", - "Microsoft.PowerShell.Core", - "Microsoft.PowerShell.Crescendo", - "Microsoft.PowerShell.Diagnostics", - "Microsoft.PowerShell.Host", - "Microsoft.PowerShell.LocalAccounts", - "Microsoft.PowerShell.Management", - "Microsoft.PowerShell.ODataUtils", - "Microsoft.PowerShell.Operation.Validation", - "Microsoft.PowerShell.PSAdapter", - "Microsoft.PowerShell.PSResourceGet", - "Microsoft.PowerShell.RemotingTools", - "Microsoft.PowerShell.SecretManagement", - "Microsoft.PowerShell.SecretStore", - "Microsoft.PowerShell.Security", - "Microsoft.PowerShell.TextUtility", - "Microsoft.PowerShell.Utility", - "Microsoft.SharePoint.Powershell", - "Microsoft.SystemCenter.ServiceManagementAutomation", - "Microsoft.Windows.ServerManager.Migration", - "Microsoft.WSMan.Management", - "Microsoft.Xrm.OnlineManagementAPI", - "Microsoft.Xrm.Tooling.CrmConnector.PowerShell", - "Microsoft.Xrm.Tooling.PackageDeployment", - "Microsoft.Xrm.Tooling.PackageDeployment.Powershell", - "Microsoft.Xrm.Tooling.Testing", - "MicrosoftPowerBIMgmt", - "MicrosoftPowerBIMgmt.Data", - "MicrosoftPowerBIMgmt.Profile", - "MicrosoftPowerBIMgmt.Reports", - "MicrosoftPowerBIMgmt.Workspaces", - "MicrosoftStaffHub", - "MicrosoftTeams", - "MIMPAM", - "mlSqlPs", - "MMAgent", - "MPIO", - "MsDtc", - "MSMQ", - "MSOnline", - "MSOnlineBackup", - "WmsCmdlets", - "WmsCmdlets3", - "NanoServerImageGenerator", - "NAVWebClientManagement", - "NetAdapter", - "NetConnection", - "NetEventPacketCapture", - "Netlbfo", - "Netldpagent", - "NetNat", - "Netqos", - "NetSecurity", - "NetSwitchtTeam", - "Nettcpip", - "Netwnv", - "NetworkConnectivity", - "NetworkConnectivityStatus", - "NetworkController", - "NetworkControllerDiagnostics", - "NetworkloadBalancingClusters", - "NetworkSwitchManager", - "NetworkTransition", - "NFS", - "NPS", - "OfficeWebapps", - "OperationsManager", - "PackageManagement", - "PartnerCenter", - "pcsvdevice", - "pef", - "Pester", - "pkiclient", - "platformidentifier", - "pnpdevice", - "PowerShellEditorServices", - "PowerShellGet", - "powershellwebaccess", - "printmanagement", - "ProcessMitigations", - "provisioning", - "PSDesiredStateConfiguration", - "PSDiagnostics", - "PSReadLine", - "PSScheduledJob", - "PSScriptAnalyzer", - "PSWorkflow", - "PSWorkflowUtility", - "RemoteAccess", - "RemoteDesktop", - "RemoteDesktopServices", - "ScheduledTasks", - "Secureboot", - "ServerCore", - "ServerManager", - "ServerManagerTasks", - "ServerMigrationcmdlets", - "ServiceFabric", - "Microsoft.Online.SharePoint.PowerShell", - "shieldedvmdatafile", - "shieldedvmprovisioning", - "shieldedvmtemplate", - "SkypeOnlineConnector", - "SkypeForBusinessHybridHealth", - "smbshare", - "smbwitness", - "smisconfig", - "softwareinventorylogging", - "SPFAdmin", - "Microsoft.SharePoint.MigrationTool.PowerShell", - "sqlps", - "SqlServer", - "StartLayout", - "StartScreen", - "Storage", - "StorageDsc", - "storageqos", - "Storagereplica", - "Storagespaces", - "Syncshare", - "System.Center.Service.Manager", - "TLS", - "TroubleshootingPack", - "TrustedPlatformModule", - "UEV", - "UpdateServices", - "UserAccessLogging", - "vamt", - "VirtualMachineManager", - "vpnclient", - "WasPSExt", - "WDAC", - "WDS", - "WebAdministration", - "WebAdministrationDsc", - "WebApplicationProxy", - "WebSites", - "Whea", - "WhiteboardAdmin", - "WindowsDefender", - "WindowsDefenderDsc", - "WindowsDeveloperLicense", - "WindowsDiagnosticData", - "WindowsErrorReporting", - "WindowServerRackup", - "WindowsSearch", - "WindowsServerBackup", - "WindowsUpdate", - "WinGetCommandNotFound", - "wsscmdlets", - "wsssetup", - "wsus", - "xActiveDirectory", - "xBitLocker", - "xDefender", - "xDhcpServer", - "xDismFeature", - "xDnsServer", - "xHyper-V", - "xHyper-VBackup", - "xPSDesiredStateConfiguration", - "xSmbShare", - "xSqlPs", - "xStorage", - "xWebAdministration", - "xWindowsUpdate", - }; - - // use a hashset when looking for module names, it should be quicker than a string comparison - s_knownModuleTags = new HashSet<string>(StringComparer.OrdinalIgnoreCase) - { - "CrescendoBuilt", - }; + s_telemetryClient = new TelemetryClient(configuration); - s_uniqueUserIdentifier = GetUniqueIdentifier().ToString(); - s_knownSubsystemNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) - { - "Completion", - "General Feedback", - "Windows Package Manager - WinGet", - "Az Predictor" - }; - } + // use a hashset when looking for module names, it should be quicker than a string comparison + s_knownModules = new HashSet<string>(StringComparer.OrdinalIgnoreCase) + { + "AADRM", + "activedirectory", + "adcsadministration", + "adcsdeployment", + "addsadministration", + "addsdeployment", + "adfs", + "adrms", + "adrmsadmin", + "agpm", + "AIShell", + "appbackgroundtask", + "applocker", + "appv", + "appvclient", + "appvsequencer", + "appvserver", + "appx", + "assignedaccess", + "Az", + "Az.Accounts", + "Az.Advisor", + "Az.Aks", + "Az.AlertsManagement", + "Az.AnalysisServices", + "Az.ApiManagement", + "Az.ApplicationInsights", + "Az.Attestation", + "Az.Automation", + "Az.Batch", + "Az.Billing", + "Az.Blueprint", + "Az.Cdn", + "Az.CognitiveServices", + "Az.Compute", + "Az.ContainerInstance", + "Az.ContainerRegistry", + "Az.DataBox", + "Az.DataFactory", + "Az.DataLakeAnalytics", + "Az.DataLakeStore", + "Az.DataMigration", + "Az.DataShare", + "Az.DeploymentManager", + "Az.DeviceProvisioningServices", + "Az.DevSpaces", + "Az.DevTestLabs", + "Az.Dns", + "Az.EventGrid", + "Az.EventHub", + "Az.FrontDoor", + "Az.GuestConfiguration", + "Az.HDInsight", + "Az.HealthcareApis", + "Az.IotCentral", + "Az.IotHub", + "Az.KeyVault", + "Az.Kusto", + "Az.LogicApp", + "Az.MachineLearning", + "Az.ManagedServiceIdentity", + "Az.ManagedServices", + "Az.ManagementPartner", + "Az.Maps", + "Az.MarketplaceOrdering", + "Az.Media", + "Az.MixedReality", + "Az.Monitor", + "Az.NetAppFiles", + "Az.Network", + "Az.NotificationHubs", + "Az.OperationalInsights", + "Az.Peering", + "Az.PolicyInsights", + "Az.PowerBIEmbedded", + "Az.PrivateDns", + "Az.RecoveryServices", + "Az.RedisCache", + "Az.Relay", + "Az.Reservations", + "Az.ResourceGraph", + "Az.Resources", + "Az.Search", + "Az.Security", + "Az.ServiceBus", + "Az.ServiceFabric", + "Az.SignalR", + "Az.Sql", + "Az.Storage", + "Az.StorageSync", + "Az.StorageTable", + "Az.StreamAnalytics", + "Az.Subscription", + "Az.Tools.Predictor", + "Az.TrafficManager", + "Az.Websites", + "Azs.Azurebridge.Admin", + "Azs.Backup.Admin", + "Azs.Commerce.Admin", + "Azs.Compute.Admin", + "Azs.Fabric.Admin", + "Azs.Gallery.Admin", + "Azs.Infrastructureinsights.Admin", + "Azs.Keyvault.Admin", + "Azs.Network.Admin", + "Azs.Storage.Admin", + "Azs.Subscriptions", + "Azs.Subscriptions.Admin", + "Azs.Update.Admin", + "AzStorageTable", + "Azure", + "Azure.AnalysisServices", + "Azure.Storage", + "AzureAD", + "AzureInformationProtection", + "AzureRM.Aks", + "AzureRM.AnalysisServices", + "AzureRM.ApiManagement", + "AzureRM.ApplicationInsights", + "AzureRM.Automation", + "AzureRM.Backup", + "AzureRM.Batch", + "AzureRM.Billing", + "AzureRM.Cdn", + "AzureRM.CognitiveServices", + "AzureRm.Compute", + "AzureRM.Compute.ManagedService", + "AzureRM.Consumption", + "AzureRM.ContainerInstance", + "AzureRM.ContainerRegistry", + "AzureRM.DataFactories", + "AzureRM.DataFactoryV2", + "AzureRM.DataLakeAnalytics", + "AzureRM.DataLakeStore", + "AzureRM.DataMigration", + "AzureRM.DeploymentManager", + "AzureRM.DeviceProvisioningServices", + "AzureRM.DevSpaces", + "AzureRM.DevTestLabs", + "AzureRm.Dns", + "AzureRM.EventGrid", + "AzureRM.EventHub", + "AzureRM.FrontDoor", + "AzureRM.HDInsight", + "AzureRm.Insights", + "AzureRM.IotCentral", + "AzureRM.IotHub", + "AzureRm.Keyvault", + "AzureRM.LocationBasedServices", + "AzureRM.LogicApp", + "AzureRM.MachineLearning", + "AzureRM.MachineLearningCompute", + "AzureRM.ManagedServiceIdentity", + "AzureRM.ManagementPartner", + "AzureRM.Maps", + "AzureRM.MarketplaceOrdering", + "AzureRM.Media", + "AzureRM.Network", + "AzureRM.NotificationHubs", + "AzureRM.OperationalInsights", + "AzureRM.PolicyInsights", + "AzureRM.PowerBIEmbedded", + "AzureRM.Profile", + "AzureRM.RecoveryServices", + "AzureRM.RecoveryServices.Backup", + "AzureRM.RecoveryServices.SiteRecovery", + "AzureRM.RedisCache", + "AzureRM.Relay", + "AzureRM.Reservations", + "AzureRM.ResourceGraph", + "AzureRM.Resources", + "AzureRM.Scheduler", + "AzureRM.Search", + "AzureRM.Security", + "AzureRM.ServerManagement", + "AzureRM.ServiceBus", + "AzureRM.ServiceFabric", + "AzureRM.SignalR", + "AzureRM.SiteRecovery", + "AzureRM.Sql", + "AzureRm.Storage", + "AzureRM.StorageSync", + "AzureRM.StreamAnalytics", + "AzureRM.Subscription", + "AzureRM.Subscription.Preview", + "AzureRM.Tags", + "AzureRM.TrafficManager", + "AzureRm.UsageAggregates", + "AzureRm.Websites", + "AzureRmStorageTable", + "bestpractices", + "bitlocker", + "bitstransfer", + "booteventcollector", + "branchcache", + "CimCmdlets", + "clusterawareupdating", + "CompatPowerShellGet", + "configci", + "ConfigurationManager", + "CompletionPredictor", + "DataProtectionManager", + "dcbqos", + "deduplication", + "defender", + "devicehealthattestation", + "dfsn", + "dfsr", + "dhcpserver", + "directaccessclient", + "directaccessclientcomponent", + "directaccessclientcomponents", + "dism", + "dnsclient", + "dnsserver", + "ElasticDatabaseJobs", + "EventTracingManagement", + "failoverclusters", + "fileserverresourcemanager", + "FIMAutomation", + "GPRegistryPolicy", + "grouppolicy", + "hardwarecertification", + "hcs", + "hgsattestation", + "hgsclient", + "hgsdiagnostics", + "hgskeyprotection", + "hgsserver", + "hnvdiagnostics", + "hostcomputeservice", + "hpc", + "HPC.ACM", + "HPC.ACM.API.PS", + "HPCPack2016", + "hyper-v", + "IISAdministration", + "international", + "ipamserver", + "iscsi", + "iscsitarget", + "ISE", + "kds", + "Microsoft.MBAM", + "Microsoft.MEDV", + "MgmtSvcAdmin", + "MgmtSvcConfig", + "MgmtSvcMySql", + "MgmtSvcSqlServer", + "Microsoft.AzureStack.ReadinessChecker", + "Microsoft.Crm.PowerShell", + "Microsoft.DiagnosticDataViewer", + "Microsoft.DirectoryServices.MetadirectoryServices.Config", + "Microsoft.Dynamics.Nav.Apps.Management", + "Microsoft.Dynamics.Nav.Apps.Tools", + "Microsoft.Dynamics.Nav.Ide", + "Microsoft.Dynamics.Nav.Management", + "Microsoft.Dynamics.Nav.Model.Tools", + "Microsoft.Dynamics.Nav.Model.Tools.Crm", + "Microsoft.EnterpriseManagement.Warehouse.Cmdlets", + "Microsoft.Medv.Administration.Commands.WorkspacePackager", + "Microsoft.PowerApps.Checker.PowerShell", + "Microsoft.PowerShell.Archive", + "Microsoft.PowerShell.ConsoleGuiTools", + "Microsoft.PowerShell.Core", + "Microsoft.PowerShell.Crescendo", + "Microsoft.PowerShell.Diagnostics", + "Microsoft.PowerShell.Host", + "Microsoft.PowerShell.LocalAccounts", + "Microsoft.PowerShell.Management", + "Microsoft.PowerShell.ODataUtils", + "Microsoft.PowerShell.Operation.Validation", + "Microsoft.PowerShell.PSAdapter", + "Microsoft.PowerShell.PSResourceGet", + "Microsoft.PowerShell.RemotingTools", + "Microsoft.PowerShell.SecretManagement", + "Microsoft.PowerShell.SecretStore", + "Microsoft.PowerShell.Security", + "Microsoft.PowerShell.TextUtility", + "Microsoft.PowerShell.Utility", + "Microsoft.SharePoint.Powershell", + "Microsoft.SystemCenter.ServiceManagementAutomation", + "Microsoft.Windows.ServerManager.Migration", + "Microsoft.WSMan.Management", + "Microsoft.Xrm.OnlineManagementAPI", + "Microsoft.Xrm.Tooling.CrmConnector.PowerShell", + "Microsoft.Xrm.Tooling.PackageDeployment", + "Microsoft.Xrm.Tooling.PackageDeployment.Powershell", + "Microsoft.Xrm.Tooling.Testing", + "MicrosoftPowerBIMgmt", + "MicrosoftPowerBIMgmt.Data", + "MicrosoftPowerBIMgmt.Profile", + "MicrosoftPowerBIMgmt.Reports", + "MicrosoftPowerBIMgmt.Workspaces", + "MicrosoftStaffHub", + "MicrosoftTeams", + "MIMPAM", + "mlSqlPs", + "MMAgent", + "MPIO", + "MsDtc", + "MSMQ", + "MSOnline", + "MSOnlineBackup", + "WmsCmdlets", + "WmsCmdlets3", + "NanoServerImageGenerator", + "NAVWebClientManagement", + "NetAdapter", + "NetConnection", + "NetEventPacketCapture", + "Netlbfo", + "Netldpagent", + "NetNat", + "Netqos", + "NetSecurity", + "NetSwitchtTeam", + "Nettcpip", + "Netwnv", + "NetworkConnectivity", + "NetworkConnectivityStatus", + "NetworkController", + "NetworkControllerDiagnostics", + "NetworkloadBalancingClusters", + "NetworkSwitchManager", + "NetworkTransition", + "NFS", + "NPS", + "OfficeWebapps", + "OperationsManager", + "PackageManagement", + "PartnerCenter", + "pcsvdevice", + "pef", + "Pester", + "pkiclient", + "platformidentifier", + "pnpdevice", + "PowerShellEditorServices", + "PowerShellGet", + "powershellwebaccess", + "printmanagement", + "ProcessMitigations", + "provisioning", + "PSDesiredStateConfiguration", + "PSDiagnostics", + "PSReadLine", + "PSScheduledJob", + "PSScriptAnalyzer", + "PSWorkflow", + "PSWorkflowUtility", + "RemoteAccess", + "RemoteDesktop", + "RemoteDesktopServices", + "ScheduledTasks", + "Secureboot", + "ServerCore", + "ServerManager", + "ServerManagerTasks", + "ServerMigrationcmdlets", + "ServiceFabric", + "Microsoft.Online.SharePoint.PowerShell", + "shieldedvmdatafile", + "shieldedvmprovisioning", + "shieldedvmtemplate", + "SkypeOnlineConnector", + "SkypeForBusinessHybridHealth", + "smbshare", + "smbwitness", + "smisconfig", + "softwareinventorylogging", + "SPFAdmin", + "Microsoft.SharePoint.MigrationTool.PowerShell", + "sqlps", + "SqlServer", + "StartLayout", + "StartScreen", + "Storage", + "StorageDsc", + "storageqos", + "Storagereplica", + "Storagespaces", + "Syncshare", + "System.Center.Service.Manager", + "TLS", + "TroubleshootingPack", + "TrustedPlatformModule", + "UEV", + "UpdateServices", + "UserAccessLogging", + "vamt", + "VirtualMachineManager", + "vpnclient", + "WasPSExt", + "WDAC", + "WDS", + "WebAdministration", + "WebAdministrationDsc", + "WebApplicationProxy", + "WebSites", + "Whea", + "WhiteboardAdmin", + "WindowsDefender", + "WindowsDefenderDsc", + "WindowsDeveloperLicense", + "WindowsDiagnosticData", + "WindowsErrorReporting", + "WindowServerRackup", + "WindowsSearch", + "WindowsServerBackup", + "WindowsUpdate", + "WinGetCommandNotFound", + "wsscmdlets", + "wsssetup", + "wsus", + "xActiveDirectory", + "xBitLocker", + "xDefender", + "xDhcpServer", + "xDismFeature", + "xDnsServer", + "xHyper-V", + "xHyper-VBackup", + "xPSDesiredStateConfiguration", + "xSmbShare", + "xSqlPs", + "xStorage", + "xWebAdministration", + "xWindowsUpdate", + }; + + // use a hashset when looking for module names, it should be quicker than a string comparison + s_knownModuleTags = new HashSet<string>(StringComparer.OrdinalIgnoreCase) + { + "CrescendoBuilt", + }; + + s_uniqueUserIdentifier = GetUniqueIdentifier().ToString(); + s_knownSubsystemNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) + { + "Completion", + "General Feedback", + "Windows Package Manager - WinGet", + "Az Predictor" + }; } /// <summary> @@ -1050,8 +1057,7 @@ private static Guid GetUniqueIdentifier() // Try to get the unique id. If this returns false, we'll // create/recreate the telemetry.uuid file to persist for next startup. Guid id = Guid.Empty; - string uuidPath = Path.Join(Platform.CacheDirectory, "telemetry.uuid"); - if (TryGetIdentifier(uuidPath, out id)) + if (TryGetIdentifier(s_uuidPath, out id)) { return id; } @@ -1066,7 +1072,7 @@ private static Guid GetUniqueIdentifier() m.WaitOne(); try { - return CreateUniqueIdentifierAndFile(uuidPath); + return CreateUniqueIdentifierAndFile(s_uuidPath); } finally { From c3d3fddb705ee7aff240be28efe755a35c4a4c06 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Tue, 19 May 2026 11:32:09 -0700 Subject: [PATCH 272/275] [release/v7.5.7] Update PowerShell telemetry to respect the diagnostics and feedback setting on Windows (#27472) --- .../PowerShell.Core.Instrumentation.man | 202 +++++++++++++++--- .../CoreCLR/CorePsPlatform.cs | 9 +- .../engine/remoting/common/PSETWTracer.cs | 4 + .../utils/Telemetry.cs | 9 + .../utils/WindowsDataCollectionSetting.cs | 185 ++++++++++++++++ .../engine/Basic/Telemetry.Tests.ps1 | 50 +++++ 6 files changed, 427 insertions(+), 32 deletions(-) create mode 100644 src/System.Management.Automation/utils/WindowsDataCollectionSetting.cs diff --git a/src/PowerShell.Core.Instrumentation/PowerShell.Core.Instrumentation.man b/src/PowerShell.Core.Instrumentation/PowerShell.Core.Instrumentation.man index fb221cfe964..bb4e15351e5 100644 --- a/src/PowerShell.Core.Instrumentation/PowerShell.Core.Instrumentation.man +++ b/src/PowerShell.Core.Instrumentation/PowerShell.Core.Instrumentation.man @@ -121,6 +121,18 @@ value="0x3002" version="1" /> + <!--Telemetry events--> + <event + channel="C_OPERATIONAL" + level="win:Error" + message="$(string.PS_PROVIDER.event.E_O_TelemetrySettingError.message)" + opcode="Exception" + symbol="TelemetrySettingError" + task="Telemetry" + template="T_TelemetrySettingError" + value="0x3011" + version="1" + /> <!--M3P events--> <event channel="C_ANALYTIC" @@ -2208,17 +2220,41 @@ value="0x6017" version="1" /> - <event - channel="C_ANALYTIC" - keywords="AmsiState" - level="win:Verbose" - message="$(string.PS_PROVIDER.event.E_A_AmsiState.message)" - opcode="Method" - symbol="AmsiState" - task="Amsi" - template="T_AmsiState" - value="0x4001" - version="1" + <event + channel="C_ANALYTIC" + keywords="AmsiState" + level="win:Verbose" + message="$(string.PS_PROVIDER.event.E_A_AmsiState.message)" + opcode="Method" + symbol="AmsiState" + task="Amsi" + template="T_AmsiState" + value="0x4001" + version="1" + /> + <event + channel="C_ANALYTIC" + keywords="WDACQuery" + level="win:Verbose" + message="$(string.PS_PROVIDER.event.E_A_WDACQuery.message)" + opcode="Method" + symbol="WDACQuery" + task="WDAC" + template="T_WDACQuery" + value="0x4002" + version="1" + /> + <event + channel="C_ANALYTIC" + keywords="WDACAudit" + level="win:Verbose" + message = "$(string.PS_PROVIDER.event.E_A_WDACAudit.message)" + opcode="Method" + symbol="WDACAudit" + task="WDACAudit" + template="T_WDACAudit" + value="0x4003" + version="1" /> </events> <channels> @@ -2409,6 +2445,12 @@ symbol="T_EXPERIMENTALFEATURE" value="107" /> + <task + message="$(string.PS_PROVIDER.task.T_Telemetry.message)" + name="Telemetry" + symbol="T_TELEMETRY" + value="108" + /> <task message="$(string.PS_PROVIDER.task.T_ScheduledJob.message)" name="ScheduledJob" @@ -2427,11 +2469,23 @@ symbol="T_ISEOperation" value="120" /> - <task - message="$(string.PS_PROVIDER.task.T_AmsiState.message)" - name="Amsi" - symbol="T_Amsi" - value="130" + <task + message="$(string.PS_PROVIDER.task.T_AmsiState.message)" + name="Amsi" + symbol="T_Amsi" + value="130" + /> + <task + message="$(string.PS_PROVIDER.task.T_WDACQuery.message)" + name="WDAC" + symbol="T_WDAC" + value="131" + /> + <task + message="$(string.PS_PROVIDER.task.T_WDACAudit.message)" + name="WDACAudit" + symbol="T_WDACAudit" + value="132" /> </tasks> <opcodes> @@ -2593,11 +2647,23 @@ name="PSWorkflow" symbol="K_PSWORKFLOW" /> - <keyword - mask="0x400" - message="$(string.PS_PROVIDER.keyword.K_AmsiState.message)" - name="AmsiState" - symbol="K_AmsiState" + <keyword + mask="0x400" + message="$(string.PS_PROVIDER.keyword.K_AmsiState.message)" + name="AmsiState" + symbol="K_AmsiState" + /> + <keyword + mask="0x800" + message="$(string.PS_PROVIDER.keyword.K_WDACQuery.message)" + name="WDACQuery" + symbol="K_WDACQuery" + /> + <keyword + mask="0x1000" + message="$(string.PS_PROVIDER.keyword.K_WDACAudit.message)" + name="WDACAudit" + symbol="K_WDACAudit" /> </keywords> <maps> @@ -4004,6 +4070,20 @@ name="StackTrace" /> </template> + <template tid="T_TelemetrySettingError"> + <data + inType="win:UnicodeString" + name="Name" + /> + <data + inType="win:UnicodeString" + name="Message" + /> + <data + inType="win:UnicodeString" + name="StackTrace" + /> + </template> <template tid="T_TrackingGuid"> <data inType="win:GUID" @@ -4080,16 +4160,48 @@ name="FileName" /> </template> - <template tid="T_AmsiState"> - <data - inType="win:UnicodeString" - name="Action" + <template tid="T_AmsiState"> + <data + inType="win:UnicodeString" + name="Action" /> - <data - inType="win:UnicodeString" - name="AmsiContext" + <data + inType="win:UnicodeString" + name="AmsiContext" /> - </template> + </template> + <template tid="T_WDACQuery"> + <data + inType="win:UnicodeString" + name="QueryName" + /> + <data + inType="win:UnicodeString" + name="FileName" + /> + <data + inType="win:Int32" + name="QuerySuccess" + /> + <data + inType="win:Int32" + name="QuerySResult" + /> + </template> + <template tid="T_WDACAudit"> + <data + inType="win:UnicodeString" + name="Title" + /> + <data + inType="win:UnicodeString" + name="Message" + /> + <data + inType="win:UnicodeString" + name="FullyQualifiedId" + /> + </template> </templates> </provider> </events> @@ -5535,6 +5647,14 @@ id="PS_PROVIDER.task.T_ExperimentalFeature.message" value="PowerShell Experimental Features" /> + <string + id="PS_PROVIDER.event.E_O_TelemetrySettingError.message" + value="Failed to retrieve diagnostics and feedback setting from Windows.%n Exception: %1 %n Message: %2 %n StackTrace: %3 %n" + /> + <string + id="PS_PROVIDER.task.T_Telemetry.message" + value="PowerShell Telemetry" + /> <string id="PS_PROVIDER.task.T_NamedPipe.message" value="PowerShell Named Pipe IPC" @@ -5719,6 +5839,30 @@ id="PS_PROVIDER.event.E_O_REMOTE_NAMEDPIPE_DISCONNECT.message" value="PowerShell IPC disconnect on process: %1 in AppDomain: %2 for User: %3." /> + <string + id="PS_PROVIDER.event.E_A_WDACQuery.message" + value="WDAC Query. %n %t Query: %1 %n %t File: %2 %n %t SuccessCode: %3 %n %t ResultCode: %4" + /> + <string + id="PS_PROVIDER.keyword.K_WDACQuery.message" + value="WDAC Query" + /> + <string + id="PS_PROVIDER.task.T_WDACQuery.message" + value="WDAC Query" + /> + <string + id="PS_PROVIDER.event.E_A_WDACAudit.message" + value="WDAC Audit. %n %t Title: %1 %n %t Message: %2 %n %t FullyQualifiedId: %3" + /> + <string + id="PS_PROVIDER.keyword.K_WDACAudit.message" + value="WDAC Audit" + /> + <string + id="PS_PROVIDER.task.T_WDACAudit.message" + value="WDAC Audit" + /> </stringTable> </resources> </localization> diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 530493f320a..36a6be4074b 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -179,9 +179,12 @@ public static bool IsStaSupported { int result = Interop.Windows.CoInitializeEx(IntPtr.Zero, Interop.Windows.COINIT_APARTMENTTHREADED); - // If 0 is returned the thread has been initialized for the first time - // as an STA and thus supported and needs to be uninitialized. - if (result > 0) + // Per COM documentation: Each successful call to CoInitializeEx (including S_FALSE) + // must be balanced by a corresponding call to CoUninitialize. + // - S_OK (0) means we initialized for the first time. + // - S_FALSE (1) means already initialized, but still increments the reference count. + // Both require CoUninitialize to decrement the reference count. + if (result >= 0) { Interop.Windows.CoUninitialize(); } diff --git a/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs b/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs index 2fd2dc0a913..989ad33e987 100644 --- a/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs +++ b/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs @@ -166,6 +166,9 @@ internal enum PSEventId : int ExperimentalFeature_InvalidName = 0x3001, ExperimentalFeature_ReadConfig_Error = 0x3002, + // Windows Diagnostics And Usage Data Settings + Telemetry_Setting_Error = 0x3011, + // Scheduled Jobs ScheduledJob_Start = 0xD001, ScheduledJob_Complete = 0xD002, @@ -240,6 +243,7 @@ internal enum PSTask : int ProviderStop = 0x69, ExecutePipeline = 0x6A, ExperimentalFeature = 0x6B, + Telemetry = 0x6C, ScheduledJob = 0x6E, NamedPipe = 0x6F, ISEOperation = 0x78, diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index 0fb3b9d94a2..7134e80df76 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -182,8 +182,17 @@ static ApplicationInsightsTelemetry() CanSendTelemetry = !GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false) && Platform.TryDeriveFromCache("telemetry.uuid", out s_uuidPath); +#if !UNIX + if (CanSendTelemetry) + { + // Respect the diagnostics and feedback setting in Windows. + CanSendTelemetry = WindowsDataCollectionSetting.CanCollectDiagnostics(PlatformDataCollectionLevel.Enhanced); + } +#endif + if (!CanSendTelemetry) { + // Avoid the initialization work if we can't send telemetry. return; } diff --git a/src/System.Management.Automation/utils/WindowsDataCollectionSetting.cs b/src/System.Management.Automation/utils/WindowsDataCollectionSetting.cs new file mode 100644 index 00000000000..5f8b607550a --- /dev/null +++ b/src/System.Management.Automation/utils/WindowsDataCollectionSetting.cs @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#if !UNIX + +using System; +using System.Management.Automation.Internal; +using System.Management.Automation.Tracing; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Microsoft.PowerShell.Telemetry; + +internal enum PlatformDataCollectionLevel : int +{ + /// <summary> + /// Minimum — only security-related data. Enterprise/education editions only. + /// </summary> + Security = 0, + + /// <summary> + /// Device info, capabilities, and basic reliability data. + /// </summary> + Basic = 1, + + /// <summary> + /// More detailed usage and reliability data, including app/feature usage patterns. + /// Removed as a user-facing option in Windows 11 (collapsed into Full). + /// </summary> + Enhanced = 2, + + /// <summary> + /// All of the above plus advanced diagnostics data that can help Microsoft fix problems. + /// </summary> + Full = 3, +} + +/// <summary> +/// Minimal projection of <c>IInspectable</c>, the base interface for all WinRT objects. +/// Slots 3–5 in every WinRT interface vtable (after <c>IUnknown</c>'s QueryInterface/AddRef/Release). +/// </summary> +[GeneratedComInterface] +[Guid("AF86E2E0-B12D-4C6A-9C5A-D7AA65101E90")] +internal partial interface IInspectable +{ + void GetIids(out uint iidCount, out nint iids); + + nint GetRuntimeClassName(); + + int GetTrustLevel(); +} + +/// <summary> +/// Projection of the WinRT interface <c>Windows.System.Profile.IPlatformDiagnosticsAndUsageDataSettingsStatics</c> +/// (IID B6E24C1B-7B1C-4B32-8C62-A66597CE723A). +/// Vtable slots 6–9, following the three <c>IInspectable</c> slots. +/// </summary> +[GeneratedComInterface] +[Guid("B6E24C1B-7B1C-4B32-8C62-A66597CE723A")] +internal partial interface IPlatformDiagnosticsAndUsageDataSettingsStatics : IInspectable +{ + PlatformDataCollectionLevel GetCollectionLevel(); + + long AddCollectionLevelChanged(nint handler); + + void RemoveCollectionLevelChanged(long token); + + // WinRT marshals bool as a byte; use byte to avoid any MarshalAs ambiguity with the source generator. + byte CanCollectDiagnostics(PlatformDataCollectionLevel level); +} + +/// <summary> +/// Wraps <c>Windows.System.Profile.PlatformDiagnosticsAndUsageDataSettings</c> using compile-time COM interop +/// and source-generated P/Invoke. No extra runtime DLLs are required. +/// </summary> +internal static partial class WindowsDataCollectionSetting +{ + /// <summary> + /// Returns <see langword="true"/> if the device's diagnostic data collection policy permits collecting at or above <paramref name="level"/>. + /// </summary> + /// <param name="level">The minimum <see cref="PlatformDataCollectionLevel"/> to test against.</param> + internal static bool CanCollectDiagnostics(PlatformDataCollectionLevel level) + { + const string ClassName = "Windows.System.Profile.PlatformDiagnosticsAndUsageDataSettings"; + + // When initializing WinRT on the calling thread, use the multi-threaded apartment (MTA). + // This is to cover the case where PowerShell gets used in a thread-pool thread. + // See the doc at https://learn.microsoft.com/windows/win32/api/roapi/ne-roapi-ro_init_type + const int RO_INIT_MULTITHREADED = 1; + + // Return values for 'RoInitialize': + // - S_OK (0) - we successfully initialized; must call 'RoUninitialize'. + // - S_FALSE (1) - already initialized with the same apartment type; must still call 'RoUninitialize'. + // - RPC_E_CHANGED_MODE - already initialized with a different apartment type; WinRT still works, do NOT call 'RoUninitialize'. + const int RPC_E_CHANGED_MODE = unchecked((int)0x80010106); + + int initHr = -1; + nint hstring = default; + nint factoryPtr = default; + + try + { + // Initialize WinRT on the calling thread. 'RoGetActivationFactory' requires it. + initHr = RoInitialize(RO_INIT_MULTITHREADED); + if (initHr < 0 && initHr != RPC_E_CHANGED_MODE) + { + // The call to initialize the Windows Runtime failed. + // Throw an exception with the HRESULT error code to provide more context on the failure. + Marshal.ThrowExceptionForHR(initHr); + } + + Marshal.ThrowExceptionForHR( + WindowsCreateString(ClassName, (uint)ClassName.Length, out hstring)); + + Guid iid = new("B6E24C1B-7B1C-4B32-8C62-A66597CE723A"); + Marshal.ThrowExceptionForHR( + RoGetActivationFactory(hstring, ref iid, out factoryPtr)); + + var comWrappers = new StrategyBasedComWrappers(); + var comObject = comWrappers.GetOrCreateObjectForComInstance(factoryPtr, CreateObjectFlags.None); + var platformSetting = (IPlatformDiagnosticsAndUsageDataSettingsStatics)comObject; + + return platformSetting.CanCollectDiagnostics(level) != 0; + } + catch (Exception ex) + { + // Log any exceptions that occur during this process, but swallow them and return false to disable telemetry rather than crashing the product. + // This API is only used to gate telemetry collection, so failure should be non-fatal. + PSEtwLog.LogOperationalError( + PSEventId.Telemetry_Setting_Error, + PSOpcode.Exception, + PSTask.Telemetry, + PSKeyword.UseAlwaysOperational, + ex.GetType().FullName, + ex.Message, + ex.StackTrace); + + return false; + } + finally + { + if (factoryPtr != default) + { + Marshal.Release(factoryPtr); + } + + if (hstring != default) + { + _ = WindowsDeleteString(hstring); + } + + // Per COM documentation: Each successful call to 'RoInitialize' (including S_FALSE) + // must be balanced by a corresponding call to 'RoUninitialize'. + if (initHr >= 0) + { + RoUninitialize(); + } + } + } + + [LibraryImport("api-ms-win-core-winrt-string-l1-1-0.dll", StringMarshalling = StringMarshalling.Utf16)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial int WindowsCreateString( + string sourceString, + uint length, + out nint hstring); + + [LibraryImport("api-ms-win-core-winrt-string-l1-1-0.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial int WindowsDeleteString(nint hstring); + + [LibraryImport("api-ms-win-core-winrt-l1-1-0.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial int RoGetActivationFactory(nint activatableClassId, ref Guid iid, out nint factory); + + [LibraryImport("api-ms-win-core-winrt-l1-1-0.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial int RoInitialize(int initType); + + [LibraryImport("api-ms-win-core-winrt-l1-1-0.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial void RoUninitialize(); +} + +#endif diff --git a/test/powershell/engine/Basic/Telemetry.Tests.ps1 b/test/powershell/engine/Basic/Telemetry.Tests.ps1 index 2378b9e5a66..0da08316a56 100644 --- a/test/powershell/engine/Basic/Telemetry.Tests.ps1 +++ b/test/powershell/engine/Basic/Telemetry.Tests.ps1 @@ -5,8 +5,53 @@ # these tests aren't going to check that telemetry is being sent # only that we're not treating the telemetry.uuid file correctly +function Get-OSTelemetryLevel { + <# + .SYNOPSIS + Returns the effective Windows Telemetry level (0-3). + Logic: Checks GPO overrides, then System preferences, then defaults to 1. + #> + + $gpoPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection" + $sysPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection" + $valueName = "AllowTelemetry" + + # 1. Check the "Managed" Policy (Group Policy) + if (Test-Path $gpoPath) { + $gpoValue = Get-ItemProperty -Path $gpoPath -Name $valueName -ErrorAction SilentlyContinue + if ($gpoValue -and $gpoValue.$valueName) { + return [int]$gpoValue.$valueName + } + } + + # 2. Check the "User/System" Preference (Settings App) + if (Test-Path $sysPath) { + $sysValue = Get-ItemProperty -Path $sysPath -Name $valueName -ErrorAction SilentlyContinue + if ($sysValue -and $sysValue.$valueName) { + return [int]$sysValue.$valueName + } + } + + # 3. Fallback to OS Default (Basic/Required) + return 1 +} + Describe "Telemetry for shell startup" -Tag CI { BeforeAll { + $skipTelemetryTests = $false + + if ($IsWindows) { + ## Skip telemetry tests if the OS telemetry level is less than 2 (Enhanced) -- PS telemetry is disabled in this case. + $osTelemetryLevel = Get-OSTelemetryLevel + $skipTelemetryTests = $osTelemetryLevel -lt 2 + } + + if ($skipTelemetryTests) { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() + $PSDefaultParameterValues["it:skip"] = $true + return + } + # if the telemetry file exists, move it out of the way # the member is internal, but we can retrieve it via reflection $cacheDir = [System.Management.Automation.Platform].GetField("CacheDirectory","NonPublic,Static").GetValue($null) @@ -23,6 +68,11 @@ Describe "Telemetry for shell startup" -Tag CI { } AfterAll { + if ($skipTelemetryTests) { + $global:PSDefaultParameterValues = $originalDefaultParameterValues + return + } + # check and reset the telemetry.uuid file if ( $uuidFileExists ) { if ( Test-Path -Path "${uuidPath}.original" ) { From 359d08e6aabb8b6d63fa59d429192463ae3e45bd Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 20 May 2026 01:46:59 -0400 Subject: [PATCH 273/275] [release/v7.5.7] Update branch for release (#27480) --- CHANGELOG/v7.5/dependencychanges.json | 15 +++ DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 8 +- ...soft.PowerShell.Commands.Management.csproj | 4 +- ...crosoft.PowerShell.Commands.Utility.csproj | 8 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 102 ++++++++-------- .../Microsoft.WSMan.Management.csproj | 4 +- .../PSVersionInfoGenerator.csproj | 6 +- .../System.Management.Automation.csproj | 24 ++-- .../BenchmarkDotNet.Extensions.csproj | 10 +- .../ResultsComparer/ResultsComparer.csproj | 10 +- ...soft.PowerShell.NamedPipeConnection.csproj | 26 ++--- test/tools/TestService/TestService.csproj | 96 +++++++-------- test/tools/WebListener/WebListener.csproj | 6 +- tools/cgmanifest/main/cgmanifest.json | 110 +++++++++--------- 17 files changed, 225 insertions(+), 210 deletions(-) create mode 100644 CHANGELOG/v7.5/dependencychanges.json diff --git a/CHANGELOG/v7.5/dependencychanges.json b/CHANGELOG/v7.5/dependencychanges.json new file mode 100644 index 00000000000..dbfa06a77c7 --- /dev/null +++ b/CHANGELOG/v7.5/dependencychanges.json @@ -0,0 +1,15 @@ +[ + { + "ChangeType": "NonSecurity", + "Branch": "release/v7.5.7", + "PackageId": ".NET SDK", + "FromVersion": "9.0.313", + "ToVersion": "9.0.314", + "VulnerabilityId": [], + "Severity": [], + "VulnerableRanges": [], + "AdvisoryUrls": [], + "Justification": "Updated .NET SDK. Building with the latest SDK is required.", + "TimestampUtc": "2026-05-19T19:07:18.0523394Z" + } +] diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 123a66e4a10..6c9fe55abb4 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "9.0.313", + "sdkImageVersion": "9.0.314", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 135a2663e2e..ce302f61899 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.313" + "version": "9.0.314" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 2884b44d129..d6970e85bd4 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,11 +7,11 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.15" /> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> - <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.15" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.16" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.16" /> + <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.16" /> <ProjectReference Include="..\System.Management.Automation\System.Management.Automation.csproj" /> - <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.16" /> </ItemGroup> <PropertyGroup> diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index edfd9c0322b..bb149dc6c96 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,8 +47,8 @@ <ItemGroup> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.16" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.16" /> </ItemGroup> </Project> diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 91c7d073fc1..23f950bdf79 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -13,8 +13,8 @@ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> - <PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.15" /> - <PackageReference Include="System.Reflection.Metadata" Version="9.0.15" /> + <PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.16" /> + <PackageReference Include="System.Reflection.Metadata" Version="9.0.16" /> <ProjectReference Include="..\System.Management.Automation\System.Management.Automation.csproj" /> <PackageReference Include="Markdig.Signed" Version="0.38.0" /> <PackageReference Include="Microsoft.PowerShell.MarkdownRender" Version="7.2.1" /> @@ -41,8 +41,8 @@ <ItemGroup> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" /> - <PackageReference Include="System.Threading.AccessControl" Version="9.0.15" /> - <PackageReference Include="System.Drawing.Common" Version="9.0.15" /> + <PackageReference Include="System.Threading.AccessControl" Version="9.0.16" /> + <PackageReference Include="System.Drawing.Common" Version="9.0.16" /> <PackageReference Include="JsonSchema.Net" Version="7.2.3" /> </ItemGroup> diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 7149411f3da..a11e815c86a 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ <ItemGroup> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.16" /> </ItemGroup> </Project> diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index d9603fbc4e8..b49a5466769 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,57 +16,57 @@ <ItemGroup> <!-- This section is to force the version of non-direct dependencies --> - <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.15" /> - <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.15" /> - <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.15" /> - <PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.15" /> - <PackageReference Include="runtime.android-arm.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.android-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.android-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.android-x86.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-arm.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-bionic-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-bionic-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-musl-arm.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-musl-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-musl-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.maccatalyst-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.maccatalyst-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.osx-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.osx-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="System.CodeDom" Version="9.0.15" /> - <PackageReference Include="System.ComponentModel.Composition" Version="9.0.15" /> - <PackageReference Include="System.ComponentModel.Composition.Registration" Version="9.0.15" /> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.15" /> - <PackageReference Include="System.Data.Odbc" Version="9.0.15" /> - <PackageReference Include="System.Data.OleDb" Version="9.0.15" /> + <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.16" /> + <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.16" /> + <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.16" /> + <PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.16" /> + <PackageReference Include="runtime.android-arm.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.android-arm64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.android-x64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.android-x86.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-arm.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-arm64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-bionic-arm64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-bionic-x64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-musl-arm.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-musl-arm64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-musl-x64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-x64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.maccatalyst-arm64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.maccatalyst-x64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.osx-arm64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.osx-x64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="System.CodeDom" Version="9.0.16" /> + <PackageReference Include="System.ComponentModel.Composition" Version="9.0.16" /> + <PackageReference Include="System.ComponentModel.Composition.Registration" Version="9.0.16" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.16" /> + <PackageReference Include="System.Data.Odbc" Version="9.0.16" /> + <PackageReference Include="System.Data.OleDb" Version="9.0.16" /> <!-- the following package(s) are from https://github.com/dotnet/fxdac --> <PackageReference Include="System.Data.SqlClient" Version="4.9.1" /> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> - <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.15" /> - <PackageReference Include="System.DirectoryServices" Version="9.0.15" /> - <PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.15" /> - <PackageReference Include="System.DirectoryServices.Protocols" Version="9.0.15" /> - <PackageReference Include="System.Drawing.Common" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.16" /> + <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.16" /> + <PackageReference Include="System.DirectoryServices" Version="9.0.16" /> + <PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.16" /> + <PackageReference Include="System.DirectoryServices.Protocols" Version="9.0.16" /> + <PackageReference Include="System.Drawing.Common" Version="9.0.16" /> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.IO.Packaging" Version="9.0.15" /> - <PackageReference Include="System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="System.Management" Version="9.0.15" /> - <PackageReference Include="System.Net.Http.WinHttpHandler" Version="9.0.15" /> - <PackageReference Include="System.Reflection.Context" Version="9.0.15" /> - <PackageReference Include="System.Runtime.Caching" Version="9.0.15" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.15" /> - <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.15" /> - <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.15" /> - <PackageReference Include="System.Security.Permissions" Version="9.0.15" /> - <PackageReference Include="System.ServiceModel.Syndication" Version="9.0.15" /> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.15" /> - <PackageReference Include="System.Speech" Version="9.0.15" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> - <PackageReference Include="System.Text.Encodings.Web" Version="9.0.15" /> + <PackageReference Include="System.IO.Packaging" Version="9.0.16" /> + <PackageReference Include="System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="System.Management" Version="9.0.16" /> + <PackageReference Include="System.Net.Http.WinHttpHandler" Version="9.0.16" /> + <PackageReference Include="System.Reflection.Context" Version="9.0.16" /> + <PackageReference Include="System.Runtime.Caching" Version="9.0.16" /> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.16" /> + <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.16" /> + <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.16" /> + <PackageReference Include="System.Security.Permissions" Version="9.0.16" /> + <PackageReference Include="System.ServiceModel.Syndication" Version="9.0.16" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.16" /> + <PackageReference Include="System.Speech" Version="9.0.16" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.16" /> + <PackageReference Include="System.Text.Encodings.Web" Version="9.0.16" /> <!-- the following package(s) are from https://github.com/dotnet/wcf they are pinned to the version 4.10.x due to a breaking change in newer versions. @@ -79,10 +79,10 @@ <PackageReference Include="System.ServiceModel.Security" Version="4.10.3" /> <PackageReference Include="System.Private.ServiceModel" Version="4.10.3" /> <!-- the source could not be found for the following package(s) --> - <PackageReference Include="Microsoft.Windows.Compatibility" Version="9.0.15" /> - <PackageReference Include="System.Threading.AccessControl" Version="9.0.15" /> + <PackageReference Include="Microsoft.Windows.Compatibility" Version="9.0.16" /> + <PackageReference Include="System.Threading.AccessControl" Version="9.0.16" /> <PackageReference Include="System.Web.Services.Description" Version="8.0.0" /> - <PackageReference Include="System.Windows.Extensions" Version="9.0.15" /> + <PackageReference Include="System.Windows.Extensions" Version="9.0.16" /> </ItemGroup> <!-- diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 64c28602b39..7fbcd7f21cb 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,11 +7,11 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.16" /> <ProjectReference Include="..\System.Management.Automation\System.Management.Automation.csproj" /> <ProjectReference Include="..\Microsoft.WSMan.Runtime\Microsoft.WSMan.Runtime.csproj" /> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.15" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.16" /> </ItemGroup> <PropertyGroup> diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index d99cddb75b1..a5301f837a0 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -17,8 +17,8 @@ <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" /> <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" /> <PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.4" /> - <PackageReference Include="System.Collections.Immutable" Version="9.0.15" /> - <PackageReference Include="System.Reflection.Metadata" Version="9.0.15" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> + <PackageReference Include="System.Collections.Immutable" Version="9.0.16" /> + <PackageReference Include="System.Reflection.Metadata" Version="9.0.16" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.16" /> </ItemGroup> </Project> diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index cb9734e1469..2531fbe6a5f 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,25 +32,25 @@ <!-- the Application Insights package --> <PackageReference Include="Microsoft.ApplicationInsights" Version="2.22.0" /> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.15" /> - <PackageReference Include="System.CodeDom" Version="9.0.15" /> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.15" /> - <PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.15" /> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> - <PackageReference Include="System.DirectoryServices" Version="9.0.15" /> + <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.16" /> + <PackageReference Include="System.CodeDom" Version="9.0.16" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.16" /> + <PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.16" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.16" /> + <PackageReference Include="System.DirectoryServices" Version="9.0.16" /> <!--PackageReference Include="System.IO.FileSystem.AccessControl" Version="6.0.0-preview.5.21301.5" /--> - <PackageReference Include="System.Management" Version="9.0.15" /> + <PackageReference Include="System.Management" Version="9.0.16" /> <PackageReference Include="System.Security.AccessControl" Version="6.0.1" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.15" /> - <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.15" /> - <PackageReference Include="System.Security.Permissions" Version="9.0.15" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.16" /> + <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.16" /> + <PackageReference Include="System.Security.Permissions" Version="9.0.16" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.16" /> <!-- the following package(s) are from the powershell org --> <PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" /> <PackageReference Include="Microsoft.PowerShell.Native" Version="700.0.0" /> <!-- Signing APIs --> <PackageReference Include="Microsoft.Security.Extensions" Version="1.4.0" /> - <PackageReference Include="System.Windows.Extensions" Version="9.0.15" /> + <PackageReference Include="System.Windows.Extensions" Version="9.0.16" /> </ItemGroup> <PropertyGroup> diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index bd18dde778f..1d2e8ee4c90 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -10,18 +10,18 @@ <PackageReference Include="BenchmarkDotNet.Annotations" Version="0.14.0" /> <PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.14.0" /> <PackageReference Include="Iced" Version="1.21.0" /> - <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.15" /> + <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.16" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" /> <PackageReference Include="Microsoft.Diagnostics.NETCore.Client" Version="0.2.661903" /> <PackageReference Include="Microsoft.Diagnostics.Runtime" Version="3.1.512801" /> <PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.30" /> <PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.4" /> - <PackageReference Include="System.Collections.Immutable" Version="9.0.15" /> - <PackageReference Include="System.IO.Pipelines" Version="9.0.15" /> + <PackageReference Include="System.Collections.Immutable" Version="9.0.16" /> + <PackageReference Include="System.IO.Pipelines" Version="9.0.16" /> <PackageReference Include="System.Management" Version="8.0.0" /> <PackageReference Include="System.Reflection.Metadata" Version="8.0.1" /> - <PackageReference Include="System.Text.Encodings.Web" Version="9.0.15" /> - <PackageReference Include="System.Text.Json" Version="9.0.15" /> + <PackageReference Include="System.Text.Encodings.Web" Version="9.0.16" /> + <PackageReference Include="System.Text.Json" Version="9.0.16" /> </ItemGroup> <ItemGroup> diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index f625a77d03a..94963a5afa3 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -10,7 +10,7 @@ <PackageReference Include="CommandLineParser" Version="2.9.1" /> <PackageReference Include="Iced" Version="1.21.0" /> <PackageReference Include="MarkdownLog.NS20" Version="0.10.1" /> - <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.15" /> + <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.16" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" /> <PackageReference Include="Microsoft.Diagnostics.NETCore.Client" Version="0.2.661903" /> <PackageReference Include="Microsoft.Diagnostics.Runtime" Version="3.1.512801" /> @@ -18,11 +18,11 @@ <PackageReference Include="Newtonsoft.Json" Version="13.0.4" /> <PackageReference Include="BenchmarkDotNet" Version="0.14.0" /> <PackageReference Include="Perfolizer" Version="0.4.0" /> - <PackageReference Include="System.Collections.Immutable" Version="9.0.15" /> - <PackageReference Include="System.IO.Pipelines" Version="9.0.15" /> + <PackageReference Include="System.Collections.Immutable" Version="9.0.16" /> + <PackageReference Include="System.IO.Pipelines" Version="9.0.16" /> <PackageReference Include="System.Management" Version="8.0.0" /> <PackageReference Include="System.Reflection.Metadata" Version="8.0.1" /> - <PackageReference Include="System.Text.Encodings.Web" Version="9.0.15" /> - <PackageReference Include="System.Text.Json" Version="9.0.15" /> + <PackageReference Include="System.Text.Encodings.Web" Version="9.0.16" /> + <PackageReference Include="System.Text.Json" Version="9.0.16" /> </ItemGroup> </Project> diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index c3d9b71a150..c0e44ca15a6 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -17,22 +17,22 @@ <PackageReference Include="Microsoft.ApplicationInsights" Version="2.22.0" /> <PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> <PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" /> - <PackageReference Include="Microsoft.PowerShell.CoreCLR.Eventing" Version="7.5.5" /> + <PackageReference Include="Microsoft.PowerShell.CoreCLR.Eventing" Version="7.5.6" /> <PackageReference Include="Microsoft.PowerShell.Native" Version="7.4.0" /> <PackageReference Include="Microsoft.Security.Extensions" Version="1.3.0" /> - <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.15" /> + <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.16" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.4" /> - <PackageReference Include="System.CodeDom" Version="9.0.15" /> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.15" /> - <PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.15" /> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> - <PackageReference Include="System.DirectoryServices" Version="9.0.15" /> - <PackageReference Include="System.Management" Version="9.0.15" /> + <PackageReference Include="System.CodeDom" Version="9.0.16" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.16" /> + <PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.16" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.16" /> + <PackageReference Include="System.DirectoryServices" Version="9.0.16" /> + <PackageReference Include="System.Management" Version="9.0.16" /> <PackageReference Include="System.Management.Automation" Version="7.5.0-preview.5" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.15" /> - <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.15" /> - <PackageReference Include="System.Security.Permissions" Version="9.0.15" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> - <PackageReference Include="System.Windows.Extensions" Version="9.0.15" /> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.16" /> + <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.16" /> + <PackageReference Include="System.Security.Permissions" Version="9.0.16" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.16" /> + <PackageReference Include="System.Windows.Extensions" Version="9.0.16" /> </ItemGroup> </Project> diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index f7e29ff7745..8d5c273e4f7 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,57 +15,57 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.15" /> - <PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.15" /> - <PackageReference Include="Microsoft.Windows.Compatibility" Version="9.0.15" /> - <PackageReference Include="runtime.android-arm.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.android-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.android-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.android-x86.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-arm.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-bionic-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-bionic-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-musl-arm.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-musl-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-musl-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.linux-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.maccatalyst-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.maccatalyst-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.osx-arm64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="runtime.osx-x64.runtime.native.System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="System.CodeDom" Version="9.0.15" /> - <PackageReference Include="System.ComponentModel.Composition" Version="9.0.15" /> - <PackageReference Include="System.ComponentModel.Composition.Registration" Version="9.0.15" /> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.15" /> - <PackageReference Include="System.Data.Odbc" Version="9.0.15" /> - <PackageReference Include="System.Data.OleDb" Version="9.0.15" /> - <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.15" /> - <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.15" /> - <PackageReference Include="System.DirectoryServices" Version="9.0.15" /> - <PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.15" /> - <PackageReference Include="System.DirectoryServices.Protocols" Version="9.0.15" /> - <PackageReference Include="System.Drawing.Common" Version="9.0.15" /> - <PackageReference Include="System.Formats.Asn1" Version="9.0.15" /> + <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="9.0.16" /> + <PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.16" /> + <PackageReference Include="Microsoft.Windows.Compatibility" Version="9.0.16" /> + <PackageReference Include="runtime.android-arm.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.android-arm64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.android-x64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.android-x86.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-arm.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-arm64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-bionic-arm64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-bionic-x64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-musl-arm.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-musl-arm64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-musl-x64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.linux-x64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.maccatalyst-arm64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.maccatalyst-x64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.osx-arm64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="runtime.osx-x64.runtime.native.System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="System.CodeDom" Version="9.0.16" /> + <PackageReference Include="System.ComponentModel.Composition" Version="9.0.16" /> + <PackageReference Include="System.ComponentModel.Composition.Registration" Version="9.0.16" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.16" /> + <PackageReference Include="System.Data.Odbc" Version="9.0.16" /> + <PackageReference Include="System.Data.OleDb" Version="9.0.16" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="9.0.16" /> + <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.16" /> + <PackageReference Include="System.DirectoryServices" Version="9.0.16" /> + <PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.16" /> + <PackageReference Include="System.DirectoryServices.Protocols" Version="9.0.16" /> + <PackageReference Include="System.Drawing.Common" Version="9.0.16" /> + <PackageReference Include="System.Formats.Asn1" Version="9.0.16" /> <PackageReference Include="System.Data.SqlClient" Version="4.9.1" /> - <PackageReference Include="System.IO.Packaging" Version="9.0.15" /> - <PackageReference Include="System.IO.Ports" Version="9.0.15" /> - <PackageReference Include="System.Management" Version="9.0.15" /> - <PackageReference Include="System.Reflection.Context" Version="9.0.15" /> - <PackageReference Include="System.Runtime.Caching" Version="9.0.15" /> + <PackageReference Include="System.IO.Packaging" Version="9.0.16" /> + <PackageReference Include="System.IO.Ports" Version="9.0.16" /> + <PackageReference Include="System.Management" Version="9.0.16" /> + <PackageReference Include="System.Reflection.Context" Version="9.0.16" /> + <PackageReference Include="System.Runtime.Caching" Version="9.0.16" /> <PackageReference Include="System.Security.AccessControl" Version="6.0.1" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.15" /> - <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.15" /> - <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.15" /> - <PackageReference Include="System.Security.Permissions" Version="9.0.15" /> - <PackageReference Include="System.ServiceModel.Syndication" Version="9.0.15" /> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.15" /> - <PackageReference Include="System.Speech" Version="9.0.15" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> - <PackageReference Include="System.Threading.AccessControl" Version="9.0.15" /> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.16" /> + <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.16" /> + <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.16" /> + <PackageReference Include="System.Security.Permissions" Version="9.0.16" /> + <PackageReference Include="System.ServiceModel.Syndication" Version="9.0.16" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.16" /> + <PackageReference Include="System.Speech" Version="9.0.16" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.16" /> + <PackageReference Include="System.Threading.AccessControl" Version="9.0.16" /> <PackageReference Include="System.Web.Services.Description" Version="8.0.0" /> - <PackageReference Include="System.Windows.Extensions" Version="9.0.15" /> + <PackageReference Include="System.Windows.Extensions" Version="9.0.16" /> </ItemGroup> </Project> diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 51420e6d140..9e182c99484 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,10 +7,10 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="9.0.15" /> - <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.15" /> + <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="9.0.16" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.16" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.4" /> <PackageReference Include="Newtonsoft.Json.Bson" Version="1.0.3" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.15" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.16" /> </ItemGroup> </Project> diff --git a/tools/cgmanifest/main/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json index 380112e0d90..70251f8b2e9 100644 --- a/tools/cgmanifest/main/cgmanifest.json +++ b/tools/cgmanifest/main/cgmanifest.json @@ -1,5 +1,4 @@ { - "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -86,7 +85,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -116,7 +115,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -156,7 +155,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -166,7 +165,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -176,7 +175,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -196,7 +195,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -206,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -216,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -226,7 +225,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -236,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -246,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -256,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -266,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -276,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -286,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -296,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -306,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -316,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -326,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -346,7 +345,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -356,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -366,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -426,7 +425,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -446,7 +445,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -456,7 +455,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -466,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -476,7 +475,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -486,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -506,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.DiagnosticSource", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -516,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -526,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -536,7 +535,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -546,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -556,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -566,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -576,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -586,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -596,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -606,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -636,7 +635,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -656,7 +655,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Metadata", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -666,7 +665,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -686,7 +685,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -696,7 +695,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -706,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -716,7 +715,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -786,7 +785,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -796,7 +795,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -806,7 +805,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -816,7 +815,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encoding.CodePages", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -826,7 +825,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encodings.Web", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -836,7 +835,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false @@ -856,10 +855,11 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.15" + "Version": "9.0.16" } }, "DevelopmentDependency": false } - ] + ], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" } From 3416dd0145a9530d93c0a9be8c066ca4212a8c16 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 21 May 2026 14:20:28 -0400 Subject: [PATCH 274/275] Update 7.5 changelog for v7.5.7 (#27484) --- CHANGELOG/7.5.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index 326652821cc..01fa5c87459 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -1,5 +1,46 @@ # 7.5 Changelog +## [7.5.7] + +### Engine Updates and Fixes + +- Fix checks for local user config file paths (#27479) + +### General Cmdlet Updates and Fixes + +- Update PowerShell telemetry to respect the diagnostics and feedback setting on Windows (#27472) + +### Build and Packaging Improvements + +<details> + +<summary> + +<p>Update to .NET SDK 9.0.314</p> + +</summary> + +<ul> +<li>Update branch for release (#27480)</li> +<li>Fix *nix permissions and use <code>certificate_logical_to_actual</code> (#27468)</li> +<li>Add the <code>windowsTargetName</code> for .NET 9 (#27474)</li> +<li>Add macOS binary code signing and package notarization (#27467)</li> +<li>Add <code>appLicensing</code> capability to Appx manifest (#27466)</li> +<li>Update <code>Microsoft.PowerShell.Native</code> to the latest GA version (#27465)</li> +<li>Update the MSIXBundle-VPack pipeline to create VPack for both LTS and Stable channel packages (#27464)</li> +<li>Remove package verification from the notice pipeline (#27463)</li> +<li>Correct Variable Template Reference in NonOfficial Pipeline Templates (#27462)</li> +<li>Externalize <code>findMissingNotices</code> target framework selection with ordered Windows fallback (#27461)</li> +<li>Exclude .exe packages from publishing to GitHub (#27460)</li> +<li>Download PMC Packages through <code>TemplateContext</code> (#27335)</li> +<li>Flip Stable PublishToChannel false for v7.5.X (#27333)</li> +<li>PMC release: Use slash instead of back-slash for Linux container (#27318)</li> +</ul> + +</details> + +[7.5.7]: https://github.com/PowerShell/PowerShell/compare/v7.5.6...v7.5.7 + ## [7.5.6] ### General Cmdlet Updates and Fixes From be14d746bc3a453972aebf332b53bcb414322911 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke <SeeminglyScience@users.noreply.github.com> Date: Fri, 22 May 2026 00:45:53 -0400 Subject: [PATCH 275/275] [release/v7.5.7] Remove unused step that clones `Internal-PowerShellTeam-Tools` repo in PMC publish pipeline (#27498) --- .pipelines/templates/release-prep-for-ev2.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml index 3ad716a3af4..ace2b8f7df4 100644 --- a/.pipelines/templates/release-prep-for-ev2.yml +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -59,20 +59,6 @@ stages: env: ob_restore_phase: true - - pwsh: | - $branch = 'mirror-target' - $gitArgs = "clone", - "--verbose", - "--branch", - "$branch", - "https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/Internal-PowerShellTeam-Tools", - '$(Pipeline.Workspace)/tools' - $gitArgs | Write-Verbose -Verbose - git $gitArgs - displayName: Clone Internal-PowerShellTeam-Tools from MSCodeHub - env: - ob_restore_phase: true - - pwsh: | Get-ChildItem Env: | Out-String -Stream | write-Verbose -Verbose displayName: 'Capture Environment Variables'