-
Notifications
You must be signed in to change notification settings - Fork 183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add command option for output the codeowners directly. #2245
Conversation
8bb9278
to
eeab17f
Compare
The following pipelines have been queued for testing: |
The following pipelines have been queued for testing: |
tools/code-owners-parser/Azure.Sdk.Tools.RetrieveCodeOwners/Program.cs
Outdated
Show resolved
Hide resolved
I think that adding all this data parsing and vso variable setting logic outside of the direct tool introduces some unnecessary complexity, and will also make it hard for us to detect and make breaking changes to the underlying tool in the future. I would suggest either:
With the dotnet tool approach we're moving towards, I think a local or remote script user should be able to use the tools directly and not have to rely too much on wrapper scripts, otherwise we lose some of the benefits of centralized CLI tooling. |
@benbp we should chat more about options and trade-offs here. @sima-zhu is implementing it this was based on guidance from me and exploring the options in different worlds. The biggest trouble comes when we want to share this code between our devops steps and other tools that need to parse codeowners. If we have the tool set the devops variable then we still have to parse that variable contents and we also have to run it as an independent devops step, which blocks scenarios such as calling it in a loop in another powershell script context. So while I agree with you parsing the output isn't great it essentially is the same as setting the devops variable because that is how those get handled as well (although by DevOps which gives us less flexibility). |
@weshaggard As you say it's not realistic to do away entirely with wrapper scripts from a pipelines perspective. I guess my issue is more around introducing too much business logic and tight coupling between scripts and the tool output, especially with parsing structured data out of log lines. I think the reverse (printing log lines and extracting info from structured data) is a better pattern to follow for us. In this scenario we would have minimal script code:
Alternatively, instead of parsing |
@sima-zhu, @benbp and I chatted more offline and came to the conclusion that it would be best if we simply have the tool write only the json content to the console in any cases where there is no errors. If there is an error then dump whatever you need to and exit non-zero. That means we can simplify our consumption a little but we will want to go ahead and remove our console logging from the codeowners library. We should also make sure we handle any errors in our conversion from json in case some other output other then the json ends up in the output. |
Or just change it to stderr and print it out regardless of exit code (i.e. get rid of the |
Lets start by removing it and if we find it is useful in some scenario we can figure out how to plumb through a logger. |
The following pipelines have been queued for testing: |
The following pipelines have been queued for testing: |
The following pipelines have been queued for testing: |
The following pipelines have been queued for testing: |
if (!$codeOwnersJson) { | ||
Write-Host "No code owners returned from the path: $CodeOwnerPathExpression" | ||
return "" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: it's not a huge deal here, but as a larger principal, this log statement uses knowledge of how the underlying GetCodeOwnersEntryFromCommand
function is implemented (using $CodeOwnerPathExpression), a function which isn't even called by this function. It would be better to log this message from within the GetCodeOwnersEntryFromCommand
function since it's specific to its implementation.
I would prefer to delete these lines and throw
from the GetCodeOwnersEntryFromCommand
function instead, which makes the code simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We fairly get into this condition.
The tool command returns error or json with real context.
if (codeOwnerEntry == null)
{
Console.Error.WriteLine(String.Format("We cannot find any closest code owners from the target path {0}", targetDirectory));
return 1;
}
else
{
var codeOwnerJson = JsonSerializer.Serialize<CodeOwnerEntry>(codeOwnerEntry);
Console.WriteLine(codeOwnerJson);
return 0;
}
The error handling here is for this line
$codeOwnersJson = $codeOwnersString | ConvertFrom-Json
ConvertFrom-Json could go wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thinking is we could set $ErrorActionPreference
to Stop
for the script context to handle these cases since ConvertFrom-Json
will throw. If the caller has this set in their shell, they'll skip your log statement anyway.
} | ||
else | ||
{ | ||
var codeOwnerJson = JsonSerializer.Serialize<CodeOwnerEntry>(codeOwnerEntry); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to do something like below to get pretty printing of the json, or is it already handled?
var codeOwnerJson = JsonSerializer.Serialize<CodeOwnerEntry>(codeOwnerEntry); | |
var codeOwnerJson = JsonSerializer.Serialize<CodeOwnerEntry>(codeOwnerEntry, new JsonSerializerOptions { WriteIndented = true }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice to have.
The following pipelines have been queued for testing: |
The following pipelines have been queued for testing: |
$VsoVariable = "" # target devops output variable | ||
[string]$CodeOwnerPathExpression, # Code path to code owners. e.g sdk/core/azure-amqp | ||
[string]$ToolVersion = "", # Placeholder. Will update in next PR | ||
[string]$ToolPath = "$env:AGENT_TOOLSDIRECTORY", # The place to check the tool existence. Put $(Agent.ToolsDirectory) as default |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to actually consider a temp directory for this. That is what @danieljurek is doing for cspell, that would allow for easier running locally as well. We can always change it in DevOps if we want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been using this for cross-platform temp directory lookup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been using something similar:
[Parameter()]
[string] $WorkingDirectory = (Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())),
This generates a temporary folder name which can then be created later if it doesn't already exist.
$TargetDirectory, # should be in relative form from root of repo. EG: sdk/servicebus | ||
$RootDirectory, # ideally $(Build.SourcesDirectory) | ||
$VsoVariable = "" # target devops output variable | ||
[string]$CodeOwnerPathExpression, # Code path to code owners. e.g sdk/core/azure-amqp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't the path to code owners this should be called "relativePathInRepoToFindOwners" or something like that.
The following pipelines have been queued for testing: |
} | ||
return & "$ToolPath/retrieve-code-owners" --target-directory "$CodeOwnerPathExpression" --code-owner-file-path "$CodeOwnerFileLocation" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this even work? I ask because I don't see any processing that would handle the --target-directory
, I would expect you would need to pass the parameters via position instead of by name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like the Dragonfruit
dependency is what's providing the magic conversion from the function argument names to the CLI flag syntax?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is pretty cool but it might be good to put a code comment above the main
method describing that the arguments will be magically handled by the Dragonfruit dependency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh this is interesting and I agree we probably should add a comment there isn't anything to really stop us from removing this dependency and breaking this command line arg parsing.
|
||
$codeOwners = $codeOwnersJson.Owners -join "," |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this join inside of the VSOVariable block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The line is still useful even VSO not set.
|
||
InstallRetrieveCodeOwnersTool | ||
|
||
$codeOwnerToolOutput = GetCodeOwnersEntryFromCommand |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not do this in GetCodeOwners function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given you aren't really calling these functions more than once you can probably eliminate the functions and just have the code inline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with moving this code inside GetCodeOwners
. Re: eliminating functions, I disagree. I think a lot of our scripts have grown larger over time, and the lack of functions at the start makes our scripts tend to evolve into spaghetti code (New-TestResources.ps1
as the best example of this). I think if we try to keep all logic in functions except for a single entrypoint function call at the end of the script, it's easier to modify the code AND easier to test because you can dot source individual functions and execute them locally (provided you filter on invocation name).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes testing is definitely a great reason to have these functions.
|
||
$codeOwnerToolOutput = GetCodeOwnersEntryFromCommand | ||
# Failed at the command of fetching code owners. | ||
if ($LASTEXITCODE -ne 0) { | ||
return "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably return an empty list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we return string with ","
I feel like string is much easy to deliver between yaml and scripts. It is also easy to parse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think to keep both the object format and the yaml<-->script format, this could be a JSON stringified empty list, i.e. "[]"
or @() | ConvertTo-Json
.
return "" | ||
} | ||
GetCodeOwners $codeOwnerToolOutput |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably should be a return statement so it is clear.
tools/code-owners-parser/Azure.Sdk.Tools.RetrieveCodeOwners/Program.cs
Outdated
Show resolved
Hide resolved
dadad0f
to
f42263d
Compare
This pull request is protected by Check Enforcer. What is Check Enforcer?Check Enforcer helps ensure all pull requests are covered by at least one check-run (typically an Azure Pipeline). When all check-runs associated with this pull request pass then Check Enforcer itself will pass. Why am I getting this message?You are getting this message because Check Enforcer did not detect any check-runs being associated with this pull request within five minutes. This may indicate that your pull request is not covered by any pipelines and so Check Enforcer is correctly blocking the pull request being merged. What should I do now?If the check-enforcer check-run is not passing and all other check-runs associated with this PR are passing (excluding license-cla) then you could try telling Check Enforcer to evaluate your pull request again. You can do this by adding a comment to this pull request as follows: |
fb09d44
to
196995a
Compare
62a8bab
to
9d8bcfe
Compare
The test is in pipeline with the custom tests run.
Here is the test without custom test run:
https://dev.azure.com/azure-sdk/internal/_build/results?buildId=1203228&view=results