Skip to content

Conversation

@gregsdennis
Copy link
Contributor

@gregsdennis gregsdennis commented Sep 3, 2022

PR Summary

Updates the Test-Json cmdlet to use JsonSchema.Net instead of NJsonSchema in order to:

  • use System.Text.Json instead of Newtonsoft
  • support the latest JSON Schema drafts (up to 2020-12)

Resolves

PR Context

Resolves #18009

NJsonSchema only supports up to draft 7, which at this point is several years old and two versions behind. Additionally, it relies on Newtonsoft.Json.

This change is a merely drop-in replacement of the implementation that provides validation.

The cmdlet API doesn't change, however the cmdlet will no longer support draft 4 schemas. Draft 4 is a decade old at this point and the JSON Schema team (myself included) is encouraging tooling to only support draft 6/7 (6 is a subset of 7) and later. (In the future, support for these should be dropped as newer versions are released.) I'm not sure if this is considered a breaking change for this repo.

To assist users in their migration away from draft 4, the alterschema draft migration tool has been created.

I expect the existing test coverage is adequate to cover this change.

PR Checklist

@ghost
Copy link

ghost commented Sep 3, 2022

CLA assistant check
All CLA requirements met.

@gregsdennis
Copy link
Contributor Author

I'm not sure if this is a problem, but I notice that all of the tests are written with single quotes. Newtonsoft is happy to parse these, but System.Text.Json will not. I suspect this is the source the test failures, but I'm not sure. I could use some help getting the tests to run locally.

@iSazonov
Copy link
Collaborator

iSazonov commented Sep 5, 2022

@gregsdennis Yes, it is main breaking change in System.Text.Json.

@SteveL-MSFT Do you agree to begin migration to System.Text.Json in the 7.4 milestone?

@gregsdennis
Copy link
Contributor Author

gregsdennis commented Sep 5, 2022

There seem to be a lot more changes to files.wxs that I expected. Maybe this is normal?

@gregsdennis
Copy link
Contributor Author

image

"invalid spacing" - but what should it be? It tells me its wrong but not how to fix it.

@iSazonov
Copy link
Collaborator

iSazonov commented Sep 6, 2022

@gregsdennis Please finish replacing ' with " in tests since you have started the process.

Invalid spacing

Try reformat:

var validationResults = _jschema.Validate(parsedJson, new ValidationOptions
{
    OutputFormat = OutputFormat.Basic
});

> files.wxs

You need to build win package locally and the script will publish new files.wxs in temp folder.

@iSazonov
Copy link
Collaborator

iSazonov commented Sep 6, 2022

@gregsdennis Maybe #11397 help you a bit.

@gregsdennis
Copy link
Contributor Author

Please finish replacing ' with " in tests since you have started the process.

I expect you don't mean all the tests. Even just in that file seems overkill. It seems there's a preference to have " wherever possible, so I only changed what was necessary.

Try reformat

The format of Func(new Class { Prop = value }); seems to be working. I can still change to what you have if that's preferred.

@iSazonov
Copy link
Collaborator

iSazonov commented Sep 6, 2022

Please finish replacing ' with " in tests since you have started the process.

I expect you don't mean all the tests. Even just in that file seems overkill. It seems there's a preference to have " wherever possible, so I only changed what was necessary.

I still see test fails because of "

@gregsdennis
Copy link
Contributor Author

The failing tests aren't (all) because of ".

For example, Json is valid against a valid schema from file is failing because the lib doesn't know about valid_schema_definitions.json, which is being referenced.

JSON Schema explicitly states that implementations SHOULD NOT download references that appear to be URLs. The URIs that are used are merely identifiers, not locations. As such, downloading is disabled in my lib by default, requiring pre-loading of all required schemas, but it seems that it may have been enabled in NJsonSchema. I can make this change.

I'll go through the other tests to see what the problems are.

@iSazonov
Copy link
Collaborator

iSazonov commented Sep 7, 2022

As such, downloading is disabled in my lib by default, requiring pre-loading of all required schemas

So we cannot reference base schema file from new schema file?

@gregsdennis
Copy link
Contributor Author

If PowerShell is comfortable with automatically fetching external documents, it can be enabled, yes, but it's not generally recommended by JSON Schema. Given that this is previous functionality, I think enabling it is fine.

I suggest adding this to the docs as a deviation from the spec.

@iSazonov
Copy link
Collaborator

iSazonov commented Sep 7, 2022

If PowerShell is comfortable with automatically fetching external documents, it can be enabled, yes, but it's not generally recommended by JSON Schema. Given that this is previous functionality, I think enabling it is fine.

I suggest adding this to the docs as a deviation from the spec.

Since this has not been reported as a security issue until now we should keep current behavior if possible. Then we will ask PowerShell security group.

@gregsdennis
Copy link
Contributor Author

It looks like there's some syntax issue I don't understand in the Test-Json recognizes non-object types: <name> tests on line 156.

I've extracted the loop into a separate file:

$types = 'string', 'number', 'boolean', 'null', 'array', 'object'
$types | Where-Object {
    $schema = "{ ""type"": ""$_"" }"
    Write-Output $schema
}


$type = 'string'
$schema = "{ ""type"": ""$type"" }"
Write-Output $schema

This outputs

string
number
boolean
null
array
object
{ "type": "string" }

I don't understand why the interpolation isn't working in the loop but it works outside of it.

@iSazonov
Copy link
Collaborator

iSazonov commented Sep 8, 2022

I don't understand why the interpolation isn't working

PowerShell interpolation works only in double quotes.

I added commit to fix the test.

@gregsdennis
Copy link
Contributor Author

gregsdennis commented Sep 8, 2022

What's the policy on changing error codes?

Test-Json throw if a schema from file is invalid is expecting InvalidJsonSchema, but the file isn't valid JSON at all. It seems that NJsonSchema preprocesses $refs so that it tries to deserialize the text as a schema before it ever reaches the validation stage. JsonSchema.Net deserializes referenced data (and caches it) at validation time. This means that the command reaches the validation stage and the resulting error is InvalidJson instead (which I think is actually more correct).

In both cases, it's an error, but the exact error is different.

Edit: After the commit below, all the tests are passing except for this.

@iSazonov
Copy link
Collaborator

iSazonov commented Sep 9, 2022

This means that the command reaches the validation stage and the resulting error is InvalidJson instead (which I think is actually more correct).

I agree with InvalidJson since we check just Json. However, the user must understand the root of the error whether it is the Json itself or a problem with the schema (reading/parsing). In other words InvalidJson must contain InvalidJsonSchema as an inner exception and the test should check this.

@gregsdennis gregsdennis force-pushed the update-test-json-to-use-jsonschema.net branch from 18443fb to eb6d1d0 Compare September 17, 2022 20:49
@gregsdennis
Copy link
Contributor Author

I've rebased and pushed.

@gregsdennis
Copy link
Contributor Author

@iSazonov since the update to .Net 7 RC1, I can't build anymore. I've installed the preview framework (Windows x64 installer).

I'm getting a lot of errors saying that it can't find Microsoft.CodeAnalysis.

An instance of analyzer Microsoft.CodeAnalysis.MakeFieldReadonly.MakeFieldReadonlyDiagnosticAnalyzer
cannot be created from C:\Program Files\dotnet\sdk\7.0.100-rc.1.22431.12\Sdks\Microsoft.NET.Sdk\codestyle\cs\Microsoft.CodeAnalysis.CodeStyle.dll :
Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
or one of its dependencies. The system cannot find the file specified.

It seems there are some rebase conflicts with how I merged the .wxs file.

@iSazonov
Copy link
Collaborator

I'm getting a lot of errors saying that it can't find Microsoft.CodeAnalysis.

Usually we need to remove nuget cache in current user profile to fix such issues. Also you need to run once Start-PSBuild -Clean.

@gregsdennis
Copy link
Contributor Author

