git.iko.soy/typeable/compaREST
on db716ee help sign in
40 files changed+192−343
since splitsnapshots
unifiedsplit
.github/actions/common_setup/action.yaml+2−2 .github/workflows/github-actions-image.yaml+81−60 .gitmodules+3 CHANGELOG.md+3−7 LICENSE+1−1 README.md+19−40 action.yaml+8−9 app/Data/OpenApi/Compare/Options.hs−1 app/Main.hs−1 awsm-css+1 compaREST.cabal+4−6 css/awsm.min.css−1 default.nix+7−18 docs/Integration_guide.md+2 docs/Releasing.md−15 docs/img/pre-release-artifacts.png docs/img/pre-release-ci.png docs/img/pre-release.png github-action/CompaREST/GitHub/API.hs+2−2 github-action/CompaREST/GitHub/Action/Config.hs+3−7 github-action/Main.hs+7−13 nix/ci.nix+1−6 nix/diff-yaml.nix−20 nix/shell.nix−11 nix/sources.json+13−13 nix/yq.nix−26 policeman.json+6 scripts/diff-yaml−35 src/Data/OpenApi/Compare/PathsPrefixTree.hs+4−5 src/Data/OpenApi/Compare/Report.hs+1−1 src/Data/OpenApi/Compare/Report/Html/Template.hs+1−1 src/Data/OpenApi/Compare/Validate/OpenApi.hs+1−2 src/Data/OpenApi/Compare/Validate/Schema.hs+1−1 src/Data/OpenApi/Compare/Validate/Schema/JsonFormula.hs+6−7 src/Data/OpenApi/Compare/Validate/Schema/Partition.hs+1−4 src/Data/OpenApi/Compare/Validate/Schema/Process.hs−2 stack.yaml+4−16 stack.yaml.lock+4−4 test/Spec/Golden/Extra.hs+2−2 test/golden/common/random-example/trace-tree.yaml+4−4
.github/actions/common_setup/action.yaml+2−2
@@ -30,13 +30,13 @@ runs:
3030 fi
3131
3232 - name: Install Nix
33− uses: cachix/install-nix-action@v27
33+ uses: cachix/install-nix-action@v16
3434 with:
3535 extra_nix_config: |
3636 system-features = kvm
3737 trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
3838 substituters = https://hydra.iohk.io https://cache.nixos.org/
39− - uses: cachix/cachix-action@v15
39+ - uses: cachix/cachix-action@v10
4040 with:
4141 name: typeable
4242 authToken: "${{ inputs.authToken }}"
.github/workflows/github-actions-image.yaml+81−60
@@ -9,23 +9,23 @@ on:
99 types: [prereleased]
1010
1111jobs:
12−# check-formatting:
13−# name: Check Haskell formatting
14−# runs-on: ubuntu-latest
15−# steps:
16−# - uses: actions/checkout@v2
17−#
18−# - name: Common setup
19−# uses: ./.github/actions/common_setup
20−# with:
21−# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
22−#
23−# - name: Run fourmolu
24−# run: |
25−# nix-shell nix/ci.nix -j auto --run "git ls-files '*.hs' | xargs fourmolu -m inplace -o -XRecursiveDo -o -XTypeApplications -o -XPatternSynonyms -o -XBangPatterns"
26−# git diff --exit-code
12+ check-formatting:
13+ name: Check Haskell formatting
14+ runs-on: ubuntu-latest
15+ steps:
16+ - uses: actions/checkout@v2
2717
28− check_versions:
18+ - name: Common setup
19+ uses: ./.github/actions/common_setup
20+ with:
21+ authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
22+
23+ - name: Run fourmolu
24+ run: |
25+ nix-shell nix/ci.nix -j auto --run "git ls-files '*.hs' | xargs fourmolu -m inplace -o -XRecursiveDo -o -XTypeApplications -o -XPatternSynonyms -o -XBangPatterns"
26+ git diff --exit-code
27+
28+ policeman:
2929 runs-on: ubuntu-latest
3030 steps:
3131 - uses: actions/checkout@v2
@@ -37,6 +37,25 @@ jobs:
3737 with:
3838 authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
3939
40+ - name: Run policeman
41+ run: |
42+ jq --argjson msg "$( $(nix-build ci/policeman.nix)/bin/policeman | grep -v "⚙" | jq -aRs . )" ".[0].message = \$msg" <policeman.json >message.json
43+ cat message.json
44+
45+ - name: Post notice
46+ uses: yuzutech/annotations-action@v0.4.0
47+ with:
48+ title: 👮 Policeman
49+ repo-token: "${{ secrets.GITHUB_TOKEN }}"
50+ input: "./message.json"
51+
52+ check_versions:
53+ runs-on: ubuntu-latest
54+ steps:
55+ - uses: actions/checkout@v2
56+ with:
57+ submodules: recursive
58+
4059 - name: Check library version
4160 if: github.event_name == 'release'
4261 run: |
@@ -108,6 +127,13 @@ jobs:
108127 name: compaREST Docker Image
109128 path: compaREST-image.tar.gz
110129
130+ - name: Install skopeo
131+ if: github.event_name == 'release'
132+ shell: bash
133+ run: |
134+ sudo apt-get -y update
135+ sudo apt-get -y install skopeo
136+
111137 - name: Login to DockerHub
112138 uses: docker/login-action@v1.10.0
113139 with:
@@ -159,18 +185,13 @@ jobs:
159185 tag: ${{ github.ref }}
160186
161187 dist:
162− needs: [check_versions, Linux]
188+ needs: check_versions
163189 runs-on: ubuntu-latest
164190 steps:
165191 - uses: actions/checkout@v2
166192 with:
167193 submodules: recursive
168194
169− - name: Common setup
170− uses: ./.github/actions/common_setup
171− with:
172− authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
173−
174195 - name: Cache
175196 uses: actions/cache@v1
176197 with:
@@ -189,7 +210,7 @@ jobs:
189210
190211 - name: Build dist
191212 run: |
192− stack sdist --pvp-bounds both
213+ stack sdist --pvp-bounds both --test-tarball
193214 echo "distPath=$(stack path | awk -F ": " '/dist-dir/ {print $2}')" >> $GITHUB_ENV
194215
195216 - name: Upload compaREST sources artifact
@@ -213,7 +234,7 @@ jobs:
213234 env:
214235 HACKAGE_KEY: ${{ secrets.HACKAGE_KEY }}
215236 run: |
216− stack upload --pvp-bounds both --candidate .
237+ stack upload --pvp-bounds both --test-tarball --candidate .
217238
218239 macOS:
219240 needs: check_versions
@@ -252,39 +273,39 @@ jobs:
252273 file: compaREST-macOS-x86.zip
253274 tag: ${{ github.ref }}
254275
255−# Linux-Windows:
256−# needs: check_versions
257−# runs-on: ubuntu-latest
258−# steps:
259−# - uses: actions/checkout@v2
260−# with:
261−# submodules: recursive
262−#
263−# - name: Common setup
264−# uses: ./.github/actions/common_setup
265−# with:
266−# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
267−#
268−# - name: Build Windows binary
269−# run: |
270−# cp -LR $(nix-build -A WindowsCompaRESTBin -j auto --no-out-link)/bin compaREST
271−#
272−# - name: Upload Windows compaREST bundle
273−# uses: actions/upload-artifact@v2
274−# with:
275−# name: compaREST binary – Windows
276−# path: compaREST
277−#
278−# - name: Zip Release Assets
279−# if: github.event_name == 'release'
280−# shell: bash
281−# run: |
282−# zip -r compaREST-Windows.zip compaREST
283−#
284−# - name: Upload compaREST binary – Windows to release
285−# if: github.event_name == 'release'
286−# uses: svenstaro/upload-release-action@2.2.1
287−# with:
288−# repo_token: ${{ secrets.GITHUB_TOKEN }}
289−# file: compaREST-Windows.zip
290−# tag: ${{ github.ref }}
276+ Linux-Windows:
277+ needs: check_versions
278+ runs-on: ubuntu-latest
279+ steps:
280+ - uses: actions/checkout@v2
281+ with:
282+ submodules: recursive
283+
284+ - name: Common setup
285+ uses: ./.github/actions/common_setup
286+ with:
287+ authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
288+
289+ - name: Build Windows binary
290+ run: |
291+ cp -LR $(nix-build -A WindowsCompaRESTBin -j auto --no-out-link)/bin compaREST
292+
293+ - name: Upload Windows compaREST bundle
294+ uses: actions/upload-artifact@v2
295+ with:
296+ name: compaREST binary – Windows
297+ path: compaREST
298+
299+ - name: Zip Release Assets
300+ if: github.event_name == 'release'
301+ shell: bash
302+ run: |
303+ zip -r compaREST-Windows.zip compaREST
304+
305+ - name: Upload compaREST binary – Windows to release
306+ if: github.event_name == 'release'
307+ uses: svenstaro/upload-release-action@2.2.1
308+ with:
309+ repo_token: ${{ secrets.GITHUB_TOKEN }}
310+ file: compaREST-Windows.zip
311+ tag: ${{ github.ref }}
.gitmodulesnew file+3
@@ -0,0 +1,3 @@
1+[submodule "awsm-css"]
2+ path = awsm-css
3+ url = https://github.com/igoradamenko/awsm.css.git
CHANGELOG.md+3−7
@@ -1,13 +1,9 @@
11# Changelog
22
3−`compaREST` uses [PVP Versioning][1].
3+`comparest` uses [PVP Versioning][1].
44
5−## 0.1.0.1
5+## 0.0.0.0
66
7−* Fixed an issue related to empty commit SHAs in GitHub Actions.
8−
9−## 0.1.0.0
10−
11−* Initial release.
7+* Initially created.
128
139[1]: https://pvp.haskell.org
LICENSE+1−1
@@ -1,6 +1,6 @@
11MIT License
22
3−Copyright (c) 2021 Typeable
3+Copyright (c) 2021 Aleksey Uymanov
44
55Permission is hereby granted, free of charge, to any person obtaining a copy
66of this software and associated documentation files (the "Software"), to deal
README.md+19−40
@@ -1,33 +1,14 @@
1−# compaREST
1+# CompaREST
22
3−[![Hackage](https://img.shields.io/hackage/v/compaREST.svg?logo=haskell)](https://hackage.haskell.org/package/compaREST)
3+[![Hackage](https://img.shields.io/hackage/v/comparest.svg?logo=haskell)](https://hackage.haskell.org/package/comparest)
4+[![Stackage Lts](http://stackage.org/package/comparest/badge/lts)](http://stackage.org/lts/package/comparest)
5+[![Stackage Nightly](http://stackage.org/package/comparest/badge/nightly)](http://stackage.org/nightly/package/comparest)
46[![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
57
68Compatibility checker for OpenAPI
9+# Quick Start Guide
710
8−## Using compaREST in Github Actions
9−
10−Add the following step to your Github Actions workflow:
11−
12−```yaml
13−- uses: typeable/comparest
14− if: ${{ github.event_name == 'pull_request' }}
15− with:
16− old: old-openapi.yaml
17− new: new-openapi.yaml
18−```
19−
20−The `new` and `old` values should be paths to your OpenAPI specifications you want to compare.
21−
22−You will get something like this in your pull requests:
23−
24−![](docs/img/github-action-report.png)
25−
26−For more detail please see our [integration guide](docs/Integration_guide.md).
27−
28−## An example
29−
30−### Your situation
11+## Your situation
3112
3213You are developing a very important server with a REST API. You have clients who use your API that you do not control. Say, you are also developing a mobile app that uses your API and you can't force someone to update to the latest version. (Or you prefer not to for UX reasons.)
3314
@@ -94,7 +75,7 @@ components:
9475 $ref: "#/components/schemas/Pet"
9576```
9677
97−### Evolving your product
78+## Evolving your product
9879
9980Enthused over your initial success you hurry to release a new and improved version of your API and mobile app.
10081
@@ -163,7 +144,7 @@ components:
163144
164145Looking at the very large and complex API description, you grow more and more concerned that your old mobile app might stop working when you update the server. But the spec is too large and too complex to reasonably assess this manually.
165146
166−### Assessing compatibility automatically
147+## Assessing compatibility automatically
167148
168149Luckily, you have access to compaREST which can programmatically analyze your APIs and determine what, if anything, breaks compatibility and what doesn't.
169150
@@ -177,15 +158,15 @@ Running this command will output a file `report.md`, containing the compatibilit
177158
178159> # Summary
179160>
180−> | [❌ Breaking changes](#breaking-changes) | [⚠️ Non-breaking changes](#non-breaking-changes) |
181−> |------------------------------------------|--------------------------------------------------|
182−> | 5 | 6 |
161+> | [⚠️ Breaking changes](#breaking-changes) | [🙆 Non-breaking changes](#non-breaking-changes) | 🤷 Unsupported feature changes |
162+> |------------------------------------------|-------------------------------------------------|-------------------------------|
163+> | 5 | 6 | 0 |
183164>
184−> # <span id="breaking-changes"></span>❌ Breaking changes
165+> # <span id="breaking-changes"></span>⚠️ Breaking changes
185166>
186167> ## **GET** /pets
187168>
188−> ### ⬅️☁️ JSON Response – 200
169+> ### 📱⬅️ JSON Response – 200
189170>
190171> #### `$[*].name(String)`
191172>
@@ -195,7 +176,7 @@ Running this command will output a file `report.md`, containing the compatibilit
195176>
196177> ## **POST** /pets
197178>
198−> ### ➡️☁️ JSON Request
179+> ### 📱➡️ JSON Request
199180>
200181> #### `$.weight`
201182>
@@ -210,7 +191,7 @@ Running this command will output a file `report.md`, containing the compatibilit
210191>
211192> Value is now a multiple of 1.0.
212193>
213−> # <span id="non-breaking-changes"></span>⚠️ Non-breaking changes
194+> # <span id="non-breaking-changes"></span>🙆 Non-breaking changes
214195>
215196> ## **GET** /pets
216197>
@@ -222,7 +203,7 @@ Running this command will output a file `report.md`, containing the compatibilit
222203>
223204> Upper bound changed from 20.0 inclusive to 30.0 inclusive.
224205>
225−> ### ⬅️☁️ JSON Response – 200
206+> ### 📱⬅️ JSON Response – 200
226207>
227208> #### `$[*].weight`
228209>
@@ -239,7 +220,7 @@ Running this command will output a file `report.md`, containing the compatibilit
239220>
240221> ## **POST** /pets
241222>
242−> ### ➡️☁️ JSON Request
223+> ### 📱➡️ JSON Request
243224>
244225> #### `$.name(String)`
245226>
@@ -249,7 +230,7 @@ Running this command will output a file `report.md`, containing the compatibilit
249230
250231You now know exactly in what situations and in what way your 1.0 version of the app will break if you deploy your 1.1 version of the server.
251232
252−### Additional formats
233+## Additional formats
253234
254235You can also produce a self-contained HTML report that you can open in your browser by simply omitting the file extension of the output file:
255236
@@ -257,9 +238,7 @@ You can also produce a self-contained HTML report that you can open in your brow
257238docker run --rm -v $(pwd):/data:rw typeable/comparest --client /data/api-1.0.0.yaml --server /data/api-1.1.0.yaml --output /data/report
258239```
259240
260−## CLI docs
261−
262−For more detail please see our [user guide](docs/User_guide.md).
241+# CLI docs
263242
264243```
265244Usage: comparest (-c|--client ARG) (-s|--server ARG)
action.yaml+8−9
@@ -7,22 +7,21 @@ inputs:
77 default: "${{ github.token }}"
88 required: false
99 repo:
10− description: The owner of the repo in which to post the results.
10+ description: The owner of the repo in which to post the comment.
1111 default: "${{ github.repository }}"
1212 required: false
1313 project_name:
14− description: The name of the project to which the API pertains. Used to name the check. Useful when you have multiple APIs in the same repo.
15− required: false
16− default: ""
14+ description: The name of the project to which the API pertains.
15+ required: true
1716 footer:
18− description: A footer that can be appended to the check body.
17+ description: A footer that can be appended to the comment.
1918 required: false
2019 default: ""
2120 old:
22− description: The path to the old (client) specification of the API.
21+ description: The path to old specification of the API.
2322 required: true
2423 new:
25− description: The path to new (server) specification of the API.
24+ description: The path to new specification of the API.
2625 required: true
2726 sha:
2827 description: The sha of the commit to post the check for.
@@ -30,7 +29,7 @@ inputs:
3029 default: "${{ github.event.pull_request.head.sha }}"
3130runs:
3231 using: "docker"
33− image: "docker://typeable/comparest-github-action:0.1.0.1"
32+ image: "docker://typeable/comparest-github-action:latest"
3433 env:
3534 GITHUB_TOKEN: "${{ inputs.GITHUB_TOKEN }}"
3635 REPO: "${{ inputs.repo }}"
@@ -45,4 +44,4 @@ runs:
4544
4645branding:
4746 icon: crosshair
48− color: blue
47+ color: gray-dark
app/Data/OpenApi/Compare/Options.hs−1
@@ -9,7 +9,6 @@ import Data.OpenApi.Compare.Report
99import GHC.Generics (Generic)
1010import Options.Applicative
1111import Options.Applicative.Help hiding (fullDesc)
12−import Text.PrettyPrint.ANSI.Leijen ((<$$>),string)
1312
1413parseOptions :: IO Options
1514parseOptions = customExecParser (prefs $ showHelpOnError) optionsParserInfo
app/Main.hs−1
@@ -2,7 +2,6 @@ module Main (main) where
22
33import Control.Monad
44import Control.Monad.Except
5−import Control.Monad.Trans (lift)
65import Data.Aeson
76import qualified Data.ByteString.Lazy as BSL
87import Data.Default
awsm-cssnew file+1

Submodule changed.

compaREST.cabal+4−6
@@ -1,6 +1,6 @@
11cabal-version: 2.4
22name: compaREST
3−version: 0.1.0.1
3+version: 0.0.0.0
44synopsis: Compatibility checker for OpenAPI
55description: Compatibility checker for OpenAPI.
66license: MIT
@@ -12,8 +12,8 @@ category: Web
1212build-type: Simple
1313extra-doc-files: README.md
1414 CHANGELOG.md
15−tested-with: GHC == 9.6
16−extra-source-files: css/awsm.min.css
15+tested-with: GHC == 8.10.4
16+extra-source-files: awsm-css/dist/awsm.min.css
1717extra-source-files:
1818 test/golden/**/*.yaml
1919 test/golden/**/*.md
@@ -26,14 +26,13 @@ common common-options
2626 -Wno-safe
2727 -Wno-prepositive-qualified-module
2828 -Wno-missing-import-lists
29− -Wno-missing-kind-signatures
3029 -Wno-partial-fields
3130 -Wno-all-missed-specialisations
3231 -Wno-missing-local-signatures
3332 -Wno-unsafe
3433 -fconstraint-solver-iterations=0
3534 default-language: Haskell2010
36− build-depends: base >= 4.12.0.0 && < 5
35+ build-depends: base >= 4.12.0.0 && < 4.16
3736 , text
3837
3938
@@ -166,7 +165,6 @@ executable compaREST
166165 , containers
167166 , doctemplates
168167 , pandoc-types
169− , prettyprinter-compat-ansi-wl-pprint
170168 ghc-options: -threaded
171169 -rtsopts
172170 -with-rtsopts=-N
css/awsm.min.cssdeleted−1
@@ -1 +0,0 @@
1−@charset "UTF-8";html{font-family:"PT Serif",Georgia,serif;font-size:100%;line-height:1.6;background:#fff;color:#000;-webkit-overflow-scrolling:touch}body{margin:1em;font-size:1rem}@media (min-width:20rem){body{font-size:calc(1rem + .0125*(100vw - 20rem))}}@media (min-width:40rem){body{font-size:1.25rem}}body article,body footer,body header,body main{position:relative;max-width:40rem;margin:0 auto}body>header{margin-bottom:3.5em}body>header h1{margin:0;font-size:1.5em}body>header p{margin:0;font-size:.85em}body>footer{margin-top:4.5em;padding-bottom:1.5em;text-align:center;font-size:.8rem;color:#aaa}details,nav,p{margin:1em 0}nav ul{list-style:none;margin:0;padding:0}nav li{display:inline-block;margin-right:1em;margin-bottom:.25em}nav a:visited{color:#0064c1}article header h1 a:visited:hover,article header h2 a:visited:hover,nav a:hover{color:#3000c1}ol,ul{margin-top:0;padding-top:0;padding-left:2.5em}p{-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}aside:first-child,p:first-child{margin-top:0}aside:last-child,p:last-child{margin-bottom:0}p+ol,p+ul{margin-top:-.75em}p img,p picture{float:right;margin-bottom:.5em;margin-left:.5em}p picture img{float:none;margin:0}blockquote,dd{padding-left:2.5em}dd{margin-bottom:1em;margin-left:0}dt{font-weight:700}blockquote{margin:0}aside{margin:.5em 0;font-style:italic;color:#aaa}@media (min-width:65rem){aside{position:absolute;right:-12.5rem;width:9.375rem;max-width:9.375rem;margin:0;padding-left:.5em;font-size:.8em;border-left:1px solid #f2f2f2}}section+section{margin-top:2em}h1,h2,h3,h4,h5,h6{margin:1.25em 0 0;line-height:1.2}h1:focus>a[href^="#"][id],h1:hover>a[href^="#"][id],h2:focus>a[href^="#"][id],h2:hover>a[href^="#"][id],h3:focus>a[href^="#"][id],h3:hover>a[href^="#"][id],h4:focus>a[href^="#"][id],h4:hover>a[href^="#"][id],h5:focus>a[href^="#"][id],h5:hover>a[href^="#"][id],h6:focus>a[href^="#"][id],h6:hover>a[href^="#"][id]{opacity:1;transition:opacity 0s,color 300ms ease-out}figure+p,h1+details,h1+p,h2+details,h2+p,h3+details,h3+p,h4+details,h4+p,h5+details,h5+p,h6+details,h6+p{margin-top:.5em}h1>a[href^="#"][id],h2>a[href^="#"][id],h3>a[href^="#"][id],h4>a[href^="#"][id],h5>a[href^="#"][id],h6>a[href^="#"][id]{position:absolute;left:-.5em;opacity:0;background:0 0;color:rgba(0,0,0,.5);transition:opacity 300ms ease-out}h1>a[href^="#"][id]:focus,h1>a[href^="#"][id]:hover,h1>a[href^="#"][id]:target,h2>a[href^="#"][id]:focus,h2>a[href^="#"][id]:hover,h2>a[href^="#"][id]:target,h3>a[href^="#"][id]:focus,h3>a[href^="#"][id]:hover,h3>a[href^="#"][id]:target,h4>a[href^="#"][id]:focus,h4>a[href^="#"][id]:hover,h4>a[href^="#"][id]:target,h5>a[href^="#"][id]:focus,h5>a[href^="#"][id]:hover,h5>a[href^="#"][id]:target,h6>a[href^="#"][id]:focus,h6>a[href^="#"][id]:hover,h6>a[href^="#"][id]:target{opacity:1;box-shadow:none;color:#000;transition:opacity 0s,color 0s}h1>a[href^="#"][id]:target:focus,h2>a[href^="#"][id]:target:focus,h3>a[href^="#"][id]:target:focus,h4>a[href^="#"][id]:target:focus,h5>a[href^="#"][id]:target:focus,h6>a[href^="#"][id]:target:focus{outline:0}h1>a[href^="#"][id]::before,h2>a[href^="#"][id]::before,h3>a[href^="#"][id]::before,h4>a[href^="#"][id]::before,h5>a[href^="#"][id]::before,h6>a[href^="#"][id]::before{content:"•"}h1{font-size:2em}h2{font-size:1.75em}h3{font-size:1.25em}h4{font-size:1.15em}h5,h6{font-size:1em}h6{margin-top:1em;color:#aaa}article+article{margin-top:5em}article header p{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:.6em;color:#aaa}article header p+h1,article header p+h2{margin-top:-.25em}article header h1+p,article header h2+p{margin-top:.25em}article header h1 a,article header h2 a{color:#000;background:url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="1"%3E%3Crect x="0" y="0.5" width="1" height="0.5" fill="rgba(0, 0, 0, 0.35)"/%3E%3C/svg%3E') left bottom repeat-x}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){article header h1 a,article header h2 a{background:url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="2"%3E%3Crect x="0" y="1" width="1" height="1" fill="rgba(0, 0, 0, 0.35)"/%3E%3C/svg%3E') left bottom repeat-x}}article header h1 a:visited,article header h2 a:visited{color:#aaa;background:url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="1"%3E%3Crect x="0" y="0.5" width="1" height="0.5" fill="rgba(170, 170, 170, 0.35)"/%3E%3C/svg%3E') left bottom repeat-x}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){article header h1 a:visited,article header h2 a:visited{background:url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="2"%3E%3Crect x="0" y="1" width="1" height="1" fill="rgba(170, 170, 170, 0.35)"/%3E%3C/svg%3E') left bottom repeat-x}}article>footer{margin-top:1.5em;font-size:.85em}a,abbr{text-decoration:none}a{color:#0064c1;transition:color 300ms ease-out,box-shadow 300ms ease-out;background:url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="1"%3E%3Crect x="0" y="0.5" width="1" height="0.5" fill="rgba(0, 100, 193, 0.35)"/%3E%3C/svg%3E') left bottom repeat-x}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){a{background:url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="2"%3E%3Crect x="0" y="1" width="1" height="1" fill="rgba(0, 100, 193, 0.35)"/%3E%3C/svg%3E') left bottom repeat-x}}a:visited{color:#80b2e0}a:active,a:hover{outline-width:0}a:hover{box-shadow:inset 0 -1px #3000c1;color:#3000c1;transition:color 0s,box-shadow 0s}abbr{margin-right:-.075em;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none;letter-spacing:.075em;font-size:.9em;border-bottom:1px dotted}img,picture{display:block;max-width:100%;margin:0 auto}audio,video{width:100%;max-width:100%}video{-o-object-position:0 -1px;object-position:0 -1px}figure{margin:1em 0 .5em;padding:0}figure figcaption{opacity:.65;font-size:.85em}table{display:inline-block;border-spacing:0;border-collapse:collapse;overflow-x:auto;max-width:100%;text-align:left;vertical-align:top;background:linear-gradient(rgba(0,0,0,.15) 0%,rgba(0,0,0,.15) 100%) 0 0,linear-gradient(rgba(0,0,0,.15) 0%,rgba(0,0,0,.15) 100%) 100% 0;background-attachment:scroll,scroll;background-size:1px 100%,1px 100%;background-repeat:no-repeat,no-repeat}table caption{font-size:.9em;background:#fff}table td,table th{padding:.35em .75em;vertical-align:top;font-size:.9em;border:1px solid #f2f2f2;border-top:0;border-left:0}table td:first-child,table th:first-child{padding-left:0;background-image:linear-gradient(to right,#fff 50%,rgba(255,255,255,0) 100%);background-size:2px 100%;background-repeat:no-repeat}table td:last-child,table th:last-child{padding-right:0;border-right:0;background-image:linear-gradient(to left,#fff 50%,rgba(255,255,255,0) 100%);background-position:100% 0;background-size:2px 100%;background-repeat:no-repeat}table td:only-child,table th:only-child{background-image:linear-gradient(to right,#fff 50%,rgba(255,255,255,0) 100%),linear-gradient(to left,#fff 50%,rgba(255,255,255,0) 100%);background-position:0 0,100% 0;background-size:2px 100%,2px 100%;background-repeat:no-repeat,no-repeat}table th{line-height:1.2}code,kbd,samp,var{font-family:Consolas,"Lucida Console",Monaco,monospace;font-style:normal}pre{overflow-x:auto;font-size:.8em;background:linear-gradient(rgba(0,0,0,.15) 0%,rgba(0,0,0,.15) 100%) 0 0,linear-gradient(rgba(0,0,0,.15) 0%,rgba(0,0,0,.15) 100%) 100% 0;background-attachment:scroll,scroll;background-size:1px 100%,1px 100%;background-repeat:no-repeat,no-repeat}pre>code,summary{display:inline-block}pre>code{overflow-x:visible;box-sizing:border-box;min-width:100%;border-right:3px solid #fff;border-left:1px solid #fff}hr{height:1px;margin:2em 0;border:0;background:#f2f2f2}details[open]{padding-bottom:.5em;border-bottom:1px solid #f2f2f2}summary{font-weight:700;border-bottom:1px dashed;cursor:pointer}summary::-webkit-details-marker{display:none}noscript{color:#d00000}::selection{background:rgba(0,100,193,.15)}
default.nix+7−18
@@ -1,13 +1,11 @@
11{ sources ? import ./nix/sources.nix
22, haskellNix ? import sources.haskellNix { inherit system; }
3−, pkgs ? import haskellNix.sources.nixpkgs-2311 (haskellNix.nixpkgsArgs // { inherit system; })
3+, pkgs ? import haskellNix.sources.nixpkgs-2105 (haskellNix.nixpkgsArgs // { inherit system; })
44, system ? builtins.currentSystem
55, nix-filter ? import sources.nix-filter
66}:
77let
88 masterPkgs = import sources.nixpkgs { inherit system; };
9− yq = import ./nix/yq.nix { pkgs = masterPkgs; };
10− diffYaml = import ./nix/diff-yaml.nix { pkgs = masterPkgs; };
119
1210 hsPkgs = pkgs.haskell-nix.stackProject {
1311 src = nix-filter {
@@ -40,7 +38,7 @@ let
4038 (inDirectory ./src)
4139 (inDirectory ./app)
4240 (inDirectory ./github-action)
43− ./css/awsm.min.css
41+ ./awsm-css/dist/awsm.min.css
4442 ./LICENSE
4543 ];
4644 };
@@ -99,18 +97,6 @@ let
9997 };
10098
10199 WindowsCompaRESTBin = hsPkgs.projectCross.mingwW64.hsPkgs.compaREST.components.exes.compaREST;
102−
103− # We use the static version so that we don't have to rebuild everything on CI.
104− # The only binaries build on CI are static.
105− test = hsPkgs.projectCross.musl64.hsPkgs.compaREST.components.tests.compaREST-tests.overrideAttrs (final: old: {
106− buildInputs = old.buildInputs ++ [ diffYaml yq ];
107− nativeBuildInputs = old.nativeBuildInputs ++ (with masterPkgs; [ makeWrapper ]);
108−
109− postInstall = ''
110− wrapProgram $out/bin/compaREST-tests \
111− --prefix PATH : ${masterPkgs.lib.makeBinPath [ diffYaml yq ]}
112− '';
113− });
114100in
115101{
116102 inherit
@@ -120,6 +106,9 @@ in
120106 compaRESTBin
121107 hsPkgs
122108 macOSCompaRESTBundle
123− WindowsCompaRESTBin
124− test;
109+ WindowsCompaRESTBin;
110+
111+ # We use the static version so that we don't have to rebuild everything on CI.
112+ # The only binaries build on CI are static.
113+ test = hsPkgs.projectCross.musl64.hsPkgs.compaREST.components.tests.compaREST-tests;
125114}
docs/Integration_guide.md+2
@@ -28,6 +28,8 @@ In our example we have already generated the two OpenAPI specs and placed them i
2828
2929We can now run our action:
3030
31+##### NOTE: will only work after public release
32+
3133```yaml
3234- uses: typeable/comparest
3335 with:
docs/Releasing.mddeleted−15
@@ -1,15 +0,0 @@
1−# The release procedure
2−
3−1. Update the version number everywhere:
4− 1. Version in [compaREST.cabal](../compaREST.cabal)
5− 2. Docker tag in [action.yaml](../action.yaml)
6− 3. Set the version of unreleased changes in [CHANGELOG.md](../CHANGELOG.md)
7−2. Publish!
8− 1. Create a pre-release on GitHub:
9− ![](img/pre-release.png)
10− 2. This will automatically start the release procedure. You can check the state of it in the "Actions" tab on GitHub:
11− ![](img/pre-release-ci.png)
12− 3. If everything goes as planned, the release action should pass and all assets should be added to the release:
13− ![](img/pre-release-artifacts.png)
14− 4. The new version should be automatically uploaded a release candidate to [Hackage](https://hackage.haskell.org/package/compaREST/candidates/). Make sure everything looks okay and publish it.
15− 5. Go to the Releases tab on GitHub and edit the release to make it not a "pre-release".
docs/img/pre-release-artifacts.pngdeleted

Binary file not shown.

docs/img/pre-release-ci.pngdeleted

Binary file not shown.

docs/img/pre-release.pngdeleted

Binary file not shown.

github-action/CompaREST/GitHub/API.hs+2−2
@@ -29,7 +29,7 @@ postStatusProcessing = do
2929 repoOwner
3030 repoName
3131 Check
32− { checkName = mkName Proxy checkName
32+ { checkName = mkName Proxy $ "compaREST – " <> projectName
3333 , checkSha = sha
3434 , checkDetailsURL = Nothing
3535 , checkExternalId = Nothing
@@ -60,7 +60,7 @@ postStatus x = do
6060 repoOwner
6161 repoName
6262 Check
63− { checkName = mkName Proxy checkName
63+ { checkName = mkName Proxy $ "compaREST – " <> projectName
6464 , checkSha = sha
6565 , checkDetailsURL = Nothing
6666 , checkExternalId = Nothing
github-action/CompaREST/GitHub/Action/Config.hs+3−7
@@ -8,14 +8,13 @@ import Data.Text (Text)
88import qualified Data.Text as T
99import qualified GitHub as GH
1010
11−import Data.Functor
1211import System.Envy
1312
1413data Config = Config
1514 { githubToken :: GH.Auth
1615 , repoOwner :: GH.Name GH.Owner
1716 , repoName :: GH.Name GH.Repo
18− , checkName :: Text
17+ , projectName :: Text
1918 , footerText :: Text
2019 , root :: FilePath
2120 , sha :: GH.Name GH.Commit
@@ -28,10 +27,7 @@ instance FromEnv Config where
2827 T.split (== '/') <$> env "REPO" >>= \case
2928 [owner, name] -> pure (owner, name)
3029 _ -> fail "malformed repo"
31− checkName <-
32− envMaybe "PROJECT_NAME" <&> \case
33− Just pName | not . T.null . T.strip $ pName -> "compaREST – " <> pName
34− _ -> "compaREST"
30+ projectName <- env "PROJECT_NAME"
3531 footerText <- env "FOOTER"
3632 root <- envMaybe "ROOT" .!= "."
3733 sha <- env "SHA"
@@ -40,7 +36,7 @@ instance FromEnv Config where
4036 { githubToken = token
4137 , repoOwner = GH.mkName Proxy owner
4238 , repoName = GH.mkName Proxy repo
43− , checkName = checkName
39+ , projectName = projectName
4440 , footerText = footerText
4541 , root = root
4642 , sha = GH.mkName Proxy sha
github-action/Main.hs+7−13
@@ -9,7 +9,6 @@ import Control.Monad.Freer.GitHub
99import Control.Monad.Freer.Reader
1010import Data.OpenApi.Compare.Run
1111import Data.Text (Text)
12−import qualified Data.Text as T
1312import qualified Data.Yaml.Aeson as Yaml
1413import qualified GitHub as GH
1514import System.Environment
@@ -23,18 +22,13 @@ import Text.Pandoc.Writers
2322main :: IO ()
2423main = do
2524 cfg <- decodeEnv >>= either error pure
26− case sha cfg of
27− x | T.null . T.strip . GH.untagName $ x -> do
28− putStrLn "SHA not specified. Exiting without doing anything."
29− pure ()
30− _ ->
31− getArgs >>= \case
32− ["pre"] -> runPre cfg
33− ["run"] -> do
34− oldFile <- getEnv "OLD"
35− newFile <- getEnv "NEW"
36− runRun cfg (root cfg </> oldFile) (root cfg </> newFile)
37− _ -> error "Invalid arguments."
25+ getArgs >>= \case
26+ ["pre"] -> runPre cfg
27+ ["run"] -> do
28+ oldFile <- getEnv "OLD"
29+ newFile <- getEnv "NEW"
30+ runRun cfg (root cfg </> oldFile) (root cfg </> newFile)
31+ _ -> error "Invalid arguments."
3832
3933runner :: Config -> Eff '[GitHub, Error GH.Error, Reader Config, IO] a -> IO a
4034runner cfg =
nix/ci.nix+1−6
@@ -1,11 +1,6 @@
11{ sources ? import ./sources.nix
22, pkgs ? import sources.nixpkgs { }
33}:
4−
5−let
6− yq = import ./yq.nix { inherit pkgs; };
7− diff-yaml = import ./diff-yaml.nix { inherit pkgs; };
8−in
94pkgs.mkShell {
10− packages = [ pkgs.haskellPackages.fourmolu diff-yaml yq ];
5+ packages = [ pkgs.haskellPackages.fourmolu ];
116}
nix/diff-yaml.nixdeleted−20
@@ -1,20 +0,0 @@
1−{ pkgs ? import <nixpkgs> {} }:
2−
3−let
4− inherit (pkgs) stdenv;
5− yq = import ./yq.nix { inherit pkgs; };
6−in
7−stdenv.mkDerivation {
8− name = "diff-yaml";
9−
10− src = ../scripts/diff-yaml;
11−
12− buildInputs = [ pkgs.bash yq ];
13−
14− phases = [ "installPhase" ];
15−
16− installPhase = ''
17− mkdir -p $out/bin
18− cp $src $out/bin/diff-yaml
19− '';
20−}
nix/shell.nixdeleted−11
@@ -1,11 +0,0 @@
1−{ sources ? import ./sources.nix
2−, pkgs ? import sources.nixpkgs { }
3−}:
4−
5−let
6− patched-yq = import ./yq.nix { inherit pkgs; };
7− diffYaml = import ./diff-yaml.nix { inherit pkgs; };
8−in
9−pkgs.mkShell {
10− buildInputs = with pkgs; [ pkg-config diffYaml patched-yq zlib ];
11−}
nix/sources.json+13−13
@@ -5,10 +5,10 @@
55 "homepage": "https://input-output-hk.github.io/haskell.nix",
66 "owner": "input-output-hk",
77 "repo": "haskell.nix",
8− "rev": "d7f95903c84a5a50d6fe0844280da82c3c81680a",
9− "sha256": "02870rk4sx44lwwa0k20iwdhqcx0ayz34yb3b0qy045p22q45815",
8+ "rev": "c8a8f57de3c14fcf1c5cda045ed885fb6d06a00e",
9+ "sha256": "0frzmvz8rhb4vgx20qms9xxqbkmg5pwivis4qis63ny5wxclzb34",
1010 "type": "tarball",
11− "url": "https://github.com/input-output-hk/haskell.nix/archive/d7f95903c84a5a50d6fe0844280da82c3c81680a.tar.gz",
11+ "url": "https://github.com/input-output-hk/haskell.nix/archive/c8a8f57de3c14fcf1c5cda045ed885fb6d06a00e.tar.gz",
1212 "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
1313 },
1414 "niv": {
@@ -17,22 +17,22 @@
1717 "homepage": "https://github.com/nmattia/niv",
1818 "owner": "nmattia",
1919 "repo": "niv",
20− "rev": "f7c538837892dd2eb83567c9f380a11efb59b53f",
21− "sha256": "0xl33k24vfc29cg9lnp95kvcq69qbq5fzb7jk9ig4lgrhaarh651",
20+ "rev": "5830a4dd348d77e39a0f3c4c762ff2663b602d4c",
21+ "sha256": "1d3lsrqvci4qz2hwjrcnd8h5vfkg8aypq3sjd4g3izbc8frwz5sm",
2222 "type": "tarball",
23− "url": "https://github.com/nmattia/niv/archive/f7c538837892dd2eb83567c9f380a11efb59b53f.tar.gz",
23+ "url": "https://github.com/nmattia/niv/archive/5830a4dd348d77e39a0f3c4c762ff2663b602d4c.tar.gz",
2424 "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
2525 },
2626 "nix-filter": {
27− "branch": "main",
27+ "branch": "master",
2828 "description": "a small self-container source filtering lib",
2929 "homepage": "",
3030 "owner": "numtide",
3131 "repo": "nix-filter",
32− "rev": "3342559a24e85fc164b295c3444e8a139924675b",
33− "sha256": "08xia32g5jzaiyhfl3kzxslzbr4w1i56i0mhy5gpfggv8gqy8sym",
32+ "rev": "3c9e33ed627e009428197b07216613206f06ed80",
33+ "sha256": "19w142crrkywxynmyw4rhz4nglrg64yjawfkw3j91qwkwbfjds84",
3434 "type": "tarball",
35− "url": "https://github.com/numtide/nix-filter/archive/3342559a24e85fc164b295c3444e8a139924675b.tar.gz",
35+ "url": "https://github.com/numtide/nix-filter/archive/3c9e33ed627e009428197b07216613206f06ed80.tar.gz",
3636 "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
3737 },
3838 "nixpkgs": {
@@ -41,10 +41,10 @@
4141 "homepage": "",
4242 "owner": "NixOS",
4343 "repo": "nixpkgs",
44− "rev": "bf038bd724982de67a2ee9a6b2f1fcb7d6a87bd7",
45− "sha256": "0ivvwdmg9fipj6ylq5ipxqpb0xnz6hsx3lyn377jacfpiqi9w0cv",
44+ "rev": "f0fe5e9ba08e658474476317717aca7acacef4d4",
45+ "sha256": "1n5syynwmg3x8lj2kyb2ilbxw5nmw7f2kw6yxsi8qadx91hrvkwm",
4646 "type": "tarball",
47− "url": "https://github.com/NixOS/nixpkgs/archive/bf038bd724982de67a2ee9a6b2f1fcb7d6a87bd7.tar.gz",
47+ "url": "https://github.com/NixOS/nixpkgs/archive/f0fe5e9ba08e658474476317717aca7acacef4d4.tar.gz",
4848 "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
4949 }
5050}
nix/yq.nixdeleted−26
@@ -1,26 +0,0 @@
1−{ pkgs ? import <nixpkgs> {} }:
2−
3−# Make yq work inside whatever `stack test` launches.
4−# Nuke this when https://github.com/kislyuk/yq/pull/193 is merged
5−# and nixpkgs includes that fix.
6−
7−let
8− yq-patch = pkgs.writeText "yq-tty-fix.patch" ''
9−diff --git a/yq/__init__.py b/yq/__init__.py
10−index d95ac4b..ae7d59e 100644
11−--- a/yq/__init__.py
12−+++ b/yq/__init__.py
13−@@ -110,7 +110,7 @@ def cli(args=None, input_format="yaml", program_name="yq"):
14− in_place = args.in_place
15− delattr(args, "in_place")
16−
17−- if sys.stdin.isatty() and not args.input_streams:
18−+ if (sys.stdin is None or sys.stdin.isatty()) and not args.input_streams:
19− parser.print_help()
20− sys.exit(2)
21− elif not args.input_streams:
22− '';
23−in
24−pkgs.yq.overrideAttrs (final: old: {
25− patches = old.patches ++ [ yq-patch ];
26−})
policeman.jsonnew file+6
@@ -0,0 +1,6 @@
1+[{
2+ "file": "compaREST.cabal",
3+ "annotation_level": "notice",
4+ "end_line": 0,
5+ "start_line": 0
6+}]
scripts/diff-yamldeleted−35
@@ -1,35 +0,0 @@
1−#!/usr/bin/env bash
2−set -e
3−
4−# Normalise YAML files passed as inputs, then run diff on them.
5−
6−check_util() {
7− local util=$1
8−
9− if [ -z $util ]; then
10− echo "Error: $util not found in PATH"
11− exit 1
12− fi
13−}
14−
15−DIFF=`which diff`
16−check_util $DIFF
17−
18−YQ=`which yq`
19−check_util $YQ
20−
21−# Only normalise YAML files.
22−# Print anything else as is.
23−normalise() {
24− local file=$1
25− local contents=($YQ -y -S '.' $file)
26−
27− # if $contents contains actual YAML data, print it
28− if [[ $? == 0 ]]; then
29− echo $contents
30− else
31− cat $file
32− fi
33−}
34−
35−$DIFF -u <(normalise $1) <(normalise $2)
src/Data/OpenApi/Compare/PathsPrefixTree.hs+4−5
@@ -23,8 +23,7 @@ where
2323import Control.Monad
2424import Data.Aeson
2525import Data.Foldable hiding (null, toList)
26−import qualified Data.Aeson.Key as Key
27−import qualified Data.Aeson.KeyMap as KeyMap
26+import qualified Data.HashMap.Strict as HM
2827import Data.Kind
2928import qualified Data.Map as M
3029import Data.Monoid
@@ -257,7 +256,7 @@ newtype MergableObject = MergableObject {getMergableObject :: Object}
257256
258257instance Semigroup MergableObject where
259258 (MergableObject x) <> (MergableObject y) =
260− MergableObject $ KeyMap.unionWith mergeValue x y
259+ MergableObject $ HM.unionWith mergeValue x y
261260 where
262261 mergeValue :: Value -> Value -> Value
263262 mergeValue (Object a) (Object b) =
@@ -272,6 +271,6 @@ instance Monoid MergableObject where
272271
273272traceObject :: Paths q r a -> Value -> Object
274273traceObject Root (Object o) = o
275−traceObject Root v = KeyMap.singleton "root" v
274+traceObject Root v = HM.singleton "root" v
276275traceObject (root `Snoc` s) v =
277− traceObject root . Object $ KeyMap.singleton (Key.fromText . T.pack . show $ s) v
276+ traceObject root . Object $ HM.singleton (T.pack . show $ s) v
src/Data/OpenApi/Compare/Report.hs+1−1
@@ -198,7 +198,7 @@ showErrs x@(P.PathsPrefixNode currentIssues _) =
198198 let -- Extract this pattern if more cases like this arise
199199 ( removedPaths :: Maybe (Orientation, [Issue 'APILevel])
200200 , otherIssues :: Set (AnIssue a)
201− ) = case eqT @a @'APILevel of
201+ ) = case eqT @a @ 'APILevel of
202202 Just Refl
203203 | (S.toList -> p@((AnIssue ori _) : _), o) <-
204204 S.partition
src/Data/OpenApi/Compare/Report/Html/Template.hs+1−1
@@ -36,4 +36,4 @@ template =
3636 \</html>"
3737
3838awsmCss :: ByteString
39−awsmCss = $(makeRelativeToProject "css/awsm.min.css" >>= embedFile)
39+awsmCss = $(makeRelativeToProject "awsm-css/dist/awsm.min.css" >>= embedFile)
src/Data/OpenApi/Compare/Validate/OpenApi.hs+1−2
@@ -38,8 +38,7 @@ tracedSecuritySchemes :: Traced OpenApi -> Traced (Definitions SecurityScheme)
3838tracedSecuritySchemes oa =
3939 traced
4040 (ask oa >>> step ComponentsSecurityScheme)
41− (unSecurityDefinitions . _componentsSecuritySchemes . _openApiComponents . extract $ oa)
42− where unSecurityDefinitions (SecurityDefinitions ds) = ds
41+ (_componentsSecuritySchemes . _openApiComponents . extract $ oa)
4342
4443tracedResponses :: Traced OpenApi -> Traced (Definitions Response)
4544tracedResponses oa =
src/Data/OpenApi/Compare/Validate/Schema.hs+1−1
@@ -5,7 +5,7 @@ module Data.OpenApi.Compare.Validate.Schema
55 )
66where
77
8−import Control.Monad (when,unless)
8+import Control.Monad.Writer
99import qualified Data.Aeson as A
1010import Data.Coerce
1111import Data.Foldable (for_, toList)
src/Data/OpenApi/Compare/Validate/Schema/JsonFormula.hs+6−7
@@ -18,11 +18,10 @@ where
1818
1919import Algebra.Lattice
2020import qualified Data.Aeson as A
21−import qualified Data.Aeson.Key as Key
22−import qualified Data.Aeson.KeyMap as KeyMap
2321import qualified Data.ByteString.Lazy as BSL
2422import qualified Data.Foldable as F
2523import Data.Functor
24+import qualified Data.HashMap.Strict as HM
2625import Data.Int
2726import Data.Kind
2827import qualified Data.Map as M
@@ -40,7 +39,7 @@ import Data.Text (Text)
4039import qualified Data.Text as T
4140import qualified Data.Text.Encoding as T
4241import Data.Typeable
43−import Text.Pandoc.Builder hiding (Format)
42+import Text.Pandoc.Builder hiding (Format, Null)
4443import Text.Regex.Pcre2
4544
4645data Bound a = Exclusive !a | Inclusive !a
@@ -178,10 +177,10 @@ satisfiesTyped (TArray a) (MaxItems m) = fromIntegral (F.length a) <= m
178177satisfiesTyped (TArray a) (MinItems m) = fromIntegral (F.length a) >= m
179178satisfiesTyped (TArray a) UniqueItems = S.size (S.fromList $ F.toList a) == F.length a -- TODO: could be better #36
180179satisfiesTyped (TObject o) (Properties props additional _) =
181− all (`KeyMap.member` o) (map Key.fromText $ M.keys (M.filter propRequired props))
182− && all (\(k, v) -> satisfies v $ maybe additional propFormula $ M.lookup (Key.toText k) props) (KeyMap.toList o)
183−satisfiesTyped (TObject o) (MaxProperties m) = fromIntegral (KeyMap.size o) <= m
184−satisfiesTyped (TObject o) (MinProperties m) = fromIntegral (KeyMap.size o) >= m
180+ all (`HM.member` o) (M.keys (M.filter propRequired props))
181+ && all (\(k, v) -> satisfies v $ maybe additional propFormula $ M.lookup k props) (HM.toList o)
182+satisfiesTyped (TObject o) (MaxProperties m) = fromIntegral (HM.size o) <= m
183+satisfiesTyped (TObject o) (MinProperties m) = fromIntegral (HM.size o) >= m
185184
186185checkNumberFormat :: Format -> Scientific -> Bool
187186checkNumberFormat "int32" (toRational -> n) =
src/Data/OpenApi/Compare/Validate/Schema/Partition.hs+1−4
@@ -16,7 +16,6 @@ where
1616import Algebra.Lattice
1717import Algebra.Lattice.Lifted
1818import Control.Applicative
19−import Control.Monad (when)
2019import Control.Monad.Reader hiding (ask)
2120import qualified Control.Monad.Reader as R
2221import Control.Monad.State
@@ -32,7 +31,6 @@ import qualified Data.List as L
3231import qualified Data.List.NonEmpty as NE
3332import qualified Data.Map as M
3433import Data.Maybe
35−import Data.Monoid
3634import Data.OpenApi
3735import Data.OpenApi.Compare.Memo
3836import Data.OpenApi.Compare.References
@@ -45,8 +43,7 @@ import Data.Ord
4543import qualified Data.Set as S
4644import Data.Text (Text)
4745import qualified Data.Text as T
48−import Data.Traversable (forM)
49−import Text.Pandoc.Builder hiding (Format)
46+import Text.Pandoc.Builder hiding (Format, Null)
5047
5148data PartitionData
5249 = DByEnumValue (DNF (S.Set A.Value))
src/Data/OpenApi/Compare/Validate/Schema/Process.hs−2
@@ -13,7 +13,6 @@ import Data.Functor.Identity
1313import qualified Data.HashMap.Strict.InsOrd as IOHM
1414import qualified Data.Map as M
1515import Data.Maybe
16−import Data.Monoid
1716import Data.OpenApi hiding (get)
1817import Data.OpenApi.Compare.Behavior
1918import Data.OpenApi.Compare.Memo
@@ -29,7 +28,6 @@ import Data.OpenApi.Compare.Validate.Schema.Traced
2928import Data.OpenApi.Compare.Validate.Schema.TypedJson
3029import Data.Ord
3130import qualified Data.Set as S
32−import Data.Traversable (forM)
3331
3432-- | A fake writer monad that doesn't actually record anything and allows lazy recursion.
3533newtype Silent w a = Silent {runSilent :: a}
stack.yaml+4−16
@@ -1,23 +1,11 @@
1−resolver: lts-22.34
1+resolver: lts-18.16
22
33packages:
44 - .
55
66extra-deps:
7− - base16-bytestring-1.0.2.0
8− - freer-simple-1.2.1.2
9− - generics-sop-0.5.1.4
10− - github-0.29
11− - http-link-header-1.2.1
127 - open-union-0.4.0.0
13− - th-abstraction-0.7.0.0
148 - type-fun-0.1.3
15− - typerep-map-0.6.0.0
16−
17−# Required for freer-simple and typerep-map
18−allow-newer: true
19−
20−nix:
21−# packages: [pkg-config yq zlib]
22− shell-file: ./nix/shell.nix
23− pure: false
9+ - github-0.26
10+ - base16-bytestring-0.1.1.7
11+ - http-link-header-1.0.3.1
stack.yaml.lock+4−4
@@ -41,7 +41,7 @@ packages:
4141 hackage: http-link-header-1.0.3.1
4242snapshots:
4343- completed:
44− size: 587393
45− url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/25.yaml
46− sha256: 1b74fb5e970497b5aefae56703f1bd44aa648bd1a5ef95c1eb8c29775087e2bf
47− original: lts-18.25
44+ size: 586286
45+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/16.yaml
46+ sha256: cdead65fca0323144b346c94286186f4969bf85594d649c49c7557295675d8a5
47+ original: lts-18.16
test/Spec/Golden/Extra.hs+2−2
@@ -59,7 +59,7 @@ goldenInputsTree ::
5959 s ->
6060 (t -> IO BSL.ByteString) ->
6161 IO TestTree
62−goldenInputsTree name filepath golden inp f =
62+goldenInputsTree name filepath golden inp f = do
6363 runTestInputTree golden f <$> getGoldenInputs name filepath inp
6464
6565runTestInputTree ::
@@ -72,7 +72,7 @@ runTestInputTree golden f (TestInputNode name rest) =
7272runTestInputTree golden f (TestInputLeaf name t path) =
7373 goldenVsStringDiff
7474 name
75− (\ref new -> ["diff-yaml", ref, new])
75+ (\ref new -> ["diff", "-u", ref, new])
7676 (path </> golden)
7777 (f t)
7878
test/golden/common/random-example/trace-tree.yaml+4−4
@@ -23,10 +23,6 @@ forwardChanges:
2323backwardChanges:
2424 AtPath "/pets":
2525 InOperation GetMethod:
26− InParam "limit":
27− InParamSchema:
28− OfType Number: MatchingMaximumWeak (ProdCons {producer = Inclusive 30.0,
29− consumer = Inclusive 20.0})
3026 WithStatusCode 200:
3127 ResponsePayload:
3228 PayloadSchema:
@@ -37,6 +33,10 @@ backwardChanges:
3733 - TypesRestricted [Number]
3834 - AdditionalToProperty
3935 - OfType Number: NoMatchingMultipleOf 1.0
36+ InParam "limit":
37+ InParamSchema:
38+ OfType Number: MatchingMaximumWeak (ProdCons {producer = Inclusive 30.0,
39+ consumer = Inclusive 20.0})
4040 InOperation PostMethod:
4141 InRequest:
4242 InPayload: