Skip to content

Commit

Permalink
Merge pull request #1654 from microsoftgraph/dev
Browse files Browse the repository at this point in the history
Merge dev into master
  • Loading branch information
millicentachieng committed Jul 4, 2023
2 parents b3b40dd + 35da1ba commit 9d722be
Show file tree
Hide file tree
Showing 5 changed files with 288 additions and 18 deletions.
186 changes: 186 additions & 0 deletions CodeSnippetsReflection.OpenAPI.Test/PowerShellGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,5 +358,191 @@ public async Task GeneratesSnippetForRequestWithWrongQuotesForStringLiteralsInBo
Assert.Contains(expectedParams, result);
Assert.Contains("-BodyParameter $params", result);
}

[Fact]
public async Task GeneratesSnippetForDeltaFunctionsWithoutParams()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/contacts/delta()?$select=displayName%2CjobTitle%2Cmail");
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Get-MgContactDelta", result);
}

[Fact]
public async Task GeneratesSnippetForDeltaFunctionsWithParams()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/drives/XXXX/items/XXXX/delta(token='token')");
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Get-MgDriveItemDelta", result);
Assert.Contains("-Token", result);
}

[Fact]
public async Task GeneratesSnippetForHttpSnippetsWithGraphPrefixOnLastPathSegment()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/places/graph.room");
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Get-MgPlaceAsRoom", result);
}

[Fact]
public async Task GeneratesSnippetForHttpSnippetsWithoutGraphPrefixOnLastPathSegment()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/places/microsoft.graph.room");
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Get-MgPlaceAsRoom", result);
}

[Fact]
public async Task GeneratesSnippetForPathsWithIdentityProviderAsRootNode()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/identityProviders");
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Get-MgIdentityProvider", result);
}

[Fact]
public async Task GeneratesSnippetForRequestWithTextContentType()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Put, $"{ServiceRootUrl}/me/drive/items/XXXX/content")
{
Content = new StringContent(
"Plain text",
Encoding.UTF8,
"text/plain")
};
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Set-MgDriveItemContent", result);
}

[Fact]
public async Task GeneratesSnippetForRequestWithApplicationZipContentType()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Put, $"{ServiceRootUrl}/me/drive/items/XXXX/content")
{
Content = new StringContent(
"Zip file content",
Encoding.UTF8,
"application/zip")
};
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Set-MgDriveItemContent", result);
}

[Fact]
public async Task GeneratesSnippetForRequestWithImageContentType()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Put, $"{ServiceRootUrl}/me/photo/$value")
{
Content = new StringContent(
"Binary data for the image",
Encoding.UTF8,
"image/jpeg")
};
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Set-MgUserPhotoContent", result);
Assert.Contains("-BodyParameter", result);
}

[Fact]
public async Task GeneratesBetaSnippetForFunctionsWithoutParams()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootBetaUrl}/contacts/delta()?$select=displayName%2CjobTitle%2Cmail");
var snippetModel = new SnippetModel(requestPayload, ServiceRootBetaUrl, await GetBetaSnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Get-MgBetaContactDelta", result);
}

[Fact]
public async Task GeneratesBetaSnippetForFunctionsWithSingleParam()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootBetaUrl}/drives/XXXX/items/XXXX/delta(token='token')");
var snippetModel = new SnippetModel(requestPayload, ServiceRootBetaUrl, await GetBetaSnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Get-MgBetaDriveItemDelta", result);
Assert.Contains("-Token", result);
}

[Fact]
public async Task GeneratesBetaSnippetForFunctionsWithMultipleParam()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootBetaUrl}/communications/callRecords/getPstnBlockedUsersLog(fromDateTime=XXXXXX,toDateTime=XXXXX)");
var snippetModel = new SnippetModel(requestPayload, ServiceRootBetaUrl, await GetBetaSnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Get-MgBetaCommunicationCallRecordPstnBlockedUserLog", result);
Assert.Contains("-ToDateTime", result);
}

[Fact]
public async Task GeneratesBetaSnippetForHttpSnippetsWithGraphPrefixOnLastPathSegment()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootBetaUrl}/places/graph.room");
var snippetModel = new SnippetModel(requestPayload, ServiceRootBetaUrl, await GetBetaSnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Get-MgBetaPlaceAsRoom", result);
}

[Fact]
public async Task GeneratesBetaSnippetForPathsWithIdentityProviderAsRootNode()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootBetaUrl}/identityProviders");
var snippetModel = new SnippetModel(requestPayload, ServiceRootBetaUrl, await GetBetaSnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Get-MgBetaIdentityProvider", result);
}

[Fact]
public async Task GeneratesBetaSnippetForRequestWithTextContentType()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Put, $"{ServiceRootBetaUrl}/me/drive/items/XXXX/content")
{
Content = new StringContent(
"Plain text",
Encoding.UTF8,
"text/plain")
};
var snippetModel = new SnippetModel(requestPayload, ServiceRootBetaUrl, await GetBetaSnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Set-MgBetaDriveItemContent", result);
}