@iSazonov I've regen'd the files.wxs file (and removed the pdb's) but I'm not sure it's right. There seem to be other DLLs listed that I didn't do anything with.

@iSazonov
Copy link
Collaborator

@iSazonov I've regen'd the files.wxs file (and removed the pdb's) but I'm not sure it's right. There seem to be other DLLs listed that I didn't do anything with.

Please build msi package locally and use files.wxs from the build.

@gregsdennis
Copy link
Contributor Author

Please build msi package locally and use files.wxs from the build.

Are there instructions for this? All I can find is the Windows build instructions. This only generates an .exe.

@iSazonov
Copy link
Collaborator

iSazonov commented Sep 20, 2022

https://github.com/PowerShell/PowerShell/blob/7dc4587014bfa22919c933607bf564f0ba53db2e/.github/CONTRIBUTING.md#pull-request---automatic-checks

Import-Module .\build.psm1
Start-PSBuild -Clean -CrossGen -PSModuleRestore -Runtime win7-x64 -Configuration Release -ReleaseTag <release tag>
Import-Module .\tools\packaging
Start-PSPackage -Type msi -ReleaseTag <release tag> -WindowsRuntime 'win7-x64' -SkipReleaseChecks

Console output should contain a reference to new files.wxs.

GitHub
PowerShell for every system! Contribute to PowerShell/PowerShell development by creating an account on GitHub.

@gregsdennis
Copy link
Contributor Author

@iSazonov I ran that except that it didn't recognize the -CrossGen switch, so I had to remove that.

PS C:\projects\PowerShell> Start-PSBuild -Clean -CrossGen -PSModuleRestore -Runtime win7-x64 -Configuration Release -ReleaseTag v1.0.0-local
Start-PSBuild: A parameter cannot be found that matches parameter name 'CrossGen'.

It also added all of the .pdb files, so I removed those. It still doesn't match. 😭

@pull-request-quantifier-deprecated

This PR has 209 quantified lines of changes. In general, a change size of upto 200 lines is ideal for the best PR experience!


Quantification details

Label      : Large
Size       : +125 -84
Percentile : 60.9%

Total files changed: 5

Change summary by file extension:
.wxs : +30 -22
.csproj : +1 -1
.cs : +59 -26
.ps1 : +35 -35

Change counts above are quantified counts, based on the PullRequestQuantifier customizations.

Why proper sizing of changes matters

Optimal pull request sizes drive a better predictable PR flow as they strike a
balance between between PR complexity and PR review overhead. PRs within the
optimal size (typical small, or medium sized PRs) mean:

  • Fast and predictable releases to production:
    • Optimal size changes are more likely to be reviewed faster with fewer
      iterations.
    • Similarity in low PR complexity drives similar review times.
  • Review quality is likely higher as complexity is lower:
    • Bugs are more likely to be detected.
    • Code inconsistencies are more likely to be detected.
  • Knowledge sharing is improved within the participants:
    • Small portions can be assimilated better.
  • Better engineering practices are exercised:
    • Solving big problems by dividing them in well contained, smaller problems.
    • Exercising separation of concerns within the code changes.

What can I do to optimize my changes

  • Use the PullRequestQuantifier to quantify your PR accurately
    • Create a context profile for your repo using the context generator
    • Exclude files that are not necessary to be reviewed or do not increase the review complexity. Example: Autogenerated code, docs, project IDE setting files, binaries, etc. Check out the Excluded section from your prquantifier.yaml context profile.
    • Understand your typical change complexity, drive towards the desired complexity by adjusting the label mapping in your prquantifier.yaml context profile.
    • Only use the labels that matter to you, see context specification to customize your prquantifier.yaml context profile.
  • Change your engineering behaviors
    • For PRs that fall outside of the desired spectrum, review the details and check if:
      • Your PR could be split in smaller, self-contained PRs instead
      • Your PR only solves one particular issue. (For example, don't refactor and code new features in the same PR).

How to interpret the change counts in git diff output

  • One line was added: +1 -0
  • One line was deleted: +0 -1
  • One line was modified: +1 -1 (git diff doesn't know about modified, it will
    interpret that line like one addition plus one deletion)
  • Change percentiles: Change characteristics (addition, deletion, modification)
    of this PR in relation to all other PRs within the repository.


Was this comment helpful? 👍  :ok_hand:  :thumbsdown: (Email)
Customize PullRequestQuantifier for this repository.

@iSazonov
Copy link
Collaborator

@gregsdennis I added new commit to fix packaging.

@gregsdennis
Copy link
Contributor Author

Thank you @iSazonov

I'm going through the checklist now, and the only breaking change that I can think of is the lack of support for single-quoted JSON (which isn't really JSON anyway).

Does this need to be documented somewhere? If so, where? Do I need to create a separate issue to track that?

@gregsdennis gregsdennis changed the title WIP: Test-Json: use JsonSchema.Net instead of NJsonSchema Test-Json: use JsonSchema.Net instead of NJsonSchema Sep 20, 2022
@iSazonov
Copy link
Collaborator

Does this need to be documented somewhere? If so, where? Do I need to create a separate issue to track that?

Common rule for PowerShell is to follow .Net behavior. I think it makes sense to explain the breaking change in docs. But now is not the time. The change has to be approved by MSFT team first. Then there are other Json cmdlets that should be migrated. And finally, there are many small differences between NewtonSoft and .Net implementations. I guess we are not able to describe them all. We can only point out this fact. I don't think this is a critical change, because the .Net implementations follow Json standard very closely.

@gregsdennis The PR contains a lot of temporary comments, so I suggest to close the PR and open new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log Large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Supporting later versions of JSON Schema

3 participants