diff --git a/CHANGELOG.md b/CHANGELOG.md index ffe4cf70d..f0f986673 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -106,6 +106,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Fix `Connect-PnPOnline` cmdlet not working with On Prem related cmdlets. [#4622](https://github.com/pnp/powershell/pull/4622) - Fix `Get\Invoke-PnPSiteTemplate` cmdlet not working in vanity domains. [#4630](https://github.com/pnp/powershell/pull/4630) - Fixed passing a `Get-PnPRecycleBinItem` result or a GUID to `Restore-PnPRecycleBinItem` not working correctly. [#4667](https://github.com/pnp/powershell/pull/4667) +- Fixed `Get-PnPChangeLog` not returning the changelog [#4707](https://github.com/pnp/powershell/pull/4707) ### Removed diff --git a/documentation/Get-PnPChangeLog.md b/documentation/Get-PnPChangeLog.md index cd68241df..40d52f4f3 100644 --- a/documentation/Get-PnPChangeLog.md +++ b/documentation/Get-PnPChangeLog.md @@ -14,12 +14,18 @@ Returns the changelog for PnP PowerShell ## SYNTAX +### Current nightly ```powershell -Get-PnPChangeLog [-Nightly] +Get-PnPChangeLog -Nightly [-Verbose] +``` + +### Specific version +```powershell +Get-PnPChangeLog [-Version ] [-Verbose] ``` ## DESCRIPTION -This cmdlets returns the changelog in markdown format. It is retrieved dynamically from GitHub. +This cmdlets returns what has changed in PnP PowerShell in a specific version in markdown format. It is retrieved dynamically from GitHub. ## EXAMPLES @@ -28,7 +34,7 @@ This cmdlets returns the changelog in markdown format. It is retrieved dynamical Get-PnPChangeLog ``` -Returns the changelog for the currently released version. +Returns the changelog for the latest released stable version. ### EXAMPLE 2 ```powershell @@ -37,11 +43,32 @@ Get-PnPChangeLog -Nightly Returns the changelog for the current nightly build. +### EXAMPLE 3 +```powershell +Get-PnPChangeLog -Version 2.12.0 +``` + +Returns the changelog for the 2.12.0 release. + ## PARAMETERS ### -Nightly Return the changelog for the nightly build +```yaml +Type: SwitchParameter +Parameter Sets: Current nightly + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Verbose +When provided, additional debug statements will be shown while executing the cmdlet. + ```yaml Type: SwitchParameter Parameter Sets: (All) @@ -53,8 +80,20 @@ Accept pipeline input: False Accept wildcard characters: False ``` -## RELATED LINKS +### -Version +Return the changelog for a specific version. Be sure to use the correct version number in the format <#>.<#>.<#>, i.e. 2.12.0, otherwise the cmdlet will fail. If omitted, the latest stable version will be returned. -[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) +```yaml +Type: SwitchParameter +Parameter Sets: Specific version +Required: False +Position: Named +Default value: Latest stable version +Accept pipeline input: False +Accept wildcard characters: False +``` + +## RELATED LINKS +[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) \ No newline at end of file diff --git a/src/Commands/Base/GetChangeLog.cs b/src/Commands/Base/GetChangeLog.cs index 8640a22bb..03c78044c 100644 --- a/src/Commands/Base/GetChangeLog.cs +++ b/src/Commands/Base/GetChangeLog.cs @@ -1,77 +1,117 @@ using System.Management.Automation; -using System.Reflection; -using System.Text.Json; +using System.Net.Http; +using System.Text.RegularExpressions; namespace PnP.PowerShell.Commands { - [Cmdlet(VerbsCommon.Get, "PnPChangeLog")] + [Cmdlet(VerbsCommon.Get, "PnPChangeLog", DefaultParameterSetName = ParameterSet_SpecificVersion)] [OutputType(typeof(string))] - public class GetChangeLog : PSCmdlet + public partial class GetChangeLog : PSCmdlet { - [Parameter(Mandatory = false)] + private const string ParameterSet_Nightly = "Current nightly"; + private const string ParameterSet_SpecificVersion = "Specific version"; + + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_Nightly)] public SwitchParameter Nightly; - [Parameter(Mandatory = false)] - public System.Version Release; + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_SpecificVersion)] + [Alias("Release")] + public System.Version Version; protected override void ProcessRecord() { - var client = PnP.Framework.Http.PnPHttpClient.Instance.GetHttpClient(); + var client = Framework.Http.PnPHttpClient.Instance.GetHttpClient(); + string releaseNotes; - if (MyInvocation.BoundParameters.ContainsKey(nameof(Release))) + if (MyInvocation.BoundParameters.ContainsKey(nameof(Version))) + { + releaseNotes = RetrieveSpecificRelease(client, Version.ToString()); + } + else if (Nightly) { - var url = $"https://api.github.com/repos/pnp/powershell/releases/tags/v{Release.Major}.{Release.Minor}.{Release.Build}"; - var response = client.GetAsync(url).GetAwaiter().GetResult(); - if (response.IsSuccessStatusCode) - { - var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); - var jsonElement = JsonSerializer.Deserialize(content); - if (jsonElement.TryGetProperty("body", out JsonElement bodyElement)) - { - WriteObject(bodyElement.GetString()); - } - } + releaseNotes = RetrieveSpecificRelease(client, "Current nightly"); } else { - var url = "https://raw.githubusercontent.com/pnp/powershell/master/CHANGELOG.md"; - if (Nightly) - { - url = "https://raw.githubusercontent.com/pnp/powershell/dev/CHANGELOG.md"; - } - var assembly = Assembly.GetExecutingAssembly(); - var currentVersion = new SemanticVersion(assembly.GetCustomAttribute().InformationalVersion); - var response = client.GetAsync(url).GetAwaiter().GetResult(); - if (response.IsSuccessStatusCode) - { - var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); - - if (Nightly) - { - var match = System.Text.RegularExpressions.Regex.Match(content, @"## \[Current Nightly\][\r\n]{1,}(.*?)[\r\n]{1,}## \[[\d\.]{5,}][\r\n]{1,}", System.Text.RegularExpressions.RegexOptions.Singleline); - - if (match.Success) - { - WriteObject(match.Groups[1].Value); - } - } - else - { - var currentVersionString = $"{currentVersion.Major}.{currentVersion.Minor}.0"; - var previousVersionString = $"{currentVersion.Major}.{currentVersion.Minor - 1}.0"; - var match = System.Text.RegularExpressions.Regex.Match(content, $"(## \\[{currentVersionString}\\]\\n(.*)\\n)(## \\[{previousVersionString}]\\n)", System.Text.RegularExpressions.RegexOptions.Singleline); - - if (match.Success) - { - WriteObject(match.Groups[1].Value); - } - } - } - else - { - throw new PSInvalidOperationException("Cannot retrieve changelog"); - } + releaseNotes = RetrieveLatestStableRelease(client); + } + + WriteObject(releaseNotes); + } + + /// + /// Retrieves the changelog regarding the latest stable release from GitHub + /// + /// HttpClient to use to request the data from GitHub + /// Thrown if it is unable to parse the changelog data properly + /// The changelog regarding the latest stable release + private string RetrieveLatestStableRelease(HttpClient httpClient) + { + var url = "https://raw.githubusercontent.com/pnp/powershell/dev/CHANGELOG.md"; + + WriteVerbose($"Retrieving changelog from {url}"); + + var response = httpClient.GetAsync(url).GetAwaiter().GetResult(); + if (!response.IsSuccessStatusCode) + { + throw new PSInvalidOperationException("Failed to retrieve changelog from GitHub"); + } + + WriteVerbose("Successfully retrieved changelog from GitHub"); + + var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + + var releasedVersions = Regex.Matches(content, @"## \[(?\d+?\.\d+?\.\d+?)]"); + if (releasedVersions.Count == 0) + { + throw new PSInvalidOperationException("Failed to identify versions in changelog on GitHub"); + } + + WriteVerbose($"Found {releasedVersions.Count} released versions in changelog"); + WriteVerbose($"Looking for release information on previous stable version {releasedVersions[0].Groups["version"].Value}"); + + var match = Regex.Match(content, @$"(?## \[{releasedVersions[0].Groups["version"].Value.Replace(".", @"\.")}]\n.*?)\n## \[\d+?\.\d+?\.\d+?\]", RegexOptions.Singleline); + + if (!match.Success) + { + throw new PSInvalidOperationException($"Failed to identify changelog for version {releasedVersions[0].Groups["version"].Value} on GitHub"); + } + + return match.Groups["changelog"].Value; + } + + /// + /// Retrieves the changelog regarding a specific release from GitHub + /// + /// HttpClient to use to request the data from GitHub + /// Thrown if it is unable to parse the changelog data properly + /// The changelog regarding the specific release + private string RetrieveSpecificRelease(HttpClient httpClient, string version) + { + var url = "https://raw.githubusercontent.com/pnp/powershell/dev/CHANGELOG.md"; + + WriteVerbose($"Retrieving changelog from {url}"); + + var response = httpClient.GetAsync(url).GetAwaiter().GetResult(); + if (!response.IsSuccessStatusCode) + { + throw new PSInvalidOperationException("Failed to retrieve changelog from GitHub"); } + + WriteVerbose("Successfully retrieved changelog from GitHub"); + + var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + + WriteVerbose($"Looking for release information on the {version} release"); + + var match = Regex.Match(content, @$"(?## \[{version}]\n.*?)\n## \[\d+?\.\d+?\.\d+?\]", RegexOptions.Singleline); + + if (!match.Success) + { + throw new PSInvalidOperationException($"Failed to identify changelog for the {version} release on GitHub"); + } + + return match.Groups["changelog"].Value; } } } \ No newline at end of file