[Fact]
public async Task GeneratesBetaSnippetForRequestWithApplicationZipContentType()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Put, $"{ServiceRootBetaUrl}/me/drive/items/XXXX/content")
{
Content = new StringContent(
"Zip file content",
Encoding.UTF8,
"application/zip")
};
var snippetModel = new SnippetModel(requestPayload, ServiceRootBetaUrl, await GetBetaSnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Set-MgBetaDriveItemContent", result);
}

[Fact]
public async Task GeneratesBetaSnippetForRequestWithImageContentType()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Put, $"{ServiceRootBetaUrl}/me/photo/$value")
{
Content = new StringContent(
"Binary data for the image",
Encoding.UTF8,
"image/jpeg")
};
var snippetModel = new SnippetModel(requestPayload, ServiceRootBetaUrl, await GetBetaSnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("Set-MgBetaUserPhotoContent", result);
Assert.Contains("-BodyParameter", result);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,23 @@ public class PowerShellGenerator : ILanguageGenerator<SnippetModel, OpenApiUrlTr
private static readonly Regex meSegmentRegex = new("^/me($|(?=/))", RegexOptions.Compiled, TimeSpan.FromSeconds(5));
private static readonly Regex encodedQueryParamsPayLoad = new(@"\w*\+", RegexOptions.Compiled, TimeSpan.FromSeconds(5));
private static readonly Regex wrongQoutesInStringLiterals = new(@"""\{", RegexOptions.Compiled, TimeSpan.FromSeconds(5));
private static readonly Regex functionWithParams = new(@"^[0-9a-zA-Z\- \/_?:.,\s]+\([\w*='{\w*}\',]*\)|^[0-9a-zA-Z\- \/_?:.,\s]+\([\w*='\w*\',]*\)|^[0-9a-zA-Z\- \/_?:.,\s]+\([\w*={w*},]*\)|^[0-9a-zA-Z\- \/_?:.,\s]+\([\w*=<w*>,]*\)", RegexOptions.Compiled, TimeSpan.FromSeconds(5));
private static readonly Regex functionWithoutParams = new(@"\w*\(\)", RegexOptions.Compiled, TimeSpan.FromSeconds(5));
public string GenerateCodeSnippet(SnippetModel snippetModel)
{
var indentManager = new IndentManager();
var snippetBuilder = new StringBuilder();
var cleanPath = snippetModel.EndPathNode.Path.Replace("\\", "/");
var isMeSegment = meSegmentRegex.IsMatch(cleanPath);
var (path, additionalKeySegmentParmeter) = SubstituteMeSegment(isMeSegment, cleanPath);
var hasGraphPrefix = cleanPath.Contains("graph", StringComparison.OrdinalIgnoreCase);
var isIdentityProvider = snippetModel.RootPathNode.Path.StartsWith("\\identityProviders", StringComparison.OrdinalIgnoreCase);
var lastPathSegment = snippetModel.EndPathNode.Segment;
var hasMicrosoftPrefix = lastPathSegment.StartsWith("microsoft", StringComparison.OrdinalIgnoreCase);
cleanPath = SubstituteIdentityProviderSegment(cleanPath, isIdentityProvider);
cleanPath = ReplaceFunctionSegments(lastPathSegment, cleanPath);
cleanPath = SubstituteGraphSegment(cleanPath, hasGraphPrefix);
cleanPath = SubstituteMicrosoftSegment(cleanPath, hasMicrosoftPrefix, lastPathSegment);
var (path, additionalKeySegmentParmeter) = SubstituteMeSegment(isMeSegment, cleanPath, lastPathSegment);
IList<PowerShellCommandInfo> matchedCommands = GetCommandForRequest(path, snippetModel.Method.ToString(), snippetModel.ApiVersion);
var targetCommand = matchedCommands.FirstOrDefault();
if (targetCommand != null)
Expand Down Expand Up @@ -72,9 +82,13 @@ public string GenerateCodeSnippet(SnippetModel snippetModel)
if (RequiresMIMEContentOutPut(snippetModel, path))
{
//Allows genration of an output file for MIME content of the message
snippetBuilder.Append($" -OutFile $outFileId");
snippetBuilder.Append(" -OutFile $outFileId");
}
}
else
{
throw new NotImplementedException($"{path} and {snippetModel.Method} operation is not supported in the sdk");
}
return snippetBuilder.ToString();
}
/// <summary>
Expand All @@ -92,8 +106,6 @@ private static bool RequiresMIMEContentOutPut(SnippetModel snippetModel, string
if (lastValue.Equals("$value") && snippetModel.Method == HttpMethod.Get) return true;
return false;
}


private static string GetCommandParameters(SnippetModel snippetModel, string payloadVarName)
{
var payloadSB = new StringBuilder();
Expand All @@ -109,29 +121,69 @@ private static string GetCommandParameters(SnippetModel snippetModel, string pay
if (!string.IsNullOrEmpty(parameterList))
payloadSB.Append($" {parameterList}");

var functionParameterList = GetFunctionParameterList(snippetModel);
if (!string.IsNullOrEmpty(functionParameterList))
payloadSB.Append($" {functionParameterList}");

var requestHeadersPayload = GetSupportedRequestHeaders(snippetModel);
if (!string.IsNullOrEmpty(requestHeadersPayload))
payloadSB.Append(requestHeadersPayload);

return payloadSB.ToString();
}

public static string ReturnCleanParamsPayload(string queryParamsPayload)
{
if(encodedQueryParamsPayLoad.IsMatch(queryParamsPayload))
return queryParamsPayload.Replace("+", " ");
return queryParamsPayload;
}

private static (string, string) SubstituteMeSegment(bool isMeSegment, string path)
private static (string, string) SubstituteMeSegment(bool isMeSegment, string path, string lastPathSegment)
{
string additionalKeySegmentParmeter = default;
if (isMeSegment)
{
path = meSegmentRegex.Replace(path, "/users/{user-id}");
additionalKeySegmentParmeter = $" -UserId $userId";
}
if (lastPathSegment.Contains("()"))
{
path = path.RemoveFunctionBraces();
}
return (path, additionalKeySegmentParmeter);
}

private static string ReplaceFunctionSegments(string lastPathSegment, string path)
{
var segmentItems = lastPathSegment.Split("(");
if (functionWithoutParams.IsMatch(lastPathSegment) || functionWithParams.IsMatch(lastPathSegment))
path = path.Replace(lastPathSegment, segmentItems[0]);
return path;
}

private static string SubstituteGraphSegment(string path, bool hasGraphPrefix)
{
if (hasGraphPrefix)
path = path.Replace("graph.", string.Empty);
return path;
}
private static string SubstituteMicrosoftSegment(string path, bool hasMicrosoftSegment, string lastSegmentPath)
{
if (hasMicrosoftSegment)
{
var splittedPath = path.Split('/');
path = path.Replace(splittedPath[splittedPath.Length - 1], lastSegmentPath);
}

return path;
}
private static string SubstituteIdentityProviderSegment(string path, bool isIdentityProvider)
{
if (isIdentityProvider)
path = path.Replace("identityProviders", "identity/identityProviders");
return path;
}

private static string GetSupportedRequestHeaders(SnippetModel snippetModel)
{
var payloadSB = new StringBuilder();
Expand All @@ -147,7 +199,6 @@ private static string GetSupportedRequestHeaders(SnippetModel snippetModel)
}
return payloadSB.ToString();
}

private static string GetKeySegmentParameters(IEnumerable<OpenApiUrlTreeNode> pathNodes)
{
if (!pathNodes.Any()) return string.Empty;
Expand All @@ -160,7 +211,6 @@ private static string GetKeySegmentParameters(IEnumerable<OpenApiUrlTreeNode> pa
return $"{x} {y}";
});
}

private static string GetRequestQueryParameters(SnippetModel model)
{
var payloadSB = new StringBuilder();
Expand All @@ -182,7 +232,6 @@ private static string GetRequestQueryParameters(SnippetModel model)
}
return default;
}

private static string GetQueryParameterValue(string normalizedParameterName, string originalValue, Dictionary<string, string> replacements)
{
if (normalizedParameterName.Equals("CountVariable"))
Expand Down Expand Up @@ -261,6 +310,15 @@ private static (string, string) GetRequestPayloadAndVariableName(SnippetModel sn
payloadSB.AppendLine("}");
}
break;
case "image/jpeg":
payloadSB.AppendLine($"{indentManager.GetIndent()}${requestBodyVarName} = Binary data for the image");
break;
case "application/zip":
payloadSB.AppendLine($"{indentManager.GetIndent()}${requestBodyVarName} = {snippetModel?.RequestBody}");
break;
case "text/plain":
payloadSB.AppendLine($"{indentManager.GetIndent()}${requestBodyVarName} = {snippetModel?.RequestBody}");
break;
default:
throw new InvalidOperationException($"Unsupported content type: {snippetModel.ContentType}");
}
Expand Down Expand Up @@ -352,5 +410,27 @@ private static string GetActionParametersList(params string[] parameters)
return string.Join(" ", nonEmptyParameters.Aggregate((a, b) => $"{a}, {b}"));
else return string.Empty;
}

private static string GetFunctionParameterList(SnippetModel snippetModel)
{
var snippetPaths = snippetModel.Path;
var paramBuilder = new StringBuilder();
if (functionWithParams.IsMatch(snippetPaths))
{
var paths = snippetPaths.Split("/");
var function = paths.Last();
var functionItems = function.Split("(");
var functionParameters = functionItems[1].Split(",");
foreach(var param in functionParameters)
{
var paramKeys = param.Split("=")[0];
var paramKey = $"-{paramKeys.ToFirstCharacterUpperCase()} ${paramKeys}Id ";
paramBuilder.Append(paramKey);
}

}
return paramBuilder.ToString();
}

}
}

0 comments on commit 9d722be

Please sign in to comment.