packages feed

github-tools 0.1.1 → 0.1.2

raw patch · 120 files changed

+8796/−525 lines, 120 filesdep +Diffdep +QuickCheckdep +aesondep −groomdep −tagsoupdep ~basedep ~githubdep ~http-clientnew-component:exe:hub-automergenew-component:exe:hub-changelognew-component:exe:hub-graphnew-component:exe:hub-pullsnew-component:exe:hub-roadmapnew-component:exe:webservice

Dependencies added: Diff, QuickCheck, aeson, aeson-pretty, case-insensitive, cryptohash, directory, expiring-cache-map, github-tools, hspec, http-media, http-types, pretty, process, quickcheck-text, servant, servant-server, split, suspend, timers, unix, unordered-containers, uuid, wai, wai-cors, wai-extra, warp

Dependencies removed: groom, tagsoup

Dependency ranges changed: base, github, http-client

Files

LICENSE view
@@ -1,5 +1,5 @@-                    GNU AFFERO GENERAL PUBLIC LICENSE-                       Version 3, 19 November 2007+                    GNU GENERAL PUBLIC LICENSE+                       Version 3, 29 June 2007   Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>  Everyone is permitted to copy and distribute verbatim copies@@ -7,15 +7,17 @@                              Preamble -  The GNU Affero General Public License is a free, copyleft license for-software and other kinds of works, specifically designed to ensure-cooperation with the community in the case of network server software.+  The GNU General Public License is a free, copyleft license for+software and other kinds of works.    The licenses for most software and other practical works are designed to take away your freedom to share and change the works.  By contrast,-our General Public Licenses are intended to guarantee your freedom to+the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free-software for all its users.+software for all its users.  We, the Free Software Foundation, use the+GNU General Public License for most of our software; it applies also to+any other work released this way by its authors.  You can apply it to+your programs, too.    When we speak of free software, we are referring to freedom, not price.  Our General Public Licenses are designed to make sure that you@@ -24,35 +26,45 @@ want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. -  Developers that use our General Public Licenses protect your rights-with two steps: (1) assert copyright on the software, and (2) offer-you this License which gives you legal permission to copy, distribute-and/or modify the software.+  To protect your rights, we need to prevent others from denying you+these rights or asking you to surrender the rights.  Therefore, you have+certain responsibilities if you distribute copies of the software, or if+you modify it: responsibilities to respect the freedom of others. -  A secondary benefit of defending all users' freedom is that-improvements made in alternate versions of the program, if they-receive widespread use, become available for other developers to-incorporate.  Many developers of free software are heartened and-encouraged by the resulting cooperation.  However, in the case of-software used on network servers, this result may fail to come about.-The GNU General Public License permits making a modified version and-letting the public access it on a server without ever releasing its-source code to the public.+  For example, if you distribute copies of such a program, whether+gratis or for a fee, you must pass on to the recipients the same+freedoms that you received.  You must make sure that they, too, receive+or can get the source code.  And you must show them these terms so they+know their rights. -  The GNU Affero General Public License is designed specifically to-ensure that, in such cases, the modified source code becomes available-to the community.  It requires the operator of a network server to-provide the source code of the modified version running there to the-users of that server.  Therefore, public use of a modified version, on-a publicly accessible server, gives the public access to the source-code of the modified version.+  Developers that use the GNU GPL protect your rights with two steps:+(1) assert copyright on the software, and (2) offer you this License+giving you legal permission to copy, distribute and/or modify it. -  An older license, called the Affero General Public License and-published by Affero, was designed to accomplish similar goals.  This is-a different license, not a version of the Affero GPL, but Affero has-released a new version of the Affero GPL which permits relicensing under-this license.+  For the developers' and authors' protection, the GPL clearly explains+that there is no warranty for this free software.  For both users' and+authors' sake, the GPL requires that modified versions be marked as+changed, so that their problems will not be attributed erroneously to+authors of previous versions. +  Some devices are designed to deny users access to install or run+modified versions of the software inside them, although the manufacturer+can do so.  This is fundamentally incompatible with the aim of+protecting users' freedom to change the software.  The systematic+pattern of such abuse occurs in the area of products for individuals to+use, which is precisely where it is most unacceptable.  Therefore, we+have designed this version of the GPL to prohibit the practice for those+products.  If such problems arise substantially in other domains, we+stand ready to extend this provision to those domains in future versions+of the GPL, as needed to protect the freedom of users.++  Finally, every program is threatened constantly by software patents.+States should not allow patents to restrict development and use of+software on general-purpose computers, but in those that do, we wish to+avoid the special danger that patents applied to a free program could+make it effectively proprietary.  To prevent this, the GPL assures that+patents cannot be used to render the program non-free.+   The precise terms and conditions for copying, distribution and modification follow. @@ -60,7 +72,7 @@    0. Definitions. -  "This License" refers to version 3 of the GNU Affero General Public License.+  "This License" refers to version 3 of the GNU General Public License.    "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.@@ -537,45 +549,35 @@ the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. -  13. Remote Network Interaction; Use with the GNU General Public License.--  Notwithstanding any other provision of this License, if you modify the-Program, your modified version must prominently offer all users-interacting with it remotely through a computer network (if your version-supports such interaction) an opportunity to receive the Corresponding-Source of your version by providing access to the Corresponding Source-from a network server at no charge, through some standard or customary-means of facilitating copying of software.  This Corresponding Source-shall include the Corresponding Source for any work covered by version 3-of the GNU General Public License that is incorporated pursuant to the-following paragraph.+  13. Use with the GNU Affero General Public License.    Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed-under version 3 of the GNU General Public License into a single+under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work.  The terms of this License will continue to apply to the part which is the covered work,-but the work with which it is combined will remain governed by version-3 of the GNU General Public License.+but the special requirements of the GNU Affero General Public License,+section 13, concerning interaction through a network will apply to the+combination as such.    14. Revised Versions of this License.    The Free Software Foundation may publish revised and/or new versions of-the GNU Affero General Public License from time to time.  Such new versions-will be similar in spirit to the present version, but may differ in detail to+the GNU General Public License from time to time.  Such new versions will+be similar in spirit to the present version, but may differ in detail to address new problems or concerns.    Each version is given a distinguishing version number.  If the-Program specifies that a certain numbered version of the GNU Affero General+Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation.  If the Program does not specify a version number of the-GNU Affero General Public License, you may choose any version ever published+GNU General Public License, you may choose any version ever published by the Free Software Foundation.    If the Program specifies that a proxy can decide which future-versions of the GNU Affero General Public License can be used, that proxy's+versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. @@ -633,29 +635,41 @@     Copyright (C) <year>  <name of author>      This program is free software: you can redistribute it and/or modify-    it under the terms of the GNU Affero General Public License as published by+    it under the terms of the GNU General Public License as published by     the Free Software Foundation, either version 3 of the License, or     (at your option) any later version.      This program is distributed in the hope that it will be useful,     but WITHOUT ANY WARRANTY; without even the implied warranty of     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-    GNU Affero General Public License for more details.+    GNU General Public License for more details. -    You should have received a copy of the GNU Affero General Public License+    You should have received a copy of the GNU General Public License     along with this program.  If not, see <http://www.gnu.org/licenses/>.  Also add information on how to contact you by electronic and paper mail. -  If your software can interact with users remotely through a computer-network, you should also make sure that it provides a way for users to-get its source.  For example, if your program is a web application, its-interface could display a "Source" link that leads users to an archive-of the code.  There are many ways you could offer source, and different-solutions will be better for different programs; see section 13 for the-specific requirements.+  If the program does terminal interaction, make it output a short+notice like this when it starts in an interactive mode: +    <program>  Copyright (C) <year>  <name of author>+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.+    This is free software, and you are welcome to redistribute it+    under certain conditions; type `show c' for details.++The hypothetical commands `show w' and `show c' should show the appropriate+parts of the General Public License.  Of course, your program's commands+might be different; for a GUI interface, you would use an "about box".+   You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary.-For more information on this, and how to apply and follow the GNU AGPL, see+For more information on this, and how to apply and follow the GNU GPL, see <http://www.gnu.org/licenses/>.++  The GNU General Public License does not permit incorporating your program+into proprietary programs.  If your program is a subroutine library, you+may consider it more useful to permit linking proprietary applications with+the library.  If this is what you want to do, use the GNU Lesser General+Public License instead of this License.  But first, please read+<http://www.gnu.org/philosophy/why-not-lgpl.html>.+
github-tools.cabal view
@@ -1,64 +1,266 @@-name:                github-tools-version:             0.1.1-synopsis:            Various Github helper utilities.-homepage:            https://toktok.github.io/-license:             AGPL-3-license-file:        LICENSE-author:              iphydf-maintainer:          iphydf@users.noreply.github.com-category:            Development-build-type:          Simple-cabal-version:       >=1.10+name:          github-tools+version:       0.1.2+synopsis:      Various Github helper utilities.+homepage:      https://toktok.github.io/+license:       GPL-3+license-file:  LICENSE+author:        iphydf+maintainer:    iphydf@users.noreply.github.com+category:      Development+build-type:    Simple+cabal-version: >=1.10 description:   - Pull Request status tool.   - Change log generator.  source-repository head-  type:             git-  location:         https://github.com/TokTok/github-tools.git+  type:     git+  location: https://github.com/TokTok/hs-github-tools.git -executable pull-status-  main-is:             pull-status.hs-  other-modules:-      PullRequestInfo-      Requests-      Review-  ghc-options:-      -Wall+library+  exposed-modules:+    GitHub.Tools.AutoMerge+    GitHub.Tools.Changelogs+    GitHub.Tools.NetworkGraph+    GitHub.Tools.PullRequestInfo+    GitHub.Tools.PullStatus+    GitHub.Tools.Requests+    GitHub.Types+    GitHub.Types.Base+    GitHub.Types.Base.Author+    GitHub.Types.Base.Branch+    GitHub.Types.Base.Change+    GitHub.Types.Base.Changes+    GitHub.Types.Base.CheckApp+    GitHub.Types.Base.CheckCommit+    GitHub.Types.Base.CheckCommitRef+    GitHub.Types.Base.CheckCommitRepo+    GitHub.Types.Base.CheckOutput+    GitHub.Types.Base.CheckPullRequest+    GitHub.Types.Base.CheckRun+    GitHub.Types.Base.CheckSuite+    GitHub.Types.Base.Commit+    GitHub.Types.Base.CommitComment+    GitHub.Types.Base.CommitDetails+    GitHub.Types.Base.CommitRef+    GitHub.Types.Base.CommitRefHtml+    GitHub.Types.Base.DateTime+    GitHub.Types.Base.Deployment+    GitHub.Types.Base.DeploymentPayload+    GitHub.Types.Base.DeploymentStatus+    GitHub.Types.Base.Hook+    GitHub.Types.Base.HookConfig+    GitHub.Types.Base.Installation+    GitHub.Types.Base.Invitation+    GitHub.Types.Base.Issue+    GitHub.Types.Base.IssueComment+    GitHub.Types.Base.Label+    GitHub.Types.Base.License+    GitHub.Types.Base.Link+    GitHub.Types.Base.Membership+    GitHub.Types.Base.Milestone+    GitHub.Types.Base.Organization+    GitHub.Types.Base.PageBuild+    GitHub.Types.Base.PageBuildError+    GitHub.Types.Base.Permissions+    GitHub.Types.Base.PullRequest+    GitHub.Types.Base.PullRequestLinks+    GitHub.Types.Base.PullRequestRef+    GitHub.Types.Base.PushCommit+    GitHub.Types.Base.Reactions+    GitHub.Types.Base.Release+    GitHub.Types.Base.RepoOwner+    GitHub.Types.Base.Repository+    GitHub.Types.Base.Review+    GitHub.Types.Base.ReviewComment+    GitHub.Types.Base.ReviewCommentLinks+    GitHub.Types.Base.ReviewLinks+    GitHub.Types.Base.SimplePullRequest+    GitHub.Types.Base.SimpleRepository+    GitHub.Types.Base.StatusCommit+    GitHub.Types.Base.Team+    GitHub.Types.Base.User+    GitHub.Types.Base.UserRef+    GitHub.Types.Base.UserStamp+    GitHub.Types.Base.Verification+    GitHub.Types.Base.Workflow+    GitHub.Types.Base.WorkflowJob+    GitHub.Types.Base.WorkflowRun+    GitHub.Types.Base.WorkflowStep+    GitHub.Types.Event+    GitHub.Types.Events+    GitHub.Types.Events.CheckRunEvent+    GitHub.Types.Events.CheckSuiteEvent+    GitHub.Types.Events.CommitCommentEvent+    GitHub.Types.Events.CreateEvent+    GitHub.Types.Events.DeleteEvent+    GitHub.Types.Events.DeploymentEvent+    GitHub.Types.Events.DeploymentStatusEvent+    GitHub.Types.Events.ForkEvent+    GitHub.Types.Events.GollumEvent+    GitHub.Types.Events.IssueCommentEvent+    GitHub.Types.Events.IssuesEvent+    GitHub.Types.Events.LabelEvent+    GitHub.Types.Events.MemberEvent+    GitHub.Types.Events.MembershipEvent+    GitHub.Types.Events.MilestoneEvent+    GitHub.Types.Events.OrganizationEvent+    GitHub.Types.Events.PageBuildEvent+    GitHub.Types.Events.PingEvent+    GitHub.Types.Events.PullRequestEvent+    GitHub.Types.Events.PullRequestReviewCommentEvent+    GitHub.Types.Events.PullRequestReviewEvent+    GitHub.Types.Events.PushEvent+    GitHub.Types.Events.ReleaseEvent+    GitHub.Types.Events.RepositoryEvent+    GitHub.Types.Events.StarEvent+    GitHub.Types.Events.StatusEvent+    GitHub.Types.Events.WatchEvent+    GitHub.Types.Events.WorkflowJobEvent+    GitHub.Types.Events.WorkflowRunEvent+    GitHub.Types.PayloadParser+    GitHub.WebHook.Handler++  ghc-options:      -Wall+  hs-source-dirs:   src+  default-language: Haskell2010   build-depends:-      base >= 4 && < 5+      aeson                 >=2+    , base                  >=4      && <5     , bytestring+    , containers+    , cryptohash+    , directory     , exceptions-    , github            >= 0.15.0-    , groom+    , github                >=0.25   && <0.29     , html-    , http-client       >= 0.4.30+    , http-client           >=0.4.30     , http-client-tls     , monad-parallel+    , process+    , QuickCheck+    , quickcheck-text+    , split     , tabular-    , tagsoup     , text     , time+    , unix+    , unordered-containers+    , uuid     , vector-  hs-source-dirs:      src-  default-language:    Haskell2010 -executable changelog-  main-is:             changelog.hs+executable hub-automerge+  main-is:          hub-automerge.hs+  ghc-options:      -Wall+  hs-source-dirs:   tools+  default-language: Haskell2010+  build-depends:+      base+    , bytestring+    , github+    , github-tools+    , text++executable hub-pulls+  main-is:          hub-pulls.hs+  ghc-options:      -Wall+  hs-source-dirs:   tools+  default-language: Haskell2010+  build-depends:+      base+    , bytestring+    , github+    , github-tools+    , text++executable hub-changelog+  main-is:          hub-changelog.hs+  ghc-options:      -Wall+  hs-source-dirs:   tools+  default-language: Haskell2010+  build-depends:+      base+    , bytestring+    , github+    , github-tools+    , text++executable hub-graph+  main-is:          hub-graph.hs+  ghc-options:      -Wall+  hs-source-dirs:   tools+  default-language: Haskell2010+  build-depends:+      base+    , bytestring+    , github+    , github-tools++executable hub-roadmap+  main-is:          hub-roadmap.hs+  ghc-options:      -Wall+  hs-source-dirs:   tools+  default-language: Haskell2010+  build-depends:+      base+    , bytestring+    , github+    , github-tools+    , text++executable webservice+  main-is:          webservice.hs+  ghc-options:      -Wall+  hs-source-dirs:   web+  default-language: Haskell2010   other-modules:-      Requests-  ghc-options:-      -Wall+    TokTok.Handlers+    TokTok.Hello+    TokTok.Webhooks+   build-depends:-      base >= 4 && < 5+      aeson-pretty+    , base     , bytestring+    , case-insensitive     , containers-    , exceptions-    , github            >= 0.15.0-    , groom-    , http-client-    , http-client-tls+    , Diff+    , expiring-cache-map+    , github+    , github-tools+    , http-media+    , http-types+    , pretty+    , servant               >=0.5+    , servant-server        >=0.5+    , suspend     , text-    , vector-  hs-source-dirs:      src-  default-language:    Haskell2010+    , time+    , timers+    , unordered-containers+    , uuid+    , wai+    , wai-cors+    , wai-extra+    , warp++test-suite testsuite+  type:               exitcode-stdio-1.0+  default-language:   Haskell2010+  hs-source-dirs:     test+  main-is:            testsuite.hs+  other-modules:+    GitHub.Types.BaseSpec+    GitHub.Types.EventsSpec++  ghc-options:        -Wall -Wno-unused-imports -threaded++  -- Support parallel test execution (since each test can take quite long,+  -- because the GitHub data structures are rather large).+  build-tool-depends: hspec-discover:hspec-discover+  build-depends:+      aeson         >=2+    , base          <5+    , github-tools+    , hspec+    , QuickCheck
+ src/GitHub/Tools/AutoMerge.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE NamedFieldPuns    #-}+{-# LANGUAGE OverloadedStrings #-}+module GitHub.Tools.AutoMerge+    ( autoMergePullRequest+    , autoMergeAll+    , trustedAuthors+    ) where++import qualified Data.ByteString.Char8        as BS8+import           Data.Text                    (Text)+import qualified Data.Text                    as Text+import qualified Data.Vector                  as V+import qualified GitHub+import           Network.HTTP.Client          (newManager)+import           Network.HTTP.Client.TLS      (tlsManagerSettings)+import           System.Directory             (setCurrentDirectory)+import           System.Process               (callProcess)++import           GitHub.Tools.PullRequestInfo (PullRequestInfo (..))+import           GitHub.Tools.PullStatus      (getPrInfos, getPullInfos,+                                               makePullRequestInfo)+import           GitHub.Tools.Requests        (request)+++trustedAuthors :: [Text]+trustedAuthors =+    [ "JFreegman"+    , "TokTok"+    , "iphydf"+    , "nurupo"+    , "robinlinden"+    , "sudden6"+    , "zugz"+    ]+++workDir :: FilePath+workDir = "/tmp/automerge"+++autoMerge+    :: String+    -> GitHub.Name GitHub.Owner+    -> PullRequestInfo+    -> IO ()+autoMerge _ _ PullRequestInfo{prOrigin = Nothing} = return ()+autoMerge token ownerName PullRequestInfo{prRepoName, prUser, prBranch, prOrigin = Just prOrigin} = do+    let clonePath = workDir <> "/" <> Text.unpack prRepoName+    callProcess "rm" ["-rf", clonePath]+    callProcess "git"+        [ "clone", "--depth=6"  -- 6 so we can merge up to 5 commits on top of the master HEAD commit+        , "--branch=" <> Text.unpack prBranch+        , "https://github.com/" <> Text.unpack prUser <> "/" <> Text.unpack prOrigin+        , clonePath+        ]+    setCurrentDirectory clonePath++    callProcess "git"+        [ "remote", "add", "upstream"+        , "https://" <> token <> "@github.com/" <> Text.unpack (GitHub.untagName ownerName) <> "/" <> Text.unpack prRepoName+        ]+    callProcess "git"+        [ "push", "upstream", Text.unpack prBranch <> ":master" ]++    -- Go back to a directory that will definitely exist even when next time+    -- we "rm -rf" the git repo cloned above.+    setCurrentDirectory workDir+++mergeable :: PullRequestInfo -> Bool+mergeable PullRequestInfo{prState, prTrustworthy, prUser} =+    prState == "clean" && (prTrustworthy || prUser `elem` trustedAuthors)+++autoMergePullRequest+  :: String+  -> GitHub.Name GitHub.Owner+  -> GitHub.Name GitHub.Repo+  -> IO ()+autoMergePullRequest token ownerName repoName = do+    let auth = Just . GitHub.OAuth . BS8.pack $ token+    mgr <- newManager tlsManagerSettings+    pulls <- (V.toList <$>+        request auth mgr (GitHub.pullRequestsForR ownerName repoName GitHub.stateOpen GitHub.FetchAll))+        >>= fmap (map $ makePullRequestInfo repoName) . getPrInfos auth mgr ownerName repoName+    putStrLn $ "found " <> show (length pulls) <> " pulls"++    let mergeablePulls = filter mergeable pulls+    putStrLn $ "selected " <> show (length mergeablePulls) <> " mergeable pulls:"+    mapM_ print mergeablePulls++    mapM_ (autoMerge token ownerName) mergeablePulls+++autoMergeAll+  :: GitHub.Name GitHub.Organization+  -> GitHub.Name GitHub.Owner+  -> String+  -> IO ()+autoMergeAll orgName ownerName token = do+    let auth = Just . GitHub.OAuth . BS8.pack $ token+    pulls <- filter mergeable . concat <$> getPullInfos orgName ownerName auth+    mapM_ (autoMerge token ownerName) pulls
+ src/GitHub/Tools/Changelogs.hs view
@@ -0,0 +1,264 @@+{-# LANGUAGE LambdaCase        #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Tools.Changelogs+  ( fetchChangeLog+  , formatChangeLog+  , ChangeLog+  ) where++import           Control.Arrow           (first, second, (&&&))+import qualified Control.Monad.Parallel  as P+import           Data.List               (foldl')+import qualified Data.List               as List+import qualified Data.List.Split         as List+import qualified Data.Map                as Map+import qualified Data.Maybe              as Maybe+import           Data.Text               (Text)+import qualified Data.Text               as Text+import qualified Data.Vector             as V+import           Debug.Trace             (traceIO)+import qualified GitHub+import           Network.HTTP.Client     (newManager)+import           Network.HTTP.Client.TLS (tlsManagerSettings)+import           Text.Read               (readMaybe)+-- import           Text.Groom              (groom)++import           GitHub.Tools.Requests+++newtype ChangeLog = ChangeLog { unChangeLog :: [(Text, [Text], [Text])] }+++data VersionComponent+  = Number Int+  | Wildcard+  deriving (Ord, Eq)+++instance Read VersionComponent where+  readsPrec _ ('x':s) = [(Wildcard, s)]+  readsPrec p input   = map (first Number) . readsPrec p $ input+++data Version+  = VersionNumber [VersionComponent]+  | VersionString Text+  deriving (Ord, Eq)+++formatChangeLog :: Bool -> ChangeLog -> Text+formatChangeLog wantRoadmap =+  (<> "\n") . foldl' (<>) "" . map formatMilestone . unChangeLog+  where+    prsWord    = if wantRoadmap then "PRs to review" else "Merged PRs"+    issuesWord = if wantRoadmap then "Planned tasks" else "Closed issues"++    formatMilestone (milestone, issues, pulls) =+      "\n\n## " <> milestone+      <> mergedPrs pulls+      <> closedIssues issues++    mergedPrs [] = ""+    mergedPrs pulls =+      foldl' (<>) ("\n\n### " <> prsWord <> ":\n") . itemise $ pulls++    closedIssues [] = ""+    closedIssues issues =+      foldl' (<>) ("\n\n### " <> issuesWord <> ":\n") . itemise $ issues++    itemise = map ("\n- " <>)+++data ChangeLogItemKind+  = Issue+  | PullRequest+  deriving Show+++data ChangeLogItem = ChangeLogItem+  { clMilestone :: Text+  , clTitle     :: Text+  , clNumber    :: Int+  }+++groupByMilestone+  :: (ChangeLogItem -> ([a], [a]) -> ([a], [a]))+  -> [ChangeLogItem]+  -> Map.Map Text ([a], [a])+  -> Map.Map Text ([a], [a])+groupByMilestone add = flip $ foldr (\item group ->+    Map.insert (clMilestone item) (+        case Map.lookup (clMilestone item) group of+          Just old -> add item old+          Nothing  -> add item ([], [])+      ) group)+++formatChangeLogItem+  :: ChangeLogItemKind+  -> GitHub.Name GitHub.Owner+  -> GitHub.Name GitHub.Repo+  -> ChangeLogItem+  -> Text+formatChangeLogItem kind ownerName repoName item =+  "[#" <> number <> "](https://github.com/" <> GitHub.untagName ownerName <>+  "/" <> GitHub.untagName repoName <> kindPart <> number <> ") " <>+  clTitle item+  where+    number = Text.pack . show . clNumber $ item+    kindPart =+      case kind of+        Issue       -> "/issues/"+        PullRequest -> "/pull/"+++makeChangeLog+  :: Bool+  -> GitHub.Name GitHub.Owner+  -> GitHub.Name GitHub.Repo+  -> [GitHub.SimplePullRequest]+  -> [GitHub.Issue]+  -> ChangeLog+makeChangeLog wantRoadmap ownerName repoName pulls issues =+  ChangeLog+  . reverseIfChangelog+  . sortChangelog+  . Map.foldlWithKey (\changes milestone (msIssues, msPulls) ->+      if milestone == "meta"+        then changes+        else+          ( milestone+          , map (formatChangeLogItem Issue       ownerName repoName) msIssues+          , map (formatChangeLogItem PullRequest ownerName repoName) msPulls+          ) : changes+    ) []+  . groupByMilestone (first  . (:)) changeLogIssues+  . groupByMilestone (second . (:)) changeLogPrs+  $ Map.empty+  where+    reverseIfChangelog l =+      if wantRoadmap+        then l+        else reverse l++    sortChangelog :: [(Text, [Text], [Text])] -> [(Text, [Text], [Text])]+    sortChangelog = List.sortOn $ \(v, _, _) -> parseVersion v++    parseVersion :: Text -> Version+    parseVersion v =+        case Text.unpack v of+            -- Milestones starting with "v" must be versions.+            'v':version ->+                case map readMaybe $ List.splitOn "." version of+                  [Just major, Just minor, Just rev] -> VersionNumber [major, minor, rev]+                  _ -> error $ "invalid version: " <> version+            _ -> VersionString v++    (mergedPrs, openPrs) = List.partition (\case+        GitHub.SimplePullRequest+          { GitHub.simplePullRequestMergedAt = Just _ } -> True+        _                                               -> False+      ) pulls++    selectedPrs =+      if wantRoadmap+        then openPrs+        else mergedPrs++    selectedItems = filter (\case+        GitHub.Issue+          { GitHub.issueMilestone = Just GitHub.Milestone+            { GitHub.milestoneState = state }+          } ->+            if wantRoadmap+              then state == "open"+              else state == "closed"+        _ -> False+      ) issues++    (backlogPrs, backlogIssues) =+      if wantRoadmap+        then+            -- Split into PRs and non-PR issues.+            List.partition (\case+              GitHub.Issue { GitHub.issuePullRequest = Just _ } -> True+              _                                                 -> False+            )+            -- Filter by issues that don't have a milestone.+          . filter (\case+              GitHub.Issue { GitHub.issueMilestone = Nothing } -> True+              _                                                -> False+            )+          $ issues+        else+          ([], [])++    addToBacklog =+      map $ \issue -> ChangeLogItem+        { clMilestone = "Backlog"+        , clTitle     = GitHub.issueTitle issue+        , clNumber    = GitHub.unIssueNumber $ GitHub.issueNumber issue+        }++    backlogPrItems    = addToBacklog backlogPrs+    backlogIssueItems = addToBacklog backlogIssues++    milestoneByIssueId =+      Map.fromList+      . map (GitHub.issueNumber &&& GitHub.milestoneTitle . Maybe.fromJust . GitHub.issueMilestone)+      $ selectedItems++    changeLogIssues :: [ChangeLogItem]+    changeLogIssues = backlogIssueItems ++ Maybe.mapMaybe (\case+        -- filter out PRs+        GitHub.Issue { GitHub.issuePullRequest = Just _ } -> Nothing+        issue -> Just ChangeLogItem+          { clMilestone = GitHub.milestoneTitle . Maybe.fromJust . GitHub.issueMilestone $ issue+          , clTitle     = GitHub.issueTitle issue+          , clNumber    = GitHub.unIssueNumber $ GitHub.issueNumber issue+          }+      ) selectedItems++    changeLogPrs :: [ChangeLogItem]+    changeLogPrs = backlogPrItems ++ Maybe.mapMaybe (\issue -> do+        milestone <- flip Map.lookup milestoneByIssueId . GitHub.simplePullRequestNumber $ issue+        return ChangeLogItem+          { clMilestone = milestone+          , clTitle     = GitHub.simplePullRequestTitle issue+          , clNumber    = GitHub.unIssueNumber $ GitHub.simplePullRequestNumber issue+          }+      ) selectedPrs+++fetchChangeLog+  :: Bool+  -> GitHub.Name GitHub.Owner+  -> GitHub.Name GitHub.Repo+  -> Maybe GitHub.Auth+  -> IO ChangeLog+fetchChangeLog wantRoadmap ownerName repoName auth = do+  -- Initialise HTTP manager so we can benefit from keep-alive connections.+  mgr <- newManager tlsManagerSettings++  let fetchPulls state = do+          traceIO $ "Fetching pull requests"+          l <- V.toList <$> request auth mgr (GitHub.pullRequestsForR ownerName repoName state GitHub.FetchAll)+          traceIO $ "Got " <> show (length l) <> " pull requests"+          return l+  let fetchIssues state = do+          traceIO $ "Fetching issues"+          l <- V.toList <$> request auth mgr (GitHub.issuesForRepoR   ownerName repoName state GitHub.FetchAll)+          traceIO $ "Got " <> show (length l) <> " issues"+          return l++  -- issues >>= putStrLn . groom++  (pulls, issues) <- uncurry (P.bindM2 (\p i -> return (p, i))) $+          if wantRoadmap+             then (fetchPulls GitHub.stateOpen  , fetchIssues GitHub.stateOpen  )+             else (fetchPulls GitHub.stateClosed, fetchIssues GitHub.stateClosed)++  traceIO "Formatting changelog/roadmap"+  return $ makeChangeLog wantRoadmap ownerName repoName pulls issues
+ src/GitHub/Tools/NetworkGraph.hs view
@@ -0,0 +1,207 @@+{-# LANGUAGE LambdaCase        #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StrictData        #-}+{-# LANGUAGE ViewPatterns      #-}+module GitHub.Tools.NetworkGraph+  ( getNetworkGraph+  ) where++import           Control.Arrow                ((&&&))+import           Control.Monad                (unless, void)+import           Data.Char                    (ord)+import qualified Data.List                    as List+import qualified Data.List.Split              as List+--import           Data.Text                    (Text)+import qualified Data.Text                    as Text+import qualified Data.Vector                  as V+import qualified GitHub                       as GH+import qualified GitHub.Data.Name             as GH+import           Network.HTTP.Client          (Manager, newManager)+import           Network.HTTP.Client.TLS      (tlsManagerSettings)+import           System.Directory             (doesDirectoryExist,+                                               setCurrentDirectory)+import           System.IO                    (hPutStrLn, stderr)+import           System.Process               (callProcess, readProcess)+import qualified Text.ParserCombinators.ReadP as R++import           GitHub.Tools.Requests+++type RepoRef = (GH.Name GH.Owner, GH.Name GH.Repo)+++data Ref = Ref String String [String] [String]+    deriving Show++instance Read Ref where+    readsPrec _ = R.readP_to_S $ Ref+        <$> R.count 25 R.get+        <*> (R.char ' ' >> readRef)+        <*> R.many1 (R.char ' ' >> readRef)+        <*> readNames+      where+        readRef = R.count 40 . R.choice . map R.char $ ['0'..'9'] ++ ['a'..'f']+        readNames = do+            void $ R.string " ("+            res <- R.sepBy (R.munch (not . (`elem` [',',')']))) (R.string ", ")+            void $ R.char ')'+            return res+++toDot :: Ref -> [String]+toDot (Ref _ _ _ []) = []+toDot (Ref date (take 6 -> ref) (map (take 6) -> parents) names@(mainName:_)) =+    "  \"" <> ref <> "\" [ " <> List.intercalate " " attrs <> " ]"+    : edges+  where+    edges = map (\parent -> "  \"" <> ref <> "\" -> \"" <> parent <> "\"") parents+    truncateName name+      | length name > 25 = take 22 name <> "..."+      | otherwise = name++    attrs =+        [ "label = \"" <> List.intercalate "\\n" (take 10 date : map truncateName names) <> "\""+        , "tooltip = \"" <> List.intercalate "\\n" names <> "\""+        , "fillcolor = \"" <> nameColor <> "\""+        ]++    palette =+        [ "#ccff00"+        , "#ccffff"+        , "#ffff66"+        , "#cccc00"+        , "#ccccff"+        , "#ffccff"+        , "#ffcccc"+        , "#ffcc33"+        , "#cc9933"+        , "#cc9999"+        , "#cc99ff"+        , "#ff99ff"+        , "#ff9933"+        , "#cc6633"+        , "#66cc99"+        , "#99cc33"+        , "#009900"+        ]++    nameColor =+        case fst $ List.break (`elem` [':','/']) mainName of+          "HEAD -> master" -> "red"+          "tag" -> "#cccccc"+          author -> palette !! ((sum . map ord $ author) `mod` (length palette))+++minDate :: String+minDate = "2022-01"+++urlBase :: String+urlBase = "https://username:password@github.com/"+++denyList :: [GH.Name GH.Owner]+denyList =+    [ "4a256b6b3e7t3e8b7t9q7t"+    , "activistWannabe2"+    , "cha63506"+    , "chai3819"+    , "CNXTEoEorg"+    , "DannaScully"+    , "din982"+    , "fireeyeusa"+    , "grubern"+    , "haiiev"+    , "innnzzz6"+    , "jamiepg1"+    , "josephyzhou"+    , "jrtorres42"+    , "kigu"+    , "lucasborer1"+    , "lukw00"+    , "makianditro1"+    , "mehulsbhatt"+    , "mk21"+    , "nfkd"+    , "noikiy"+    , "ProgrammerAndHacker"+    , "receptpr9001"+    , "shaunstanislaus"+    , "sometwo"+    , "SunelContus"+    , "treejames"+    , "xeon2007"+    , "xuecai"+    ]+++-- | Monadic version of @unless@, taking the condition in the monad+unlessM :: Monad m => m Bool -> m () -> m ()+unlessM condM acc = do+    cond <- condM+    unless cond acc+++getNetworkGraph+    :: Maybe GH.Auth+    -> [RepoRef]+    -> IO String+getNetworkGraph _ [] = return []+getNetworkGraph auth repos@(rootRepo:seedRepos) = do+    -- Initialise HTTP manager so we can benefit from keep-alive connections.+    mgr <- newManager tlsManagerSettings++    unlessM (doesDirectoryExist clonePath) $ do+        hPutStrLn stderr "Cloning initial repo"+        clone rootRepo+        setCurrentDirectory clonePath++        hPutStrLn stderr $ "Adding remotes for " <> show (length seedRepos) <> " seed repos"+        mapM_ addRemote seedRepos++        hPutStrLn stderr $ "Querying GitHub for forks..."+        forks <- V.filter (not . (`elem` denyList) . fst) . V.concat <$> mapM (forksFor mgr) repos++        hPutStrLn stderr $ "Adding remotes for " <> show (V.length forks) <> " forks"+        V.mapM_ addRemote forks++        hPutStrLn stderr "Fetching all remotes"+        fetchAll++    setCurrentDirectory clonePath+    dotLines <- concatMap toDot <$> gitLog++    return . unlines . concat $+        [ [ "strict digraph \"" <> repoPath rootRepo <> "\" {"+          , "  graph [splines=ortho, rankdir=LR]"+          , "  node [shape=box width=2.5 margin=\"0,0.02\" style=filled]"+          , "  edge [dir=back]"+          ]+        , dotLines+        , ["}"]+        ]++  where+    repoPath (GH.N (Text.unpack -> owner), GH.N (Text.unpack -> repo)) =+        owner <> "/" <> repo++    clonePath = "/tmp/hub-graph/" <> (Text.unpack . GH.untagName . snd $ rootRepo)++    clone repo =+        callProcess "git" ["clone", urlBase <> repoPath repo, clonePath]++    addRemote repo@(GH.N (Text.unpack -> owner), _) =+        callProcess "git" ["remote", "add", owner, urlBase <> repoPath repo]++    fetchAll =+        callProcess "git" ["fetch", "--all", "--prune", "--jobs=10"]++    gitLog =+        map read+        . filter (>= minDate)+        . List.splitOn "\n"+        <$> readProcess "git" ["log", "--all", "--format=%cI %H %P%d", "--topo-order", "--simplify-by-decoration"] ""++    forksFor :: Manager -> RepoRef -> IO (V.Vector RepoRef)+    forksFor mgr (owner, repo) =+        V.map (GH.simpleOwnerLogin . GH.repoOwner &&& GH.repoName) <$> request auth mgr (GH.forksForR owner repo GH.FetchAll)
+ src/GitHub/Tools/PullRequestInfo.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE DeriveGeneric     #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Tools.PullRequestInfo where++import           Control.Monad         (join)+import           Data.Aeson            (FromJSON, ToJSON)+import qualified Data.List             as List+import           Data.Text             (Text)+import qualified Data.Text             as Text+import           Data.Time.Clock       (UTCTime, diffUTCTime)+import           GHC.Generics          (Generic)+import           Text.Html             (prettyHtml, toHtml)+import           Text.Tabular          (Header (..), Properties (..),+                                        Table (..))+import qualified Text.Tabular.AsciiArt as AsciiArt+import qualified Text.Tabular.Html     as Html+++data PullRequestInfo = PullRequestInfo+  { prRepoName    :: Text+    -- ^ The repository for which the pull request is.+  , prNumber      :: Int+    -- ^ The assigned pull request issue number.+  , prUser        :: Text+    -- ^ The user who proposed this PR.+  , prBranch      :: Text+    -- ^ The branch name from which the pull request came.+  , prCreated     :: UTCTime+    -- ^ Creation time of pull request. I.e. when it was proposed.+  , prTitle       :: Text+    -- ^ Title of pull request.+  , prReviewers   :: [Text]+    -- ^ The list of pull request reviewers (assignees).+  , prState       :: Text+    -- ^ The mergeability state of the PR (clean = it's mergeable now).+  , prOrigin      :: Maybe Text+    -- ^ The origin repository as user/reponame string.+  , prTrustworthy :: Bool+    -- ^ Whether the author is an org member (True) or an outside contributor (False).+  }+  deriving (Ord, Eq, Generic, Show)++instance ToJSON PullRequestInfo+instance FromJSON PullRequestInfo+++formatPR :: Bool -> UTCTime -> [[PullRequestInfo]] -> Text+formatPR False now = Text.pack . AsciiArt.render Text.unpack Text.unpack Text.unpack . prToTable now+formatPR True  now = Text.pack . prettyHtml . Html.render textHtml textHtml textHtml . prToTable now+  where textHtml = toHtml . Text.unpack+++prToTable :: UTCTime -> [[PullRequestInfo]] -> Table Text Text Text+prToTable now prss = Table rowNames columnNames rows+  where+    rowNames = Group SingleLine+      . map (Group NoLine . map (Header . getRowName))+      . filter (not . null)+      $ prss++    getRowName pr =+      let repo num = prRepoName pr <> " " <> num in+      repo . Text.pack . show . prNumber $ pr++    columnNames =  Group SingleLine+      [ Header "branch"+      , Header "age"+      , Header "title"+      , Header "state"+      , Header "review_status"+      ]++    rows = map (flip map+      [ \pr -> prUser pr <> "/" <> prBranch pr+      , Text.pack . (++ "d") . show . diffInDays now . prCreated+      , prTitle+      , prState+      , Text.pack . List.intercalate "," . map Text.unpack . prReviewers+      ] . flip ($)) $ join prss+++diffInDays :: UTCTime -> UTCTime -> Int+diffInDays a b = round $ diffUTCTime a b / (60 * 60 * 24)
+ src/GitHub/Tools/PullStatus.hs view
@@ -0,0 +1,137 @@+{-# LANGUAGE OverloadedStrings #-}+module GitHub.Tools.PullStatus+  ( getPrInfos+  , getPullStatus+  , getPullInfos+  , makePullRequestInfo+  , showPullInfos+  ) where++import qualified Control.Monad.Parallel       as Parallel+import qualified Data.List                    as List+import           Data.Text                    (Text)+import qualified Data.Text                    as Text+import           Data.Time.Clock              (getCurrentTime)+import qualified Data.Vector                  as V+import qualified GitHub+import           Network.HTTP.Client          (Manager, newManager)+import           Network.HTTP.Client.TLS      (tlsManagerSettings)++import           GitHub.Tools.PullRequestInfo (PullRequestInfo (..))+import qualified GitHub.Tools.PullRequestInfo as PullRequestInfo+import           GitHub.Tools.Requests+++getFullPr+  :: Maybe GitHub.Auth+  -> Manager+  -> GitHub.Name GitHub.Owner+  -> GitHub.Name GitHub.Repo+  -> GitHub.SimplePullRequest+  -> IO GitHub.PullRequest+getFullPr auth mgr owner repo =+  request auth mgr+    . GitHub.pullRequestR owner repo+    . GitHub.simplePullRequestNumber+++getPrInfo+  :: Maybe GitHub.Auth+  -> Manager+  -> GitHub.Name GitHub.Owner+  -> GitHub.Name GitHub.Repo+  -> GitHub.SimplePullRequest+  -> IO ([Text], GitHub.PullRequest)+getPrInfo auth mgr ownerName repoName pr = do+  let assignees = V.toList $ GitHub.simplePullRequestAssignees pr+  let reviewers = map (GitHub.untagName . GitHub.simpleUserLogin) assignees+  -- Get more information that is only in the PullRequest response.+  fullPr <- getFullPr auth mgr ownerName repoName pr+  return (reviewers, fullPr)+++getPrInfos+  :: Maybe GitHub.Auth+  -> Manager+  -> GitHub.Name GitHub.Owner+  -> GitHub.Name GitHub.Repo+  -> [GitHub.SimplePullRequest]+  -> IO [([Text], GitHub.PullRequest)]+getPrInfos auth mgr ownerName repoName =+    Parallel.mapM (getPrInfo auth mgr ownerName repoName)+++makePullRequestInfo+  :: GitHub.Name GitHub.Repo+  -> ([Text], GitHub.PullRequest)+  -> PullRequestInfo+makePullRequestInfo repoName (reviewers, pr) = PullRequestInfo+  { prRepoName    = GitHub.untagName repoName+  , prNumber      = GitHub.unIssueNumber $ GitHub.pullRequestNumber pr+  , prUser        = user+  , prBranch      = Text.tail branch+  , prCreated     = GitHub.pullRequestCreatedAt pr+  , prTitle       = GitHub.pullRequestTitle pr+  , prReviewers   = reviewers+  , prState       = showMergeableState $ GitHub.pullRequestMergeableState pr+  , prOrigin      = GitHub.untagName . GitHub.repoName <$> GitHub.pullRequestCommitRepo (GitHub.pullRequestHead pr)+  -- TODO(iphydf): The Haskell github package doesn't support this yet.+  -- , prTrustworthy = GitHub.pullRequestAuthorAssociation pr+  , prTrustworthy = False+  }+  where+    (user, branch) = Text.breakOn ":" . GitHub.pullRequestCommitLabel . GitHub.pullRequestHead $ pr++    showMergeableState GitHub.StateBehind   = "behind"+    showMergeableState GitHub.StateBlocked  = "blocked"+    showMergeableState GitHub.StateClean    = "clean"+    showMergeableState GitHub.StateDirty    = "dirty"+    showMergeableState GitHub.StateDraft    = "draft"+    showMergeableState GitHub.StateUnknown  = "unknown"+    showMergeableState GitHub.StateUnstable = "unstable"+++getPrsForRepo+  :: Maybe GitHub.Auth+  -> Manager+  -> GitHub.Name GitHub.Owner+  -> GitHub.Name GitHub.Repo+  -> IO [PullRequestInfo]+getPrsForRepo auth mgr ownerName repoName =+  map (makePullRequestInfo repoName) <$> (+      -- Get PR list.+      V.toList <$> request auth mgr (GitHub.pullRequestsForR ownerName repoName GitHub.stateOpen GitHub.FetchAll)+      -- Get more details about each PR.+      >>= getPrInfos auth mgr ownerName repoName)+++getPullInfos+  :: GitHub.Name GitHub.Organization+  -> GitHub.Name GitHub.Owner+  -> Maybe GitHub.Auth+  -> IO [[PullRequestInfo]]+getPullInfos orgName ownerName auth = do+  -- Initialise HTTP manager so we can benefit from keep-alive connections.+  mgr <- newManager tlsManagerSettings++  -- Get repo list.+  repos <- V.toList <$> request auth mgr (GitHub.organizationReposR orgName GitHub.RepoPublicityAll GitHub.FetchAll)+  let repoNames = map GitHub.repoName repos++  filter (not . null) . List.sort <$> Parallel.mapM (getPrsForRepo auth mgr ownerName) repoNames+++showPullInfos :: Bool -> [[PullRequestInfo]] -> IO Text+showPullInfos wantHtml infos =+  -- Pretty-print table with information.+  flip (PullRequestInfo.formatPR wantHtml) infos <$> getCurrentTime+++getPullStatus+  :: GitHub.Name GitHub.Organization+  -> GitHub.Name GitHub.Owner+  -> Bool+  -> Maybe GitHub.Auth+  -> IO Text+getPullStatus orgName ownerName wantHtml auth =+  getPullInfos orgName ownerName auth >>= showPullInfos wantHtml
+ src/GitHub/Tools/Requests.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE DataKinds #-}+module GitHub.Tools.Requests where++import           Control.Monad.Catch (throwM)+import           Data.Aeson          (FromJSON)+import qualified GitHub+import           Network.HTTP.Client (Manager)+++request+  :: FromJSON a+  => Maybe GitHub.Auth+  -> Manager+  -> GitHub.Request 'GitHub.RO a+  -> IO a+request auth mgr req = do+  response <- executeRequest+  case response of+    Left  err -> throwM err+    Right res -> return res++  where+    executeRequest =+      case auth of+        Nothing -> GitHub.executeRequestWithMgr' mgr req+        Just tk -> GitHub.executeRequestWithMgr mgr tk req
+ src/GitHub/Types.hs view
@@ -0,0 +1,5 @@+module GitHub.Types (module X) where++import           GitHub.Types.Base          as X+import           GitHub.Types.Events        as X+import           GitHub.Types.PayloadParser as X
+ src/GitHub/Types/Base.hs view
@@ -0,0 +1,62 @@+module GitHub.Types.Base (module X) where++import           GitHub.Types.Base.Author             as X+import           GitHub.Types.Base.Branch             as X+import           GitHub.Types.Base.Change             as X+import           GitHub.Types.Base.Changes            as X+import           GitHub.Types.Base.CheckApp           as X+import           GitHub.Types.Base.CheckCommit        as X+import           GitHub.Types.Base.CheckCommitRef     as X+import           GitHub.Types.Base.CheckCommitRepo    as X+import           GitHub.Types.Base.CheckOutput        as X+import           GitHub.Types.Base.CheckPullRequest   as X+import           GitHub.Types.Base.CheckRun           as X+import           GitHub.Types.Base.CheckSuite         as X+import           GitHub.Types.Base.Commit             as X+import           GitHub.Types.Base.CommitComment      as X+import           GitHub.Types.Base.CommitDetails      as X+import           GitHub.Types.Base.CommitRef          as X+import           GitHub.Types.Base.CommitRefHtml      as X+import           GitHub.Types.Base.DateTime           as X+import           GitHub.Types.Base.Deployment         as X+import           GitHub.Types.Base.DeploymentPayload  as X+import           GitHub.Types.Base.DeploymentStatus   as X+import           GitHub.Types.Base.Hook               as X+import           GitHub.Types.Base.HookConfig         as X+import           GitHub.Types.Base.Installation       as X+import           GitHub.Types.Base.Invitation         as X+import           GitHub.Types.Base.Issue              as X+import           GitHub.Types.Base.IssueComment       as X+import           GitHub.Types.Base.Label              as X+import           GitHub.Types.Base.License            as X+import           GitHub.Types.Base.Link               as X+import           GitHub.Types.Base.Membership         as X+import           GitHub.Types.Base.Milestone          as X+import           GitHub.Types.Base.Organization       as X+import           GitHub.Types.Base.PageBuild          as X+import           GitHub.Types.Base.PageBuildError     as X+import           GitHub.Types.Base.Permissions        as X+import           GitHub.Types.Base.PullRequest        as X+import           GitHub.Types.Base.PullRequestLinks   as X+import           GitHub.Types.Base.PullRequestRef     as X+import           GitHub.Types.Base.PushCommit         as X+import           GitHub.Types.Base.Reactions          as X+import           GitHub.Types.Base.Release            as X+import           GitHub.Types.Base.RepoOwner          as X+import           GitHub.Types.Base.Repository         as X+import           GitHub.Types.Base.Review             as X+import           GitHub.Types.Base.ReviewComment      as X+import           GitHub.Types.Base.ReviewCommentLinks as X+import           GitHub.Types.Base.ReviewLinks        as X+import           GitHub.Types.Base.SimplePullRequest  as X+import           GitHub.Types.Base.SimpleRepository   as X+import           GitHub.Types.Base.StatusCommit       as X+import           GitHub.Types.Base.Team               as X+import           GitHub.Types.Base.User               as X+import           GitHub.Types.Base.UserRef            as X+import           GitHub.Types.Base.UserStamp          as X+import           GitHub.Types.Base.Verification       as X+import           GitHub.Types.Base.Workflow           as X+import           GitHub.Types.Base.WorkflowJob        as X+import           GitHub.Types.Base.WorkflowRun        as X+import           GitHub.Types.Base.WorkflowStep       as X
+ src/GitHub/Types/Base/Author.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Author where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- Author++data Author = Author+    { authorName     :: Text+    , authorEmail    :: Text+    , authorUsername :: Maybe Text+    } deriving (Eq, Show, Read)+++instance FromJSON Author where+    parseJSON (Object x) = Author+        <$> x .: "name"+        <*> x .: "email"+        <*> x .:? "username"++    parseJSON _ = fail "Author"+++instance ToJSON Author where+    toJSON Author{..} = object+        [ "name"     .= authorName+        , "email"    .= authorEmail+        , "username" .= authorUsername+        ]++instance Arbitrary Author where+    arbitrary = Author+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Branch.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Branch where++import           Data.Aeson                  (FromJSON (..), ToJSON (..),+                                              object)+import           Data.Aeson.Types            (Value (..), (.:), (.=))+import           Data.Text                   (Text)+import           Test.QuickCheck.Arbitrary   (Arbitrary (..))++import           GitHub.Types.Base.CommitRef++------------------------------------------------------------------------------+-- Branch++data Branch = Branch+    { branchName      :: Text+    , branchProtected :: Bool+    , branchCommit    :: CommitRef+    } deriving (Eq, Show, Read)+++instance FromJSON Branch where+    parseJSON (Object x) = Branch+        <$> x .: "name"+        <*> x .: "protected"+        <*> x .: "commit"++    parseJSON _ = fail "Branch"+++instance ToJSON Branch where+    toJSON Branch{..} = object+        [ "name"      .= branchName+        , "protected" .= branchProtected+        , "commit"    .= branchCommit+        ]+++instance Arbitrary Branch where+    arbitrary = Branch+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Change.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Change where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- Change++newtype Change = Change+    { changesFrom :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON Change where+    parseJSON (Object x) = Change+        <$> x .: "from"++    parseJSON _ = fail "Change"+++instance ToJSON Change where+    toJSON Change{..} = object+        [ "from" .= changesFrom+        ]+++instance Arbitrary Change where+    arbitrary = Change+        <$> arbitrary
+ src/GitHub/Types/Base/Changes.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Changes where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:?), (.=))+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base.Change++------------------------------------------------------------------------------+-- Changes++data Changes = Changes+    { changesTitle :: Maybe Change+    , changesBody  :: Maybe Change+    } deriving (Eq, Show, Read)+++instance FromJSON Changes where+    parseJSON (Object x) = Changes+        <$> x .:? "title"+        <*> x .:? "body"++    parseJSON _ = fail "Changes"+++instance ToJSON Changes where+    toJSON Changes{..} = object+        [ "title" .= changesTitle+        , "body"  .= changesBody+        ]+++instance Arbitrary Changes where+    arbitrary = Changes+        <$> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/CheckApp.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.CheckApp where++import           Data.Aeson                    (FromJSON (..), ToJSON (..),+                                                object)+import           Data.Aeson.Types              (Value (..), (.:), (.=))+import           Data.Text                     (Text)+import           Test.QuickCheck.Arbitrary     (Arbitrary (..))++import           GitHub.Types.Base.Permissions+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- CheckApp++data CheckApp = CheckApp+    { checkAppCreatedAt   :: Text+    , checkAppDescription :: Text+    , checkAppEvents      :: [Text]+    , checkAppExternalUrl :: Text+    , checkAppHtmlUrl     :: Text+    , checkAppId          :: Int+    , checkAppName        :: Text+    , checkAppNodeId      :: Text+    , checkAppOwner       :: User+    , checkAppPermissions :: Permissions+    , checkAppSlug        :: Text+    , checkAppUpdatedAt   :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON CheckApp where+    parseJSON (Object x) = CheckApp+        <$> x .: "created_at"+        <*> x .: "description"+        <*> x .: "events"+        <*> x .: "external_url"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "name"+        <*> x .: "node_id"+        <*> x .: "owner"+        <*> x .: "permissions"+        <*> x .: "slug"+        <*> x .: "updated_at"++    parseJSON _ = fail "CheckApp"+++instance ToJSON CheckApp where+    toJSON CheckApp{..} = object+        [ "created_at"   .= checkAppCreatedAt+        , "description"  .= checkAppDescription+        , "events"       .= checkAppEvents+        , "external_url" .= checkAppExternalUrl+        , "html_url"     .= checkAppHtmlUrl+        , "id"           .= checkAppId+        , "name"         .= checkAppName+        , "node_id"      .= checkAppNodeId+        , "owner"        .= checkAppOwner+        , "permissions"  .= checkAppPermissions+        , "slug"         .= checkAppSlug+        , "updated_at"   .= checkAppUpdatedAt+        ]+++instance Arbitrary CheckApp where+    arbitrary = CheckApp+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/CheckCommit.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.CheckCommit where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base.Author++------------------------------------------------------------------------------+-- CheckCommit++data CheckCommit = CheckCommit+    { checkCommitAuthor    :: Author+    , checkCommitCommitter :: Author+    , checkCommitId        :: Text+    , checkCommitMessage   :: Text+    , checkCommitTimestamp :: Text+    , checkCommitTreeId    :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON CheckCommit where+    parseJSON (Object x) = CheckCommit+        <$> x .: "author"+        <*> x .: "committer"+        <*> x .: "id"+        <*> x .: "message"+        <*> x .: "timestamp"+        <*> x .: "tree_id"++    parseJSON _ = fail "CheckCommit"+++instance ToJSON CheckCommit where+    toJSON CheckCommit{..} = object+        [ "author"       .= checkCommitAuthor+        , "committer"    .= checkCommitCommitter+        , "id"           .= checkCommitId+        , "message"      .= checkCommitMessage+        , "timestamp"    .= checkCommitTimestamp+        , "tree_id"      .= checkCommitTreeId+        ]+++instance Arbitrary CheckCommit where+    arbitrary = CheckCommit+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/CheckCommitRef.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.CheckCommitRef where++import           Data.Aeson                        (FromJSON (..), ToJSON (..),+                                                    object)+import           Data.Aeson.Types                  (Value (..), (.:), (.=))+import           Data.Text                         (Text)+import           Test.QuickCheck.Arbitrary         (Arbitrary (..))++import           GitHub.Types.Base.CheckCommitRepo++------------------------------------------------------------------------------+-- CheckCommitRef++data CheckCommitRef = CheckCommitRef+    { checkCommitRefSha  :: Text+    , checkCommitRefRef  :: Text+    , checkCommitRefRepo :: CheckCommitRepo+    } deriving (Eq, Show, Read)+++instance FromJSON CheckCommitRef where+    parseJSON (Object x) = CheckCommitRef+        <$> x .: "sha"+        <*> x .: "ref"+        <*> x .: "repo"++    parseJSON _ = fail "CheckCommitRef"+++instance ToJSON CheckCommitRef where+    toJSON CheckCommitRef{..} = object+        [ "sha"          .= checkCommitRefSha+        , "ref"          .= checkCommitRefRef+        , "repo"         .= checkCommitRefRepo+        ]+++instance Arbitrary CheckCommitRef where+    arbitrary = CheckCommitRef+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/CheckCommitRepo.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.CheckCommitRepo where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- CheckCommitRepo++data CheckCommitRepo = CheckCommitRepo+    { checkCommitRepoId   :: Int+    , checkCommitRepoName :: Text+    , checkCommitRepoUrl  :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON CheckCommitRepo where+    parseJSON (Object x) = CheckCommitRepo+        <$> x .: "id"+        <*> x .: "name"+        <*> x .: "url"++    parseJSON _ = fail "CheckCommitRepo"+++instance ToJSON CheckCommitRepo where+    toJSON CheckCommitRepo{..} = object+        [ "id"           .= checkCommitRepoId+        , "name"         .= checkCommitRepoName+        , "url"          .= checkCommitRepoUrl+        ]+++instance Arbitrary CheckCommitRepo where+    arbitrary = CheckCommitRepo+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/CheckOutput.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.CheckOutput where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- CheckOutput++data CheckOutput = CheckOutput+    { checkOutputAnnotationsCount :: Int+    , checkOutputAnnotationsUrl   :: Text+    , checkOutputSummary          :: Maybe Text+    , checkOutputText             :: Maybe Text+    , checkOutputTitle            :: Maybe Text+    } deriving (Eq, Show, Read)+++instance FromJSON CheckOutput where+    parseJSON (Object x) = CheckOutput+        <$> x .: "annotations_count"+        <*> x .: "annotations_url"+        <*> x .: "summary"+        <*> x .: "text"+        <*> x .: "title"++    parseJSON _ = fail "CheckOutput"+++instance ToJSON CheckOutput where+    toJSON CheckOutput{..} = object+        [ "annotations_count" .= checkOutputAnnotationsCount+        , "annotations_url"   .= checkOutputAnnotationsUrl+        , "summary"           .= checkOutputSummary+        , "text"              .= checkOutputText+        , "title"             .= checkOutputTitle+        ]+++instance Arbitrary CheckOutput where+    arbitrary = CheckOutput+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/CheckPullRequest.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.CheckPullRequest where++import           Data.Aeson                       (FromJSON (..), ToJSON (..),+                                                   object)+import           Data.Aeson.Types                 (Value (..), (.:), (.=))+import           Data.Text                        (Text)+import           Test.QuickCheck.Arbitrary        (Arbitrary (..))++import           GitHub.Types.Base.CheckCommitRef++------------------------------------------------------------------------------+-- CheckPullRequest++data CheckPullRequest = CheckPullRequest+    { checkPullRequestBase   :: CheckCommitRef+    , checkPullRequestHead   :: CheckCommitRef+    , checkPullRequestId     :: Int+    , checkPullRequestNumber :: Int+    , checkPullRequestUrl    :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON CheckPullRequest where+    parseJSON (Object x) = CheckPullRequest+        <$> x .: "base"+        <*> x .: "head"+        <*> x .: "id"+        <*> x .: "number"+        <*> x .: "url"++    parseJSON _ = fail "CheckPullRequest"+++instance ToJSON CheckPullRequest where+    toJSON CheckPullRequest{..} = object+        [ "base"   .= checkPullRequestBase+        , "head"   .= checkPullRequestHead+        , "id"     .= checkPullRequestId+        , "number" .= checkPullRequestNumber+        , "url"    .= checkPullRequestUrl+        ]+++instance Arbitrary CheckPullRequest where+    arbitrary = CheckPullRequest+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/CheckRun.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.CheckRun where++import           Data.Aeson                         (FromJSON (..), ToJSON (..),+                                                     object)+import           Data.Aeson.Types                   (Value (..), (.:), (.=))+import           Data.Text                          (Text)+import           Test.QuickCheck.Arbitrary          (Arbitrary (..))++import           GitHub.Types.Base.CheckApp+import           GitHub.Types.Base.CheckOutput+import           GitHub.Types.Base.CheckPullRequest+import           GitHub.Types.Base.CheckSuite++------------------------------------------------------------------------------+-- CheckRun++data CheckRun = CheckRun+    { checkRunApp          :: CheckApp+    , checkRunCheckSuite   :: CheckSuite+    , checkRunCompletedAt  :: Maybe Text+    , checkRunConclusion   :: Maybe Text+    , checkRunDetailsUrl   :: Text+    , checkRunExternalId   :: Text+    , checkRunHeadSha      :: Text+    , checkRunHtmlUrl      :: Text+    , checkRunId           :: Int+    , checkRunName         :: Text+    , checkRunNodeId       :: Text+    , checkRunOutput       :: CheckOutput+    , checkRunPullRequests :: [CheckPullRequest]+    , checkRunStartedAt    :: Text+    , checkRunStatus       :: Text+    , checkRunUrl          :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON CheckRun where+    parseJSON (Object x) = CheckRun+        <$> x .: "app"+        <*> x .: "check_suite"+        <*> x .: "completed_at"+        <*> x .: "conclusion"+        <*> x .: "details_url"+        <*> x .: "external_id"+        <*> x .: "head_sha"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "name"+        <*> x .: "node_id"+        <*> x .: "output"+        <*> x .: "pull_requests"+        <*> x .: "started_at"+        <*> x .: "status"+        <*> x .: "url"++    parseJSON _ = fail "CheckRun"+++instance ToJSON CheckRun where+    toJSON CheckRun{..} = object+        [ "app"           .= checkRunApp+        , "check_suite"   .= checkRunCheckSuite+        , "completed_at"  .= checkRunCompletedAt+        , "conclusion"    .= checkRunConclusion+        , "details_url"   .= checkRunDetailsUrl+        , "external_id"   .= checkRunExternalId+        , "head_sha"      .= checkRunHeadSha+        , "html_url"      .= checkRunHtmlUrl+        , "id"            .= checkRunId+        , "name"          .= checkRunName+        , "node_id"       .= checkRunNodeId+        , "output"        .= checkRunOutput+        , "pull_requests" .= checkRunPullRequests+        , "started_at"    .= checkRunStartedAt+        , "status"        .= checkRunStatus+        , "url"           .= checkRunUrl+        ]+++instance Arbitrary CheckRun where+    arbitrary = CheckRun+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/CheckSuite.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.CheckSuite where++import           Data.Aeson                         (FromJSON (..), ToJSON (..),+                                                     object)+import           Data.Aeson.Types                   (Value (..), (.:), (.:?),+                                                     (.=))+import           Data.Text                          (Text)+import           Test.QuickCheck.Arbitrary          (Arbitrary (..))++import           GitHub.Types.Base.CheckApp+import           GitHub.Types.Base.CheckCommit+import           GitHub.Types.Base.CheckPullRequest++------------------------------------------------------------------------------+-- CheckSuite++data CheckSuite = CheckSuite+    { checkSuiteAfter                :: Maybe Text+    , checkSuiteApp                  :: CheckApp+    , checkSuiteBefore               :: Maybe Text+    , checkSuiteCheckRunsUrl         :: Maybe Text+    , checkSuiteConclusion           :: Maybe Text+    , checkSuiteHeadBranch           :: Maybe Text+    , checkSuiteHeadCommit           :: Maybe CheckCommit+    , checkSuiteHeadSha              :: Text+    , checkSuiteId                   :: Int+    , checkSuiteLatestCheckRunsCount :: Maybe Int+    , checkSuiteNodeId               :: Text+    , checkSuitePullRequests         :: [CheckPullRequest]+    , checkSuiteRerequestable        :: Maybe Bool+    , checkSuiteRunsRerequestable    :: Maybe Bool+    , checkSuiteStatus               :: Text+    , checkSuiteUrl                  :: Text+    , checkSuiteUpdatedAt            :: Text+    , checkSuiteCreatedAt            :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON CheckSuite where+    parseJSON (Object x) = CheckSuite+        <$> x .: "after"+        <*> x .: "app"+        <*> x .: "before"+        <*> x .:? "check_runs_url"+        <*> x .: "conclusion"+        <*> x .: "head_branch"+        <*> x .:? "head_commit"+        <*> x .: "head_sha"+        <*> x .: "id"+        <*> x .:? "latest_check_runs_count"+        <*> x .: "node_id"+        <*> x .: "pull_requests"+        <*> x .:? "rerequestable"+        <*> x .:? "runs_rerequestable"+        <*> x .: "status"+        <*> x .: "url"+        <*> x .: "updated_at"+        <*> x .: "created_at"++    parseJSON _ = fail "CheckSuite"+++instance ToJSON CheckSuite where+    toJSON CheckSuite{..} = object+        [ "after"                   .= checkSuiteAfter+        , "app"                     .= checkSuiteApp+        , "before"                  .= checkSuiteBefore+        , "check_runs_url"          .= checkSuiteCheckRunsUrl+        , "conclusion"              .= checkSuiteConclusion+        , "head_branch"             .= checkSuiteHeadBranch+        , "head_commit"             .= checkSuiteHeadCommit+        , "head_sha"                .= checkSuiteHeadSha+        , "id"                      .= checkSuiteId+        , "latest_check_runs_count" .= checkSuiteLatestCheckRunsCount+        , "node_id"                 .= checkSuiteNodeId+        , "pull_requests"           .= checkSuitePullRequests+        , "rerequestable"           .= checkSuiteRerequestable+        , "runs_rerequestable"      .= checkSuiteRunsRerequestable+        , "status"                  .= checkSuiteStatus+        , "url"                     .= checkSuiteUrl+        , "updated_at"              .= checkSuiteUpdatedAt+        , "created_at"              .= checkSuiteCreatedAt+        ]+++instance Arbitrary CheckSuite where+    arbitrary = CheckSuite+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Commit.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Commit where++import           Data.Aeson                   (FromJSON (..), ToJSON (..),+                                               object)+import           Data.Aeson.Types             (Value (..), (.:), (.:?), (.=))+import           Data.Text                    (Text)+import           Test.QuickCheck.Arbitrary    (Arbitrary (..))++import           GitHub.Types.Base.Repository+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- Commit++data Commit = Commit+    { commitSha   :: Text+    , commitUser  :: Maybe User+    , commitRepo  :: Maybe Repository+    , commitLabel :: Text+    , commitRef   :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON Commit where+    parseJSON (Object x) = Commit+        <$> x .: "sha"+        <*> x .:? "user"+        <*> x .: "repo"+        <*> x .: "label"+        <*> x .: "ref"++    parseJSON _ = fail "Commit"+++instance ToJSON Commit where+    toJSON Commit{..} = object+        [ "sha"   .= commitSha+        , "user"  .= commitUser+        , "repo"  .= commitRepo+        , "label" .= commitLabel+        , "ref"   .= commitRef+        ]+++instance Arbitrary Commit where+    arbitrary = Commit+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/CommitComment.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.CommitComment where++import           Data.Aeson                 (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types           (Value (..), (.:), (.=))+import           Data.Text                  (Text)+import           Test.QuickCheck.Arbitrary  (Arbitrary (..))++import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- CommitComment++data CommitComment = CommitComment+    { commitCommentUrl       :: Text+    , commitCommentHtmlUrl   :: Text+    , commitCommentId        :: Int+    , commitCommentUser      :: User+    , commitCommentPosition  :: Maybe Int+    , commitCommentLine      :: Maybe Int+    , commitCommentPath      :: Maybe Text+    , commitCommentCommitId  :: Text+    , commitCommentCreatedAt :: DateTime+    , commitCommentUpdatedAt :: DateTime+    , commitCommentBody      :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON CommitComment where+    parseJSON (Object x) = CommitComment+        <$> x .: "url"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "user"+        <*> x .: "position"+        <*> x .: "line"+        <*> x .: "path"+        <*> x .: "commit_id"+        <*> x .: "created_at"+        <*> x .: "updated_at"+        <*> x .: "body"++    parseJSON _ = fail "CommitComment"+++instance ToJSON CommitComment where+    toJSON CommitComment{..} = object+        [ "url"        .= commitCommentUrl+        , "html_url"   .= commitCommentHtmlUrl+        , "id"         .= commitCommentId+        , "user"       .= commitCommentUser+        , "position"   .= commitCommentPosition+        , "line"       .= commitCommentLine+        , "path"       .= commitCommentPath+        , "commit_id"  .= commitCommentCommitId+        , "created_at" .= commitCommentCreatedAt+        , "updated_at" .= commitCommentUpdatedAt+        , "body"       .= commitCommentBody+        ]+++instance Arbitrary CommitComment where+    arbitrary = CommitComment+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/CommitDetails.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.CommitDetails where++import           Data.Aeson                     (FromJSON (..), ToJSON (..),+                                                 object)+import           Data.Aeson.Types               (Value (..), (.:), (.=))+import           Data.Text                      (Text)+import           Test.QuickCheck.Arbitrary      (Arbitrary (..))++import           GitHub.Types.Base.CommitRef+import           GitHub.Types.Base.UserStamp+import           GitHub.Types.Base.Verification++------------------------------------------------------------------------------+-- CommitDetails++data CommitDetails = CommitDetails+    { commitDetailsAuthor       :: UserStamp+    , commitDetailsCommentCount :: Int+    , commitDetailsCommitter    :: UserStamp+    , commitDetailsMessage      :: Text+    , commitDetailsTree         :: CommitRef+    , commitDetailsUrl          :: Text+    , commitDetailsVerification :: Verification+    } deriving (Eq, Show, Read)+++instance FromJSON CommitDetails where+    parseJSON (Object x) = CommitDetails+        <$> x .: "author"+        <*> x .: "comment_count"+        <*> x .: "committer"+        <*> x .: "message"+        <*> x .: "tree"+        <*> x .: "url"+        <*> x .: "verification"++    parseJSON _ = fail "CommitDetails"+++instance ToJSON CommitDetails where+    toJSON CommitDetails{..} = object+        [ "author"        .= commitDetailsAuthor+        , "comment_count" .= commitDetailsCommentCount+        , "committer"     .= commitDetailsCommitter+        , "message"       .= commitDetailsMessage+        , "tree"          .= commitDetailsTree+        , "url"           .= commitDetailsUrl+        , "verification"  .= commitDetailsVerification+        ]+++instance Arbitrary CommitDetails where+    arbitrary = CommitDetails+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/CommitRef.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.CommitRef where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- CommitRef++data CommitRef = CommitRef+    { commitRefSha :: Text+    , commitRefUrl :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON CommitRef where+    parseJSON (Object x) = CommitRef+        <$> x .: "sha"+        <*> x .: "url"++    parseJSON _ = fail "CommitRef"+++instance ToJSON CommitRef where+    toJSON CommitRef{..} = object+        [ "sha" .= commitRefSha+        , "url" .= commitRefUrl+        ]+++instance Arbitrary CommitRef where+    arbitrary = CommitRef+        <$> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/CommitRefHtml.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.CommitRefHtml where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- CommitRefHtml++data CommitRefHtml = CommitRefHtml+    { commitRefHtmlSha     :: Text+    , commitRefHtmlUrl     :: Text+    , commitRefHtmlHtmlUrl :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON CommitRefHtml where+    parseJSON (Object x) = CommitRefHtml+        <$> x .: "sha"+        <*> x .: "url"+        <*> x .: "html_url"++    parseJSON _ = fail "CommitRefHtml"+++instance ToJSON CommitRefHtml where+    toJSON CommitRefHtml{..} = object+        [ "sha"      .= commitRefHtmlSha+        , "url"      .= commitRefHtmlUrl+        , "html_url" .= commitRefHtmlHtmlUrl+        ]+++instance Arbitrary CommitRefHtml where+    arbitrary = CommitRefHtml+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/DateTime.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE StrictData #-}+module GitHub.Types.Base.DateTime where++import           Control.Applicative       ((<|>))+import           Data.Aeson                (FromJSON (..), ToJSON (..))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))+import qualified Test.QuickCheck.Gen       as Gen++------------------------------------------------------------------------------+-- DateTime++data DateTime+    = DateTimeStamp Int+    | DateTimeText Text+    deriving (Eq, Show, Read)+++instance FromJSON DateTime where+    parseJSON x =+          DateTimeStamp <$> parseJSON x+      <|> DateTimeText  <$> parseJSON x+++instance ToJSON DateTime where+    toJSON (DateTimeStamp x) = toJSON x+    toJSON (DateTimeText  x) = toJSON x+++instance Arbitrary DateTime where+    arbitrary = Gen.oneof+      [ DateTimeStamp <$> arbitrary+      , DateTimeText  <$> arbitrary+      ]
+ src/GitHub/Types/Base/Deployment.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Deployment where++import           Data.Aeson                          (FromJSON (..),+                                                      ToJSON (..), object)+import           Data.Aeson.Types                    (Value (..), (.:), (.=))+import           Data.Text                           (Text)+import           Test.QuickCheck.Arbitrary           (Arbitrary (..))++import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.DeploymentPayload+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- Deployment++data Deployment = Deployment+    { deploymentUrl                   :: Text+    , deploymentId                    :: Int+    , deploymentNodeId                :: Text+    , deploymentSha                   :: Text+    , deploymentRef                   :: Text+    , deploymentTask                  :: Text+    , deploymentPayload               :: Maybe DeploymentPayload+    , deploymentEnvironment           :: Text+    , deploymentOriginalEnvironment   :: Text+    , deploymentProductionEnvironment :: Bool+    , deploymentTransientEnvironment  :: Bool+    , deploymentDescription           :: Maybe Text+    , deploymentCreator               :: User+    , deploymentCreatedAt             :: DateTime+    , deploymentUpdatedAt             :: DateTime+    , deploymentStatusesUrl           :: Text+    , deploymentRepositoryUrl         :: Text+    } deriving (Eq, Show, Read)++instance FromJSON Deployment where+    parseJSON (Object x) = Deployment+        <$> x .: "url"+        <*> x .: "id"+        <*> x .: "node_id"+        <*> x .: "sha"+        <*> x .: "ref"+        <*> x .: "task"+        <*> x .: "payload"+        <*> x .: "environment"+        <*> x .: "original_environment"+        <*> x .: "production_environment"+        <*> x .: "transient_environment"+        <*> x .: "description"+        <*> x .: "creator"+        <*> x .: "created_at"+        <*> x .: "updated_at"+        <*> x .: "statuses_url"+        <*> x .: "repository_url"++    parseJSON _ = fail "Deployment"++instance ToJSON Deployment where+    toJSON Deployment{..} = object+        [ "url"                    .= deploymentUrl+        , "id"                     .= deploymentId+        , "node_id"                .= deploymentNodeId+        , "sha"                    .= deploymentSha+        , "ref"                    .= deploymentRef+        , "task"                   .= deploymentTask+        , "payload"                .= deploymentPayload+        , "environment"            .= deploymentEnvironment+        , "original_environment"   .= deploymentOriginalEnvironment+        , "production_environment" .= deploymentProductionEnvironment+        , "transient_environment"  .= deploymentTransientEnvironment+        , "description"            .= deploymentDescription+        , "creator"                .= deploymentCreator+        , "created_at"             .= deploymentCreatedAt+        , "updated_at"             .= deploymentUpdatedAt+        , "statuses_url"           .= deploymentStatusesUrl+        , "repository_url"         .= deploymentRepositoryUrl+        ]+++instance Arbitrary Deployment where+    arbitrary = Deployment+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/DeploymentPayload.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.DeploymentPayload where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:?), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- DeploymentPayload++newtype DeploymentPayload = DeploymentPayload+    { deploymentPayloadWebUrl :: Maybe Text+    } deriving (Eq, Show, Read)++instance FromJSON DeploymentPayload where+    parseJSON (Object x) = DeploymentPayload+        <$> x .:? "web_url"++    parseJSON _ = fail "DeploymentPayload"++instance ToJSON DeploymentPayload where+    toJSON DeploymentPayload{..} = object+        [ "web_url" .= deploymentPayloadWebUrl+        ]+++instance Arbitrary DeploymentPayload where+    arbitrary = DeploymentPayload+        <$> arbitrary
+ src/GitHub/Types/Base/DeploymentStatus.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.DeploymentStatus where++import           Data.Aeson                 (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types           (Value (..), (.:), (.=))+import           Data.Text                  (Text)+import           Test.QuickCheck.Arbitrary  (Arbitrary (..))++import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- DeploymentStatus++data DeploymentStatus = DeploymentStatus+    { deploymentStatusUrl            :: Text+    , deploymentStatusId             :: Int+    , deploymentStatusState          :: Text+    , deploymentStatusNodeId         :: Text+    , deploymentStatusCreator        :: User+    , deploymentStatusDescription    :: Text+    , deploymentStatusEnvironment    :: Text+    , deploymentStatusTargetUrl      :: Text+    , deploymentStatusLogUrl         :: Text+    , deploymentStatusCreatedAt      :: DateTime+    , deploymentStatusUpdatedAt      :: DateTime+    , deploymentStatusDeploymentUrl  :: Text+    , deploymentStatusRepositoryUrl  :: Text+    , deploymentStatusEnvironmentUrl :: Text+    } deriving (Eq, Show, Read)++instance FromJSON DeploymentStatus where+    parseJSON (Object x) = DeploymentStatus+        <$> x .: "url"+        <*> x .: "id"+        <*> x .: "state"+        <*> x .: "node_id"+        <*> x .: "creator"+        <*> x .: "description"+        <*> x .: "environment"+        <*> x .: "target_url"+        <*> x .: "log_url"+        <*> x .: "created_at"+        <*> x .: "updated_at"+        <*> x .: "deployment_url"+        <*> x .: "repository_url"+        <*> x .: "environment_url"++    parseJSON _ = fail "DeploymentStatus"++instance ToJSON DeploymentStatus where+    toJSON DeploymentStatus{..} = object+        [ "url"             .= deploymentStatusUrl+        , "id"              .= deploymentStatusId+        , "state"           .= deploymentStatusState+        , "node_id"         .= deploymentStatusNodeId+        , "creator"         .= deploymentStatusCreator+        , "description"     .= deploymentStatusDescription+        , "environment"     .= deploymentStatusEnvironment+        , "target_url"      .= deploymentStatusTargetUrl+        , "log_url"         .= deploymentStatusLogUrl+        , "created_at"      .= deploymentStatusCreatedAt+        , "updated_at"      .= deploymentStatusUpdatedAt+        , "deployment_url"  .= deploymentStatusDeploymentUrl+        , "repository_url"  .= deploymentStatusRepositoryUrl+        , "environment_url" .= deploymentStatusEnvironmentUrl+        ]+++instance Arbitrary DeploymentStatus where+    arbitrary = DeploymentStatus+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Hook.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Hook where++import           Data.Aeson                   (FromJSON (..), ToJSON (..),+                                               object)+import           Data.Aeson.Types             (Value (..), (.:), (.=))+import           Data.Text                    (Text)+import           Test.QuickCheck.Arbitrary    (Arbitrary (..))++import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.HookConfig++------------------------------------------------------------------------------+-- Hook++data Hook = Hook+    { hookActive    :: Bool+    , hookConfig    :: HookConfig+    , hookCreatedAt :: DateTime+    , hookEvents    :: [Text]+    , hookId        :: Int+    , hookName      :: Text+    , hookPingUrl   :: Text+    , hookType      :: Text+    , hookUpdatedAt :: DateTime+    , hookUrl       :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON Hook where+    parseJSON (Object x) = Hook+        <$> x .: "active"+        <*> x .: "config"+        <*> x .: "created_at"+        <*> x .: "events"+        <*> x .: "id"+        <*> x .: "name"+        <*> x .: "ping_url"+        <*> x .: "type"+        <*> x .: "updated_at"+        <*> x .: "url"++    parseJSON _ = fail "Hook"+++instance ToJSON Hook where+    toJSON Hook{..} = object+        [ "active"     .= hookActive+        , "config"     .= hookConfig+        , "created_at" .= hookCreatedAt+        , "events"     .= hookEvents+        , "id"         .= hookId+        , "name"       .= hookName+        , "ping_url"   .= hookPingUrl+        , "type"       .= hookType+        , "updated_at" .= hookUpdatedAt+        , "url"        .= hookUrl+        ]+++instance Arbitrary Hook where+    arbitrary = Hook+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/HookConfig.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.HookConfig where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- HookConfig++data HookConfig = HookConfig+    { hookConfigContentType :: Text+    , hookConfigInsecureSsl :: Text+    , hookConfigSecret      :: Text+    , hookConfigUrl         :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON HookConfig where+    parseJSON (Object x) = HookConfig+        <$> x .: "content_type"+        <*> x .: "insecure_ssl"+        <*> x .: "secret"+        <*> x .: "url"++    parseJSON _ = fail "HookConfig"+++instance ToJSON HookConfig where+    toJSON HookConfig{..} = object+        [ "content_type" .= hookConfigContentType+        , "insecure_ssl" .= hookConfigInsecureSsl+        , "secret"       .= hookConfigSecret+        , "url"          .= hookConfigUrl+        ]+++instance Arbitrary HookConfig where+    arbitrary = HookConfig+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Installation.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Installation where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- Installation++data Installation = Installation+    { installationId     :: Int+    , installationNodeId :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON Installation where+    parseJSON (Object x) = Installation+        <$> x .: "id"+        <*> x .: "node_id"++    parseJSON _ = fail "Installation"+++instance ToJSON Installation where+    toJSON Installation{..} = object+        [ "id"      .= installationId+        , "node_id" .= installationNodeId+        ]+++instance Arbitrary Installation where+    arbitrary = Installation+        <$> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Invitation.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Invitation where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- Invitation++data Invitation = Invitation+    { invitationEmail :: Maybe Text+    , invitationId    :: Int+    , invitationLogin :: Text+    , invitationRole  :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON Invitation where+    parseJSON (Object x) = Invitation+        <$> x .: "email"+        <*> x .: "id"+        <*> x .: "login"+        <*> x .: "role"++    parseJSON _ = fail "Invitation"+++instance ToJSON Invitation where+    toJSON Invitation{..} = object+        [ "email"            .= invitationEmail+        , "id"               .= invitationId+        , "login"            .= invitationLogin+        , "role"             .= invitationRole+        ]+++instance Arbitrary Invitation where+    arbitrary = Invitation+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Issue.hs view
@@ -0,0 +1,155 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Issue where++import           Data.Aeson                       (FromJSON (..), ToJSON (..),+                                                   object)+import           Data.Aeson.Types                 (Value (..), (.:), (.:?),+                                                   (.=))+import           Data.Text                        (Text)+import           Test.QuickCheck.Arbitrary        (Arbitrary (..))++import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.Label+import           GitHub.Types.Base.Milestone+import           GitHub.Types.Base.PullRequestRef+import           GitHub.Types.Base.Reactions+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- Issue++data Issue = Issue+    { issueActiveLockReason      :: Maybe Text+    , issueAssignee              :: Maybe User+    , issueAssignees             :: [User]+    , issueAuthorAssociation     :: Text+    , issueBody                  :: Maybe Text+    , issueClosedAt              :: Maybe DateTime+    , issueComments              :: Int+    , issueCommentsUrl           :: Text+    , issueCreatedAt             :: DateTime+    , issueDraft                 :: Maybe Bool+    , issueEventsUrl             :: Text+    , issueHtmlUrl               :: Text+    , issueId                    :: Int+    , issueLabels                :: [Label]+    , issueLabelsUrl             :: Text+    , issueLocked                :: Bool+    , issueMilestone             :: Maybe Milestone+    , issueNodeId                :: Text+    , issueNumber                :: Int+    , issuePerformedViaGithubApp :: Maybe Text+    , issuePullRequest           :: Maybe PullRequestRef+    , issueReactions             :: Reactions+    , issueRepositoryUrl         :: Text+    , issueState                 :: Text+    , issueTimelineUrl           :: Text+    , issueTitle                 :: Text+    , issueUpdatedAt             :: DateTime+    , issueUrl                   :: Text+    , issueUser                  :: User+    } deriving (Eq, Show, Read)+++instance FromJSON Issue where+    parseJSON (Object x) = Issue+        <$> x .: "active_lock_reason"+        <*> x .: "assignee"+        <*> x .: "assignees"+        <*> x .: "author_association"+        <*> x .: "body"+        <*> x .: "closed_at"+        <*> x .: "comments"+        <*> x .: "comments_url"+        <*> x .: "created_at"+        <*> x .: "draft"+        <*> x .: "events_url"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "labels"+        <*> x .: "labels_url"+        <*> x .: "locked"+        <*> x .: "milestone"+        <*> x .: "node_id"+        <*> x .: "number"+        <*> x .: "performed_via_github_app"+        <*> x .:? "pull_request"+        <*> x .: "reactions"+        <*> x .: "repository_url"+        <*> x .: "state"+        <*> x .: "timeline_url"+        <*> x .: "title"+        <*> x .: "updated_at"+        <*> x .: "url"+        <*> x .: "user"++    parseJSON _ = fail "Issue"+++instance ToJSON Issue where+    toJSON Issue{..} = object+        [ "active_lock_reason"       .= issueActiveLockReason+        , "assignee"                 .= issueAssignee+        , "assignees"                .= issueAssignees+        , "author_association"       .= issueAuthorAssociation+        , "body"                     .= issueBody+        , "closed_at"                .= issueClosedAt+        , "comments"                 .= issueComments+        , "comments_url"             .= issueCommentsUrl+        , "created_at"               .= issueCreatedAt+        , "draft"                    .= issueDraft+        , "events_url"               .= issueEventsUrl+        , "html_url"                 .= issueHtmlUrl+        , "id"                       .= issueId+        , "labels"                   .= issueLabels+        , "labels_url"               .= issueLabelsUrl+        , "locked"                   .= issueLocked+        , "milestone"                .= issueMilestone+        , "node_id"                  .= issueNodeId+        , "number"                   .= issueNumber+        , "performed_via_github_app" .= issuePerformedViaGithubApp+        , "pull_request"             .= issuePullRequest+        , "reactions"                .= issueReactions+        , "repository_url"           .= issueRepositoryUrl+        , "state"                    .= issueState+        , "timeline_url"             .= issueTimelineUrl+        , "title"                    .= issueTitle+        , "updated_at"               .= issueUpdatedAt+        , "url"                      .= issueUrl+        , "user"                     .= issueUser+        ]+++instance Arbitrary Issue where+    arbitrary = Issue+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/IssueComment.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.IssueComment where++import           Data.Aeson                  (FromJSON (..), ToJSON (..),+                                              object)+import           Data.Aeson.Types            (Value (..), (.:), (.=))+import           Data.Text                   (Text)+import           Test.QuickCheck.Arbitrary   (Arbitrary (..))++import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.Reactions+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- IssueComment++data IssueComment = IssueComment+    { issueCommentAuthorAssociation     :: Text+    , issueCommentBody                  :: Text+    , issueCommentCreatedAt             :: DateTime+    , issueCommentHtmlUrl               :: Text+    , issueCommentId                    :: Int+    , issueCommentNodeId                :: Text+    , issueCommentIssueUrl              :: Text+    , issueCommentPerformedViaGithubApp :: Maybe Bool+    , issueCommentReactions             :: Reactions+    , issueCommentUpdatedAt             :: DateTime+    , issueCommentUrl                   :: Text+    , issueCommentUser                  :: User+    } deriving (Eq, Show, Read)+++instance FromJSON IssueComment where+    parseJSON (Object x) = IssueComment+        <$> x .: "author_association"+        <*> x .: "body"+        <*> x .: "created_at"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "node_id"+        <*> x .: "issue_url"+        <*> x .: "performed_via_github_app"+        <*> x .: "reactions"+        <*> x .: "updated_at"+        <*> x .: "url"+        <*> x .: "user"++    parseJSON _ = fail "IssueComment"+++instance ToJSON IssueComment where+    toJSON IssueComment{..} = object+        [ "author_association"       .= issueCommentAuthorAssociation+        , "body"                     .= issueCommentBody+        , "created_at"               .= issueCommentCreatedAt+        , "html_url"                 .= issueCommentHtmlUrl+        , "id"                       .= issueCommentId+        , "node_id"                  .= issueCommentNodeId+        , "issue_url"                .= issueCommentIssueUrl+        , "performed_via_github_app" .= issueCommentPerformedViaGithubApp+        , "reactions"                .= issueCommentReactions+        , "updated_at"               .= issueCommentUpdatedAt+        , "url"                      .= issueCommentUrl+        , "user"                     .= issueCommentUser+        ]+++instance Arbitrary IssueComment where+    arbitrary = IssueComment+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Label.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Label where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- Label++data Label = Label+    { labelColor       :: Text+    , labelDefault     :: Bool+    , labelDescription :: Text+    , labelUrl         :: Text+    , labelName        :: Text+    , labelId          :: Int+    , labelNodeId      :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON Label where+    parseJSON (Object x) = Label+        <$> x .: "color"+        <*> x .: "default"+        <*> x .: "description"+        <*> x .: "url"+        <*> x .: "name"+        <*> x .: "id"+        <*> x .: "node_id"++    parseJSON _ = fail "Label"+++instance ToJSON Label where+    toJSON Label{..} = object+        [ "color"       .= labelColor+        , "default"     .= labelDefault+        , "description" .= labelDescription+        , "url"         .= labelUrl+        , "name"        .= labelName+        , "id"          .= labelId+        , "node_id"     .= labelNodeId+        ]+++instance Arbitrary Label where+    arbitrary = Label+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/License.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.License where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- License++data License = License+    { licenseKey    :: Text+    , licenseName   :: Text+    , licenseNodeId :: Text+    , licenseSpdxId :: Maybe Text+    , licenseUrl    :: Maybe Text+    } deriving (Eq, Show, Read)+++instance FromJSON License where+    parseJSON (Object x) = License+        <$> x .: "key"+        <*> x .: "name"+        <*> x .: "node_id"+        <*> x .: "spdx_id"+        <*> x .: "url"++    parseJSON _ = fail "License"+++instance ToJSON License where+    toJSON License{..} = object+        [ "key"     .= licenseKey+        , "name"    .= licenseName+        , "node_id" .= licenseNodeId+        , "spdx_id" .= licenseSpdxId+        , "url"     .= licenseUrl+        ]++instance Arbitrary License where+    arbitrary = License+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Link.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Link where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- Link++newtype Link = Link+    { linkHref :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON Link where+    parseJSON (Object x) = Link+        <$> x .: "href"++    parseJSON _ = fail "Link"+++instance ToJSON Link where+    toJSON Link{..} = object+        [ "href" .= linkHref+        ]+++instance Arbitrary Link where+    arbitrary = Link+        <$> arbitrary
+ src/GitHub/Types/Base/Membership.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Membership where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- Membership++data Membership = Membership+    { membershipOrganizationUrl :: Text+    , membershipRole            :: Text+    , membershipState           :: Text+    , membershipUrl             :: Text+    , membershipUser            :: User+    } deriving (Eq, Show, Read)+++instance FromJSON Membership where+    parseJSON (Object x) = Membership+        <$> x .: "organization_url"+        <*> x .: "role"+        <*> x .: "state"+        <*> x .: "url"+        <*> x .: "user"++    parseJSON _ = fail "Membership"+++instance ToJSON Membership where+    toJSON Membership{..} = object+        [ "organization_url" .= membershipOrganizationUrl+        , "role"             .= membershipRole+        , "state"            .= membershipState+        , "url"              .= membershipUrl+        , "user"             .= membershipUser+        ]+++instance Arbitrary Membership where+    arbitrary = Membership+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Milestone.hs view
@@ -0,0 +1,97 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Milestone where++import           Data.Aeson                 (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types           (Value (..), (.:), (.=))+import           Data.Text                  (Text)+import           Test.QuickCheck.Arbitrary  (Arbitrary (..))++import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- Milestone++data Milestone = Milestone+    { milestoneCreator      :: User+    , milestoneClosedIssues :: Int+    , milestoneState        :: Text+    , milestoneDueOn        :: Maybe Text+    , milestoneUrl          :: Text+    , milestoneUpdatedAt    :: DateTime+    , milestoneCreatedAt    :: DateTime+    , milestoneId           :: Int+    , milestoneNodeId       :: Text+    , milestoneTitle        :: Text+    , milestoneClosedAt     :: Maybe DateTime+    , milestoneNumber       :: Int+    , milestoneDescription  :: Maybe Text+    , milestoneLabelsUrl    :: Text+    , milestoneHtmlUrl      :: Text+    , milestoneOpenIssues   :: Int+    } deriving (Eq, Show, Read)+++instance FromJSON Milestone where+    parseJSON (Object x) = Milestone+        <$> x .: "creator"+        <*> x .: "closed_issues"+        <*> x .: "state"+        <*> x .: "due_on"+        <*> x .: "url"+        <*> x .: "updated_at"+        <*> x .: "created_at"+        <*> x .: "id"+        <*> x .: "node_id"+        <*> x .: "title"+        <*> x .: "closed_at"+        <*> x .: "number"+        <*> x .: "description"+        <*> x .: "labels_url"+        <*> x .: "html_url"+        <*> x .: "open_issues"++    parseJSON _ = fail "Milestone"+++instance ToJSON Milestone where+    toJSON Milestone{..} = object+        [ "creator"       .= milestoneCreator+        , "closed_issues" .= milestoneClosedIssues+        , "state"         .= milestoneState+        , "due_on"        .= milestoneDueOn+        , "url"           .= milestoneUrl+        , "updated_at"    .= milestoneUpdatedAt+        , "created_at"    .= milestoneCreatedAt+        , "id"            .= milestoneId+        , "node_id"       .= milestoneNodeId+        , "title"         .= milestoneTitle+        , "closed_at"     .= milestoneClosedAt+        , "number"        .= milestoneNumber+        , "description"   .= milestoneDescription+        , "labels_url"    .= milestoneLabelsUrl+        , "html_url"      .= milestoneHtmlUrl+        , "open_issues"   .= milestoneOpenIssues+        ]+++instance Arbitrary Milestone where+    arbitrary = Milestone+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Organization.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Organization where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- Organization++data Organization = Organization+    { organizationAvatarUrl        :: Text+    , organizationDescription      :: Text+    , organizationEmail            :: Maybe Text+    , organizationEventsUrl        :: Text+    , organizationHooksUrl         :: Text+    , organizationId               :: Int+    , organizationIssuesUrl        :: Text+    , organizationLogin            :: Text+    , organizationMembersUrl       :: Text+    , organizationNodeId           :: Text+    , organizationPublicMembersUrl :: Text+    , organizationReposUrl         :: Text+    , organizationUrl              :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON Organization where+    parseJSON (Object x) = Organization+        <$> x .: "avatar_url"+        <*> x .: "description"+        <*> x .:? "email"+        <*> x .: "events_url"+        <*> x .: "hooks_url"+        <*> x .: "id"+        <*> x .: "issues_url"+        <*> x .: "login"+        <*> x .: "members_url"+        <*> x .: "node_id"+        <*> x .: "public_members_url"+        <*> x .: "repos_url"+        <*> x .: "url"++    parseJSON _ = fail "Organization"+++instance ToJSON Organization where+    toJSON Organization{..} = object+        [ "avatar_url"         .= organizationAvatarUrl+        , "description"        .= organizationDescription+        , "email"              .= organizationEmail+        , "events_url"         .= organizationEventsUrl+        , "hooks_url"          .= organizationHooksUrl+        , "id"                 .= organizationId+        , "issues_url"         .= organizationIssuesUrl+        , "login"              .= organizationLogin+        , "members_url"        .= organizationMembersUrl+        , "node_id"            .= organizationNodeId+        , "public_members_url" .= organizationPublicMembersUrl+        , "repos_url"          .= organizationReposUrl+        , "url"                .= organizationUrl+        ]+++instance Arbitrary Organization where+    arbitrary = Organization+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/PageBuild.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.PageBuild where++import           Data.Aeson                       (FromJSON (..), ToJSON (..),+                                                   object)+import           Data.Aeson.Types                 (Value (..), (.:), (.=))+import           Data.Text                        (Text)+import           Test.QuickCheck.Arbitrary        (Arbitrary (..))++import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.PageBuildError+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- PageBuild++data PageBuild = PageBuild+    { pageBuildCommit    :: Text+    , pageBuildCreatedAt :: DateTime+    , pageBuildDuration  :: Int+    , pageBuildError     :: PageBuildError+    , pageBuildPusher    :: User+    , pageBuildStatus    :: Text+    , pageBuildUpdatedAt :: DateTime+    , pageBuildUrl       :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON PageBuild where+    parseJSON (Object x) = PageBuild+        <$> x .: "commit"+        <*> x .: "created_at"+        <*> x .: "duration"+        <*> x .: "error"+        <*> x .: "pusher"+        <*> x .: "status"+        <*> x .: "updated_at"+        <*> x .: "url"++    parseJSON _ = fail "PageBuild"+++instance ToJSON PageBuild where+    toJSON PageBuild{..} = object+        [ "commit"     .= pageBuildCommit+        , "created_at" .= pageBuildCreatedAt+        , "duration"   .= pageBuildDuration+        , "error"      .= pageBuildError+        , "pusher"     .= pageBuildPusher+        , "status"     .= pageBuildStatus+        , "updated_at" .= pageBuildUpdatedAt+        , "url"        .= pageBuildUrl+        ]+++instance Arbitrary PageBuild where+    arbitrary = PageBuild+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/PageBuildError.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.PageBuildError where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- PageBuildError++newtype PageBuildError = PageBuildError+    { pageBuildErrorMessage :: Maybe Text+    } deriving (Eq, Show, Read)+++instance FromJSON PageBuildError where+    parseJSON (Object x) = PageBuildError+        <$> x .: "message"++    parseJSON _ = fail "PageBuildError"+++instance ToJSON PageBuildError where+    toJSON PageBuildError{..} = object+        [ "message" .= pageBuildErrorMessage+        ]+++instance Arbitrary PageBuildError where+    arbitrary = PageBuildError+        <$> arbitrary
+ src/GitHub/Types/Base/Permissions.hs view
@@ -0,0 +1,131 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Permissions where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:?), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- Permissions++data Permissions = Permissions+    { permissionsActions              :: Maybe Text+    , permissionsAdministration       :: Maybe Text+    , permissionsChecks               :: Maybe Text+    , permissionsContents             :: Maybe Text+    , permissionsContentReferences    :: Maybe Text+    , permissionsDeployments          :: Maybe Text+    , permissionsDiscussions          :: Maybe Text+    , permissionsEmails               :: Maybe Text+    , permissionsIssues               :: Maybe Text+    , permissionsKeys                 :: Maybe Text+    , permissionsMembers              :: Maybe Text+    , permissionsMergeQueues          :: Maybe Text+    , permissionsMetadata             :: Maybe Text+    , permissionsOrganizationHooks    :: Maybe Text+    , permissionsOrganizationPackages :: Maybe Text+    , permissionsOrganizationProjects :: Maybe Text+    , permissionsPackages             :: Maybe Text+    , permissionsPages                :: Maybe Text+    , permissionsPullRequests         :: Maybe Text+    , permissionsRepositoryHooks      :: Maybe Text+    , permissionsRepositoryProjects   :: Maybe Text+    , permissionsSecurityEvents       :: Maybe Text+    , permissionsSingleFile           :: Maybe Text+    , permissionsStatuses             :: Maybe Text+    , permissionsVulnerabilityAlerts  :: Maybe Text+    } deriving (Eq, Show, Read)+++instance FromJSON Permissions where+    parseJSON (Object x) = Permissions+        <$> x .:? "actions"+        <*> x .:? "administration"+        <*> x .:? "checks"+        <*> x .:? "contents"+        <*> x .:? "content_references"+        <*> x .:? "deployments"+        <*> x .:? "discussions"+        <*> x .:? "emails"+        <*> x .:? "issues"+        <*> x .:? "keys"+        <*> x .:? "members"+        <*> x .:? "merge_queues"+        <*> x .:? "metadata"+        <*> x .:? "organization_hooks"+        <*> x .:? "organization_packages"+        <*> x .:? "organization_projects"+        <*> x .:? "packages"+        <*> x .:? "pages"+        <*> x .:? "pull_requests"+        <*> x .:? "repository_hooks"+        <*> x .:? "repository_projects"+        <*> x .:? "security_events"+        <*> x .:? "single_file"+        <*> x .:? "statuses"+        <*> x .:? "vulnerability_alerts"++    parseJSON _ = fail "Permissions"+++instance ToJSON Permissions where+    toJSON Permissions{..} = object+        [ "actions"               .= permissionsActions+        , "administration"        .= permissionsAdministration+        , "checks"                .= permissionsChecks+        , "contents"              .= permissionsContents+        , "content_references"    .= permissionsContentReferences+        , "deployments"           .= permissionsDeployments+        , "discussions"           .= permissionsDiscussions+        , "emails"                .= permissionsEmails+        , "issues"                .= permissionsIssues+        , "keys"                  .= permissionsKeys+        , "members"               .= permissionsMembers+        , "merge_queues"          .= permissionsMergeQueues+        , "metadata"              .= permissionsMetadata+        , "organization_hooks"    .= permissionsOrganizationHooks+        , "organization_packages" .= permissionsOrganizationPackages+        , "organization_projects" .= permissionsOrganizationProjects+        , "packages"              .= permissionsPackages+        , "pages"                 .= permissionsPages+        , "pull_requests"         .= permissionsPullRequests+        , "repository_hooks"      .= permissionsRepositoryHooks+        , "repository_projects"   .= permissionsRepositoryProjects+        , "security_events"       .= permissionsSecurityEvents+        , "single_file"           .= permissionsSingleFile+        , "statuses"              .= permissionsStatuses+        , "vulnerability_alerts"  .= permissionsVulnerabilityAlerts+        ]+++instance Arbitrary Permissions where+    arbitrary = Permissions+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/PullRequest.hs view
@@ -0,0 +1,223 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.PullRequest where++import           Data.Aeson                         (FromJSON (..), ToJSON (..),+                                                     object)+import           Data.Aeson.Types                   (Value (..), (.:), (.=))+import           Data.Text                          (Text)+import           Test.QuickCheck.Arbitrary          (Arbitrary (..))++import           GitHub.Types.Base.Commit+import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.Label+import           GitHub.Types.Base.Milestone+import           GitHub.Types.Base.PullRequestLinks+import           GitHub.Types.Base.Team+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- PullRequest++data PullRequest = PullRequest+    { pullRequestAdditions           :: Int+    , pullRequestAssignee            :: Maybe User+    , pullRequestAssignees           :: [User]+    , pullRequestAuthorAssociation   :: Text+    , pullRequestBase                :: Commit+    , pullRequestBody                :: Maybe Text+    , pullRequestChangedFiles        :: Int+    , pullRequestClosedAt            :: Maybe DateTime+    , pullRequestComments            :: Int+    , pullRequestCommentsUrl         :: Text+    , pullRequestCommits             :: Int+    , pullRequestCommitsUrl          :: Text+    , pullRequestCreatedAt           :: DateTime+    , pullRequestDeletions           :: Int+    , pullRequestDiffUrl             :: Text+    , pullRequestDraft               :: Bool+    , pullRequestHead                :: Commit+    , pullRequestHtmlUrl             :: Text+    , pullRequestId                  :: Int+    , pullRequestIssueUrl            :: Text+    , pullRequestLabels              :: [Label]+    , pullRequestLinks               :: PullRequestLinks+    , pullRequestLocked              :: Bool+    , pullRequestMaintainerCanModify :: Bool+    , pullRequestMergeable           :: Maybe Bool+    , pullRequestMergeableState      :: Text+    , pullRequestMergeCommitSha      :: Maybe Text+    , pullRequestMerged              :: Bool+    , pullRequestMergedAt            :: Maybe DateTime+    , pullRequestMergedBy            :: Maybe User+    , pullRequestMilestone           :: Maybe Milestone+    , pullRequestNodeId              :: Text+    , pullRequestNumber              :: Int+    , pullRequestPatchUrl            :: Text+    , pullRequestRebaseable          :: Maybe Bool+    , pullRequestRequestedReviewers  :: [User]+    , pullRequestRequestedTeams      :: [Team]+    , pullRequestReviewComments      :: Int+    , pullRequestReviewCommentsUrl   :: Text+    , pullRequestReviewCommentUrl    :: Text+    , pullRequestState               :: Text+    , pullRequestStatusesUrl         :: Text+    , pullRequestTitle               :: Text+    , pullRequestUpdatedAt           :: DateTime+    , pullRequestUrl                 :: Text+    , pullRequestUser                :: User+    } deriving (Eq, Show, Read)+++instance FromJSON PullRequest where+    parseJSON (Object x) = PullRequest+        <$> x .: "additions"+        <*> x .: "assignee"+        <*> x .: "assignees"+        <*> x .: "author_association"+        <*> x .: "base"+        <*> x .: "body"+        <*> x .: "changed_files"+        <*> x .: "closed_at"+        <*> x .: "comments"+        <*> x .: "comments_url"+        <*> x .: "commits"+        <*> x .: "commits_url"+        <*> x .: "created_at"+        <*> x .: "deletions"+        <*> x .: "diff_url"+        <*> x .: "draft"+        <*> x .: "head"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "issue_url"+        <*> x .: "labels"+        <*> x .: "_links"+        <*> x .: "locked"+        <*> x .: "maintainer_can_modify"+        <*> x .: "mergeable"+        <*> x .: "mergeable_state"+        <*> x .: "merge_commit_sha"+        <*> x .: "merged"+        <*> x .: "merged_at"+        <*> x .: "merged_by"+        <*> x .: "milestone"+        <*> x .: "node_id"+        <*> x .: "number"+        <*> x .: "patch_url"+        <*> x .: "rebaseable"+        <*> x .: "requested_reviewers"+        <*> x .: "requested_teams"+        <*> x .: "review_comments"+        <*> x .: "review_comments_url"+        <*> x .: "review_comment_url"+        <*> x .: "state"+        <*> x .: "statuses_url"+        <*> x .: "title"+        <*> x .: "updated_at"+        <*> x .: "url"+        <*> x .: "user"++    parseJSON _ = fail "PullRequest"+++instance ToJSON PullRequest where+    toJSON PullRequest{..} = object+        [ "additions"             .= pullRequestAdditions+        , "assignee"              .= pullRequestAssignee+        , "assignees"             .= pullRequestAssignees+        , "author_association"    .= pullRequestAuthorAssociation+        , "base"                  .= pullRequestBase+        , "body"                  .= pullRequestBody+        , "changed_files"         .= pullRequestChangedFiles+        , "closed_at"             .= pullRequestClosedAt+        , "comments"              .= pullRequestComments+        , "comments_url"          .= pullRequestCommentsUrl+        , "commits"               .= pullRequestCommits+        , "commits_url"           .= pullRequestCommitsUrl+        , "created_at"            .= pullRequestCreatedAt+        , "deletions"             .= pullRequestDeletions+        , "diff_url"              .= pullRequestDiffUrl+        , "draft"                 .= pullRequestDraft+        , "head"                  .= pullRequestHead+        , "html_url"              .= pullRequestHtmlUrl+        , "id"                    .= pullRequestId+        , "issue_url"             .= pullRequestIssueUrl+        , "labels"                .= pullRequestLabels+        , "_links"                .= pullRequestLinks+        , "locked"                .= pullRequestLocked+        , "maintainer_can_modify" .= pullRequestMaintainerCanModify+        , "mergeable"             .= pullRequestMergeable+        , "mergeable_state"       .= pullRequestMergeableState+        , "merge_commit_sha"      .= pullRequestMergeCommitSha+        , "merged"                .= pullRequestMerged+        , "merged_at"             .= pullRequestMergedAt+        , "merged_by"             .= pullRequestMergedBy+        , "milestone"             .= pullRequestMilestone+        , "node_id"               .= pullRequestNodeId+        , "number"                .= pullRequestNumber+        , "patch_url"             .= pullRequestPatchUrl+        , "rebaseable"            .= pullRequestRebaseable+        , "requested_reviewers"   .= pullRequestRequestedReviewers+        , "requested_teams"       .= pullRequestRequestedTeams+        , "review_comments"       .= pullRequestReviewComments+        , "review_comments_url"   .= pullRequestReviewCommentsUrl+        , "review_comment_url"    .= pullRequestReviewCommentUrl+        , "state"                 .= pullRequestState+        , "statuses_url"          .= pullRequestStatusesUrl+        , "title"                 .= pullRequestTitle+        , "updated_at"            .= pullRequestUpdatedAt+        , "url"                   .= pullRequestUrl+        , "user"                  .= pullRequestUser+        ]+++instance Arbitrary PullRequest where+    arbitrary = PullRequest+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/PullRequestLinks.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.PullRequestLinks where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base.Link++------------------------------------------------------------------------------+-- PullRequestLinks++data PullRequestLinks = PullRequestLinks+    { pullRequestLinksSelf           :: Link+    , pullRequestLinksCommits        :: Link+    , pullRequestLinksStatuses       :: Link+    , pullRequestLinksReviewComments :: Link+    , pullRequestLinksHtml           :: Link+    , pullRequestLinksComments       :: Link+    , pullRequestLinksReviewComment  :: Link+    , pullRequestLinksIssue          :: Link+    } deriving (Eq, Show, Read)+++instance FromJSON PullRequestLinks where+    parseJSON (Object x) = PullRequestLinks+        <$> x .: "self"+        <*> x .: "commits"+        <*> x .: "statuses"+        <*> x .: "review_comments"+        <*> x .: "html"+        <*> x .: "comments"+        <*> x .: "review_comment"+        <*> x .: "issue"++    parseJSON _ = fail "PullRequestLinks"+++instance ToJSON PullRequestLinks where+    toJSON PullRequestLinks{..} = object+        [ "self"            .= pullRequestLinksSelf+        , "commits"         .= pullRequestLinksCommits+        , "statuses"        .= pullRequestLinksStatuses+        , "review_comments" .= pullRequestLinksReviewComments+        , "html"            .= pullRequestLinksHtml+        , "comments"        .= pullRequestLinksComments+        , "review_comment"  .= pullRequestLinksReviewComment+        , "issue"           .= pullRequestLinksIssue+        ]+++instance Arbitrary PullRequestLinks where+    arbitrary = PullRequestLinks+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/PullRequestRef.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.PullRequestRef where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- PullRequestRef++data PullRequestRef = PullRequestRef+    { pullRequestRefUrl      :: Text+    , pullRequestRefDiffUrl  :: Text+    , pullRequestRefPatchUrl :: Text+    , pullRequestRefHtmlUrl  :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON PullRequestRef where+    parseJSON (Object x) = PullRequestRef+        <$> x .: "url"+        <*> x .: "diff_url"+        <*> x .: "patch_url"+        <*> x .: "html_url"++    parseJSON _ = fail "PullRequestRef"+++instance ToJSON PullRequestRef where+    toJSON PullRequestRef{..} = object+        [ "url"       .= pullRequestRefUrl+        , "diff_url"  .= pullRequestRefDiffUrl+        , "patch_url" .= pullRequestRefPatchUrl+        , "html_url"  .= pullRequestRefHtmlUrl+        ]+++instance Arbitrary PullRequestRef where+    arbitrary = PullRequestRef+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/PushCommit.hs view
@@ -0,0 +1,76 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.PushCommit where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base.Author++------------------------------------------------------------------------------+-- PushCommit++data PushCommit = PushCommit+    { pushCommitAdded     :: [Text]+    , pushCommitAuthor    :: Author+    , pushCommitCommitter :: Maybe Author+    , pushCommitDistinct  :: Bool+    , pushCommitId        :: Text+    , pushCommitMessage   :: Text+    , pushCommitModified  :: [Text]+    , pushCommitRemoved   :: [Text]+    , pushCommitTimestamp :: Text+    , pushCommitTreeId    :: Text+    , pushCommitUrl       :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON PushCommit where+    parseJSON (Object x) = PushCommit+        <$> x .: "added"+        <*> x .: "author"+        <*> x .: "committer"+        <*> x .: "distinct"+        <*> x .: "id"+        <*> x .: "message"+        <*> x .: "modified"+        <*> x .: "removed"+        <*> x .: "timestamp"+        <*> x .: "tree_id"+        <*> x .: "url"++    parseJSON _ = fail "PushCommit"+++instance ToJSON PushCommit where+    toJSON PushCommit{..} = object+        [ "added"        .= pushCommitAdded+        , "author"       .= pushCommitAuthor+        , "committer"    .= pushCommitCommitter+        , "distinct"     .= pushCommitDistinct+        , "id"           .= pushCommitId+        , "message"      .= pushCommitMessage+        , "modified"     .= pushCommitModified+        , "removed"      .= pushCommitRemoved+        , "timestamp"    .= pushCommitTimestamp+        , "tree_id"      .= pushCommitTreeId+        , "url"          .= pushCommitUrl+        ]+++instance Arbitrary PushCommit where+    arbitrary = PushCommit+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Reactions.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Reactions where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- Reactions++data Reactions = Reactions+    { reactionsConfused   :: Int+    , reactionsEyes       :: Int+    , reactionsHeart      :: Int+    , reactionsHooray     :: Int+    , reactionsLaugh      :: Int+    , reactionsMinus1     :: Int+    , reactionsPlus1      :: Int+    , reactionsRocket     :: Int+    , reactionsTotalCount :: Int+    , reactionsUrl        :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON Reactions where+    parseJSON (Object x) = Reactions+        <$> x .: "confused"+        <*> x .: "eyes"+        <*> x .: "heart"+        <*> x .: "hooray"+        <*> x .: "laugh"+        <*> x .: "-1"+        <*> x .: "+1"+        <*> x .: "rocket"+        <*> x .: "total_count"+        <*> x .: "url"++    parseJSON _ = fail "Reactions"+++instance ToJSON Reactions where+    toJSON Reactions{..} = object+        [ "confused"    .= reactionsConfused+        , "eyes"        .= reactionsEyes+        , "heart"       .= reactionsHeart+        , "hooray"      .= reactionsHooray+        , "laugh"       .= reactionsLaugh+        , "-1"          .= reactionsMinus1+        , "+1"          .= reactionsPlus1+        , "rocket"      .= reactionsRocket+        , "total_count" .= reactionsTotalCount+        , "url"         .= reactionsUrl+        ]+++instance Arbitrary Reactions where+    arbitrary = Reactions+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Release.hs view
@@ -0,0 +1,109 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Release where++import           Data.Aeson                 (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types           (Value (..), (.:), (.=))+import           Data.Text                  (Text)+import           Test.QuickCheck.Arbitrary  (Arbitrary (..))++import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- Release++data Release = Release+    { releaseAssets          :: [Text]+    , releaseAssetsUrl       :: Text+    , releaseAuthor          :: User+    , releaseBody            :: Text+    , releaseCreatedAt       :: DateTime+    , releaseDraft           :: Bool+    , releaseHtmlUrl         :: Text+    , releaseId              :: Int+    , releaseMentionsCount   :: Int+    , releaseName            :: Text+    , releaseNodeId          :: Text+    , releasePrerelease      :: Bool+    , releasePublishedAt     :: Maybe DateTime+    , releaseTagName         :: Text+    , releaseTarballUrl      :: Maybe Text+    , releaseTargetCommitish :: Text+    , releaseUploadUrl       :: Text+    , releaseUrl             :: Text+    , releaseZipballUrl      :: Maybe Text+    } deriving (Eq, Show, Read)+++instance FromJSON Release where+    parseJSON (Object x) = Release+        <$> x .: "assets"+        <*> x .: "assets_url"+        <*> x .: "author"+        <*> x .: "body"+        <*> x .: "created_at"+        <*> x .: "draft"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "mentions_count"+        <*> x .: "name"+        <*> x .: "node_id"+        <*> x .: "prerelease"+        <*> x .: "published_at"+        <*> x .: "tag_name"+        <*> x .: "tarball_url"+        <*> x .: "target_commitish"+        <*> x .: "upload_url"+        <*> x .: "url"+        <*> x .: "zipball_url"++    parseJSON _ = fail "Release"+++instance ToJSON Release where+    toJSON Release{..} = object+        [ "assets"           .= releaseAssets+        , "assets_url"       .= releaseAssetsUrl+        , "author"           .= releaseAuthor+        , "body"             .= releaseBody+        , "created_at"       .= releaseCreatedAt+        , "draft"            .= releaseDraft+        , "html_url"         .= releaseHtmlUrl+        , "id"               .= releaseId+        , "mentions_count"   .= releaseMentionsCount+        , "name"             .= releaseName+        , "node_id"          .= releaseNodeId+        , "prerelease"       .= releasePrerelease+        , "published_at"     .= releasePublishedAt+        , "tag_name"         .= releaseTagName+        , "tarball_url"      .= releaseTarballUrl+        , "target_commitish" .= releaseTargetCommitish+        , "upload_url"       .= releaseUploadUrl+        , "url"              .= releaseUrl+        , "zipball_url"      .= releaseZipballUrl+        ]+++instance Arbitrary Release where+    arbitrary = Release+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/RepoOwner.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE StrictData #-}+module GitHub.Types.Base.RepoOwner where++import           Control.Applicative       ((<|>))+import           Data.Aeson                (FromJSON (..), ToJSON (..))+import           Test.QuickCheck.Arbitrary (Arbitrary (..))+import qualified Test.QuickCheck.Gen       as Gen++import           GitHub.Types.Base.User+import           GitHub.Types.Base.UserRef++------------------------------------------------------------------------------+-- RepoOwner++data RepoOwner+    = RepoOwnerUser User+    | RepoOwnerUserRef UserRef+    deriving (Eq, Show, Read)+++instance FromJSON RepoOwner where+    parseJSON x =+          RepoOwnerUser    <$> parseJSON x+      <|> RepoOwnerUserRef <$> parseJSON x+++instance ToJSON RepoOwner where+    toJSON (RepoOwnerUser    x) = toJSON x+    toJSON (RepoOwnerUserRef x) = toJSON x+++instance Arbitrary RepoOwner where+    arbitrary = Gen.oneof+      [ RepoOwnerUser    <$> arbitrary+      , RepoOwnerUserRef <$> arbitrary+      ]
+ src/GitHub/Types/Base/Repository.hs view
@@ -0,0 +1,394 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Repository where++import           Data.Aeson                  (FromJSON (..), ToJSON (..),+                                              object)+import           Data.Aeson.Types            (Value (..), (.:), (.:?), (.=))+import           Data.Text                   (Text)+import           Test.QuickCheck.Arbitrary   (Arbitrary (..))++import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.License+import           GitHub.Types.Base.RepoOwner++------------------------------------------------------------------------------+-- Repository++data Repository = Repository+    { repositoryAllowAutoMerge           :: Maybe Bool+    , repositoryAllowForking             :: Bool+    , repositoryAllowMergeCommit         :: Maybe Bool+    , repositoryAllowRebaseMerge         :: Maybe Bool+    , repositoryAllowSquashMerge         :: Maybe Bool+    , repositoryAllowUpdateBranch        :: Maybe Bool+    , repositoryArchived                 :: Bool+    , repositoryArchiveUrl               :: Text+    , repositoryAssigneesUrl             :: Text+    , repositoryBlobsUrl                 :: Text+    , repositoryBranchesUrl              :: Text+    , repositoryCloneUrl                 :: Text+    , repositoryCollaboratorsUrl         :: Text+    , repositoryCommentsUrl              :: Text+    , repositoryCommitsUrl               :: Text+    , repositoryCompareUrl               :: Text+    , repositoryContentsUrl              :: Text+    , repositoryContributorsUrl          :: Text+    , repositoryCreatedAt                :: DateTime+    , repositoryCustomProperties         :: Value  -- TODO(iphydf): Figure out what this actually is.+    , repositoryDefaultBranch            :: Text+    , repositoryDeleteBranchOnMerge      :: Maybe Bool+    , repositoryDeploymentsUrl           :: Text+    , repositoryDescription              :: Maybe Text+    , repositoryDisabled                 :: Bool+    , repositoryDownloadsUrl             :: Text+    , repositoryEventsUrl                :: Text+    , repositoryFork                     :: Bool+    , repositoryForks                    :: Int+    , repositoryForksCount               :: Int+    , repositoryForksUrl                 :: Text+    , repositoryFullName                 :: Text+    , repositoryGitCommitsUrl            :: Text+    , repositoryGitRefsUrl               :: Text+    , repositoryGitTagsUrl               :: Text+    , repositoryGitUrl                   :: Text+    , repositoryIsTemplate               :: Bool+    , repositoryHasDiscussions           :: Bool+    , repositoryHasDownloads             :: Bool+    , repositoryHasIssues                :: Bool+    , repositoryHasPages                 :: Bool+    , repositoryHasProjects              :: Bool+    , repositoryHasWiki                  :: Bool+    , repositoryHomepage                 :: Maybe Text+    , repositoryHooksUrl                 :: Text+    , repositoryHtmlUrl                  :: Text+    , repositoryId                       :: Int+    , repositoryIssueCommentUrl          :: Text+    , repositoryIssueEventsUrl           :: Text+    , repositoryIssuesUrl                :: Text+    , repositoryKeysUrl                  :: Text+    , repositoryLabelsUrl                :: Text+    , repositoryLanguage                 :: Maybe Text+    , repositoryLanguagesUrl             :: Text+    , repositoryLicense                  :: Maybe License+    , repositoryMasterBranch             :: Maybe Text+    , repositoryMergesUrl                :: Text+    , repositoryMilestonesUrl            :: Text+    , repositoryMirrorUrl                :: Maybe Text+    , repositoryName                     :: Text+    , repositoryNodeId                   :: Text+    , repositoryNotificationsUrl         :: Text+    , repositoryOpenIssues               :: Int+    , repositoryOpenIssuesCount          :: Int+    , repositoryOrganization             :: Maybe Text+    , repositoryOwner                    :: RepoOwner+    , repositoryPrivate                  :: Bool+    , repositoryPublic                   :: Maybe Bool+    , repositoryPullsUrl                 :: Text+    , repositoryPushedAt                 :: Maybe DateTime+    , repositoryReleasesUrl              :: Text+    , repositorySize                     :: Int+    , repositorySshUrl                   :: Text+    , repositoryStargazers               :: Maybe Int+    , repositoryStargazersCount          :: Int+    , repositoryStargazersUrl            :: Text+    , repositoryStatusesUrl              :: Text+    , repositorySubscribersUrl           :: Text+    , repositorySubscriptionUrl          :: Text+    , repositorySvnUrl                   :: Text+    , repositoryTagsUrl                  :: Text+    , repositoryTeamsUrl                 :: Text+    , repositoryTopics                   :: [Text]+    , repositoryTreesUrl                 :: Text+    , repositoryUpdatedAt                :: DateTime+    , repositoryUrl                      :: Text+    , repositoryVisibility               :: Text+    , repositoryWatchers                 :: Int+    , repositoryWatchersCount            :: Int+    , repositoryWebCommitSignoffRequired :: Bool+    } deriving (Eq, Show, Read)+++instance FromJSON Repository where+    parseJSON (Object x) = Repository+        <$> x .:? "allow_auto_merge"+        <*> x .: "allow_forking"+        <*> x .:? "allow_merge_commit"+        <*> x .:? "allow_rebase_merge"+        <*> x .:? "allow_squash_merge"+        <*> x .:? "allow_update_branch"+        <*> x .: "archived"+        <*> x .: "archive_url"+        <*> x .: "assignees_url"+        <*> x .: "blobs_url"+        <*> x .: "branches_url"+        <*> x .: "clone_url"+        <*> x .: "collaborators_url"+        <*> x .: "comments_url"+        <*> x .: "commits_url"+        <*> x .: "compare_url"+        <*> x .: "contents_url"+        <*> x .: "contributors_url"+        <*> x .: "created_at"+        <*> x .: "custom_properties"+        <*> x .: "default_branch"+        <*> x .:? "delete_branch_on_merge"+        <*> x .: "deployments_url"+        <*> x .: "description"+        <*> x .: "disabled"+        <*> x .: "downloads_url"+        <*> x .: "events_url"+        <*> x .: "fork"+        <*> x .: "forks"+        <*> x .: "forks_count"+        <*> x .: "forks_url"+        <*> x .: "full_name"+        <*> x .: "git_commits_url"+        <*> x .: "git_refs_url"+        <*> x .: "git_tags_url"+        <*> x .: "git_url"+        <*> x .: "is_template"+        <*> x .: "has_discussions"+        <*> x .: "has_downloads"+        <*> x .: "has_issues"+        <*> x .: "has_pages"+        <*> x .: "has_projects"+        <*> x .: "has_wiki"+        <*> x .: "homepage"+        <*> x .: "hooks_url"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "issue_comment_url"+        <*> x .: "issue_events_url"+        <*> x .: "issues_url"+        <*> x .: "keys_url"+        <*> x .: "labels_url"+        <*> x .:? "language"+        <*> x .: "languages_url"+        <*> x .: "license"+        <*> x .:? "master_branch"+        <*> x .: "merges_url"+        <*> x .: "milestones_url"+        <*> x .: "mirror_url"+        <*> x .: "name"+        <*> x .: "node_id"+        <*> x .: "notifications_url"+        <*> x .: "open_issues"+        <*> x .: "open_issues_count"+        <*> x .:? "organization"+        <*> x .: "owner"+        <*> x .: "private"+        <*> x .:? "public"+        <*> x .: "pulls_url"+        <*> x .: "pushed_at"+        <*> x .: "releases_url"+        <*> x .: "size"+        <*> x .: "ssh_url"+        <*> x .:? "stargazers"+        <*> x .: "stargazers_count"+        <*> x .: "stargazers_url"+        <*> x .: "statuses_url"+        <*> x .: "subscribers_url"+        <*> x .: "subscription_url"+        <*> x .: "svn_url"+        <*> x .: "tags_url"+        <*> x .: "teams_url"+        <*> x .: "topics"+        <*> x .: "trees_url"+        <*> x .: "updated_at"+        <*> x .: "url"+        <*> x .: "visibility"+        <*> x .: "watchers"+        <*> x .: "watchers_count"+        <*> x .: "web_commit_signoff_required"++    parseJSON _ = fail "Repository"++instance ToJSON Repository where+    toJSON Repository{..} = object+        [ "allow_auto_merge"            .= repositoryAllowAutoMerge+        , "allow_forking"               .= repositoryAllowForking+        , "allow_merge_commit"          .= repositoryAllowMergeCommit+        , "allow_rebase_merge"          .= repositoryAllowRebaseMerge+        , "allow_squash_merge"          .= repositoryAllowSquashMerge+        , "allow_update_branch"         .= repositoryAllowUpdateBranch+        , "archived"                    .= repositoryArchived+        , "archive_url"                 .= repositoryArchiveUrl+        , "assignees_url"               .= repositoryAssigneesUrl+        , "blobs_url"                   .= repositoryBlobsUrl+        , "branches_url"                .= repositoryBranchesUrl+        , "clone_url"                   .= repositoryCloneUrl+        , "collaborators_url"           .= repositoryCollaboratorsUrl+        , "comments_url"                .= repositoryCommentsUrl+        , "commits_url"                 .= repositoryCommitsUrl+        , "compare_url"                 .= repositoryCompareUrl+        , "contents_url"                .= repositoryContentsUrl+        , "contributors_url"            .= repositoryContributorsUrl+        , "created_at"                  .= repositoryCreatedAt+        , "custom_properties"           .= repositoryCustomProperties+        , "default_branch"              .= repositoryDefaultBranch+        , "delete_branch_on_merge"      .= repositoryDeleteBranchOnMerge+        , "deployments_url"             .= repositoryDeploymentsUrl+        , "description"                 .= repositoryDescription+        , "disabled"                    .= repositoryDisabled+        , "downloads_url"               .= repositoryDownloadsUrl+        , "events_url"                  .= repositoryEventsUrl+        , "fork"                        .= repositoryFork+        , "forks"                       .= repositoryForks+        , "forks_count"                 .= repositoryForksCount+        , "forks_url"                   .= repositoryForksUrl+        , "full_name"                   .= repositoryFullName+        , "git_commits_url"             .= repositoryGitCommitsUrl+        , "git_refs_url"                .= repositoryGitRefsUrl+        , "git_tags_url"                .= repositoryGitTagsUrl+        , "git_url"                     .= repositoryGitUrl+        , "is_template"                 .= repositoryIsTemplate+        , "has_discussions"             .= repositoryHasDiscussions+        , "has_downloads"               .= repositoryHasDownloads+        , "has_issues"                  .= repositoryHasIssues+        , "has_pages"                   .= repositoryHasPages+        , "has_projects"                .= repositoryHasProjects+        , "has_wiki"                    .= repositoryHasWiki+        , "homepage"                    .= repositoryHomepage+        , "hooks_url"                   .= repositoryHooksUrl+        , "html_url"                    .= repositoryHtmlUrl+        , "id"                          .= repositoryId+        , "issue_comment_url"           .= repositoryIssueCommentUrl+        , "issue_events_url"            .= repositoryIssueEventsUrl+        , "issues_url"                  .= repositoryIssuesUrl+        , "keys_url"                    .= repositoryKeysUrl+        , "labels_url"                  .= repositoryLabelsUrl+        , "language"                    .= repositoryLanguage+        , "languages_url"               .= repositoryLanguagesUrl+        , "license"                     .= repositoryLicense+        , "master_branch"               .= repositoryMasterBranch+        , "merges_url"                  .= repositoryMergesUrl+        , "milestones_url"              .= repositoryMilestonesUrl+        , "mirror_url"                  .= repositoryMirrorUrl+        , "name"                        .= repositoryName+        , "node_id"                     .= repositoryNodeId+        , "notifications_url"           .= repositoryNotificationsUrl+        , "open_issues"                 .= repositoryOpenIssues+        , "open_issues_count"           .= repositoryOpenIssuesCount+        , "organization"                .= repositoryOrganization+        , "owner"                       .= repositoryOwner+        , "private"                     .= repositoryPrivate+        , "public"                      .= repositoryPublic+        , "pulls_url"                   .= repositoryPullsUrl+        , "pushed_at"                   .= repositoryPushedAt+        , "releases_url"                .= repositoryReleasesUrl+        , "size"                        .= repositorySize+        , "ssh_url"                     .= repositorySshUrl+        , "stargazers"                  .= repositoryStargazers+        , "stargazers_count"            .= repositoryStargazersCount+        , "stargazers_url"              .= repositoryStargazersUrl+        , "statuses_url"                .= repositoryStatusesUrl+        , "subscribers_url"             .= repositorySubscribersUrl+        , "subscription_url"            .= repositorySubscriptionUrl+        , "svn_url"                     .= repositorySvnUrl+        , "tags_url"                    .= repositoryTagsUrl+        , "teams_url"                   .= repositoryTeamsUrl+        , "topics"                      .= repositoryTopics+        , "trees_url"                   .= repositoryTreesUrl+        , "updated_at"                  .= repositoryUpdatedAt+        , "url"                         .= repositoryUrl+        , "visibility"                  .= repositoryVisibility+        , "watchers"                    .= repositoryWatchers+        , "watchers_count"              .= repositoryWatchersCount+        , "web_commit_signoff_required" .= repositoryWebCommitSignoffRequired+        ]+++instance Arbitrary Repository where+    arbitrary = Repository+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Review.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Review where++import           Data.Aeson                    (FromJSON (..), ToJSON (..),+                                                object)+import           Data.Aeson.Types              (Value (..), (.:), (.=))+import           Data.Text                     (Text)+import           Test.QuickCheck.Arbitrary     (Arbitrary (..))++import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.ReviewLinks+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- Review++data Review = Review+    { reviewId                :: Int+    , reviewUser              :: User+    , reviewAuthorAssociation :: Text+    , reviewCommitId          :: Text+    , reviewBody              :: Maybe Text+    , reviewSubmittedAt       :: DateTime+    , reviewNodeId            :: Text+    , reviewState             :: Text+    , reviewHtmlUrl           :: Text+    , reviewPullRequestUrl    :: Text+    , reviewLinks             :: ReviewLinks+    } deriving (Eq, Show, Read)+++instance FromJSON Review where+    parseJSON (Object x) = Review+        <$> x .: "id"+        <*> x .: "user"+        <*> x .: "author_association"+        <*> x .: "commit_id"+        <*> x .: "body"+        <*> x .: "submitted_at"+        <*> x .: "node_id"+        <*> x .: "state"+        <*> x .: "html_url"+        <*> x .: "pull_request_url"+        <*> x .: "_links"++    parseJSON _ = fail "Review"+++instance ToJSON Review where+    toJSON Review{..} = object+        [ "id"                 .= reviewId+        , "user"               .= reviewUser+        , "author_association" .= reviewAuthorAssociation+        , "commit_id"          .= reviewCommitId+        , "body"               .= reviewBody+        , "submitted_at"       .= reviewSubmittedAt+        , "node_id"            .= reviewNodeId+        , "state"              .= reviewState+        , "html_url"           .= reviewHtmlUrl+        , "pull_request_url"   .= reviewPullRequestUrl+        , "_links"             .= reviewLinks+        ]+++instance Arbitrary Review where+    arbitrary = Review+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/ReviewComment.hs view
@@ -0,0 +1,131 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.ReviewComment where++import           Data.Aeson                           (FromJSON (..),+                                                       ToJSON (..), object)+import           Data.Aeson.Types                     (Value (..), (.:), (.=))+import           Data.Text                            (Text)+import           Test.QuickCheck.Arbitrary            (Arbitrary (..))++import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.ReviewCommentLinks+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- ReviewComment++data ReviewComment = ReviewComment+    { reviewCommentAuthorAssociation   :: Text+    , reviewCommentBody                :: Text+    , reviewCommentCommitId            :: Text+    , reviewCommentCreatedAt           :: DateTime+    , reviewCommentDiffHunk            :: Text+    , reviewCommentHtmlUrl             :: Text+    , reviewCommentId                  :: Int+    , reviewCommentLine                :: Int+    , reviewCommentLinks               :: ReviewCommentLinks+    , reviewCommentNodeId              :: Text+    , reviewCommentOriginalCommitId    :: Text+    , reviewCommentOriginalLine        :: Int+    , reviewCommentOriginalPosition    :: Maybe Int+    , reviewCommentOriginalStartLine   :: Maybe Int+    , reviewCommentPath                :: Maybe Text+    , reviewCommentPosition            :: Maybe Int+    , reviewCommentPullRequestReviewId :: Int+    , reviewCommentPullRequestUrl      :: Text+    , reviewCommentSide                :: Text+    , reviewCommentStartLine           :: Maybe Int+    , reviewCommentStartSide           :: Maybe Text+    , reviewCommentUpdatedAt           :: DateTime+    , reviewCommentUrl                 :: Text+    , reviewCommentUser                :: User+    } deriving (Eq, Show, Read)+++instance FromJSON ReviewComment where+    parseJSON (Object x) = ReviewComment+        <$> x .: "author_association"+        <*> x .: "body"+        <*> x .: "commit_id"+        <*> x .: "created_at"+        <*> x .: "diff_hunk"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "line"+        <*> x .: "_links"+        <*> x .: "node_id"+        <*> x .: "original_commit_id"+        <*> x .: "original_line"+        <*> x .: "original_position"+        <*> x .: "original_start_line"+        <*> x .: "path"+        <*> x .: "position"+        <*> x .: "pull_request_review_id"+        <*> x .: "pull_request_url"+        <*> x .: "side"+        <*> x .: "start_line"+        <*> x .: "start_side"+        <*> x .: "updated_at"+        <*> x .: "url"+        <*> x .: "user"++    parseJSON _ = fail "ReviewComment"+++instance ToJSON ReviewComment where+    toJSON ReviewComment{..} = object+        [ "author_association"     .= reviewCommentAuthorAssociation+        , "body"                   .= reviewCommentBody+        , "commit_id"              .= reviewCommentCommitId+        , "created_at"             .= reviewCommentCreatedAt+        , "diff_hunk"              .= reviewCommentDiffHunk+        , "html_url"               .= reviewCommentHtmlUrl+        , "id"                     .= reviewCommentId+        , "line"                   .= reviewCommentLine+        , "_links"                 .= reviewCommentLinks+        , "node_id"                .= reviewCommentNodeId+        , "original_commit_id"     .= reviewCommentOriginalCommitId+        , "original_line"          .= reviewCommentOriginalLine+        , "original_position"      .= reviewCommentOriginalPosition+        , "original_start_line"    .= reviewCommentOriginalStartLine+        , "path"                   .= reviewCommentPath+        , "position"               .= reviewCommentPosition+        , "pull_request_review_id" .= reviewCommentPullRequestReviewId+        , "pull_request_url"       .= reviewCommentPullRequestUrl+        , "side"                   .= reviewCommentSide+        , "start_line"             .= reviewCommentStartLine+        , "start_side"             .= reviewCommentStartSide+        , "updated_at"             .= reviewCommentUpdatedAt+        , "url"                    .= reviewCommentUrl+        , "user"                   .= reviewCommentUser+        ]+++instance Arbitrary ReviewComment where+    arbitrary = ReviewComment+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/ReviewCommentLinks.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.ReviewCommentLinks where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base.Link++------------------------------------------------------------------------------+-- ReviewCommentLinks++data ReviewCommentLinks = ReviewCommentLinks+    { reviewCommentLinksHtml        :: Link+    , reviewCommentLinksSelf        :: Link+    , reviewCommentLinksPullRequest :: Link+    } deriving (Eq, Show, Read)+++instance FromJSON ReviewCommentLinks where+    parseJSON (Object x) = ReviewCommentLinks+        <$> x .: "html"+        <*> x .: "self"+        <*> x .: "pull_request"++    parseJSON _ = fail "ReviewCommentLinks"+++instance ToJSON ReviewCommentLinks where+    toJSON ReviewCommentLinks{..} = object+        [ "html"         .= reviewCommentLinksHtml+        , "self"         .= reviewCommentLinksSelf+        , "pull_request" .= reviewCommentLinksPullRequest+        ]+++instance Arbitrary ReviewCommentLinks where+    arbitrary = ReviewCommentLinks+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/ReviewLinks.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.ReviewLinks where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base.Link++------------------------------------------------------------------------------+-- ReviewLinks++data ReviewLinks = ReviewLinks+    { reviewLinksHtml        :: Link+    , reviewLinksPullRequest :: Link+    } deriving (Eq, Show, Read)+++instance FromJSON ReviewLinks where+    parseJSON (Object x) = ReviewLinks+        <$> x .: "html"+        <*> x .: "pull_request"++    parseJSON _ = fail "ReviewLinks"+++instance ToJSON ReviewLinks where+    toJSON ReviewLinks{..} = object+        [ "html"         .= reviewLinksHtml+        , "pull_request" .= reviewLinksPullRequest+        ]+++instance Arbitrary ReviewLinks where+    arbitrary = ReviewLinks+        <$> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/SimplePullRequest.hs view
@@ -0,0 +1,175 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.SimplePullRequest where++import           Data.Aeson                         (FromJSON (..), ToJSON (..),+                                                     object)+import           Data.Aeson.Types                   (Value (..), (.:), (.=))+import           Data.Text                          (Text)+import           Test.QuickCheck.Arbitrary          (Arbitrary (..))++import           GitHub.Types.Base.Commit+import           GitHub.Types.Base.DateTime+import           GitHub.Types.Base.Label+import           GitHub.Types.Base.Milestone+import           GitHub.Types.Base.PullRequestLinks+import           GitHub.Types.Base.Team+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- SimplePullRequest++data SimplePullRequest = SimplePullRequest+    { simplePullRequestState              :: Text+    , simplePullRequestReviewCommentUrl   :: Text+    , simplePullRequestAssignees          :: [User]+    , simplePullRequestAuthorAssociation  :: Text+    , simplePullRequestDraft              :: Bool+    , simplePullRequestLocked             :: Bool+    , simplePullRequestBase               :: Commit+    , simplePullRequestBody               :: Text+    , simplePullRequestHead               :: Commit+    , simplePullRequestUrl                :: Text+    , simplePullRequestMilestone          :: Maybe Milestone+    , simplePullRequestStatusesUrl        :: Text+    , simplePullRequestMergedAt           :: Maybe DateTime+    , simplePullRequestCommitsUrl         :: Text+    , simplePullRequestAssignee           :: Maybe User+    , simplePullRequestDiffUrl            :: Text+    , simplePullRequestUser               :: User+    , simplePullRequestCommentsUrl        :: Text+    , simplePullRequestLinks              :: PullRequestLinks+    , simplePullRequestUpdatedAt          :: DateTime+    , simplePullRequestPatchUrl           :: Text+    , simplePullRequestCreatedAt          :: DateTime+    , simplePullRequestId                 :: Int+    , simplePullRequestNodeId             :: Text+    , simplePullRequestIssueUrl           :: Text+    , simplePullRequestTitle              :: Text+    , simplePullRequestClosedAt           :: Maybe DateTime+    , simplePullRequestNumber             :: Int+    , simplePullRequestMergeCommitSha     :: Maybe Text+    , simplePullRequestReviewCommentsUrl  :: Text+    , simplePullRequestHtmlUrl            :: Text+    , simplePullRequestRequestedReviewers :: [User]+    , simplePullRequestRequestedTeams     :: [Team]+    , simplePullRequestLabels             :: [Label]+    } deriving (Eq, Show, Read)+++instance FromJSON SimplePullRequest where+    parseJSON (Object x) = SimplePullRequest+        <$> x .: "state"+        <*> x .: "review_comment_url"+        <*> x .: "assignees"+        <*> x .: "author_association"+        <*> x .: "draft"+        <*> x .: "locked"+        <*> x .: "base"+        <*> x .: "body"+        <*> x .: "head"+        <*> x .: "url"+        <*> x .: "milestone"+        <*> x .: "statuses_url"+        <*> x .: "merged_at"+        <*> x .: "commits_url"+        <*> x .: "assignee"+        <*> x .: "diff_url"+        <*> x .: "user"+        <*> x .: "comments_url"+        <*> x .: "_links"+        <*> x .: "updated_at"+        <*> x .: "patch_url"+        <*> x .: "created_at"+        <*> x .: "id"+        <*> x .: "node_id"+        <*> x .: "issue_url"+        <*> x .: "title"+        <*> x .: "closed_at"+        <*> x .: "number"+        <*> x .: "merge_commit_sha"+        <*> x .: "review_comments_url"+        <*> x .: "html_url"+        <*> x .: "requested_reviewers"+        <*> x .: "requested_teams"+        <*> x .: "labels"++    parseJSON _ = fail "SimplePullRequest"+++instance ToJSON SimplePullRequest where+    toJSON SimplePullRequest{..} = object+        [ "state"                .= simplePullRequestState+        , "review_comment_url"   .= simplePullRequestReviewCommentUrl+        , "assignees"            .= simplePullRequestAssignees+        , "author_association"   .= simplePullRequestAuthorAssociation+        , "draft"                .= simplePullRequestDraft+        , "locked"               .= simplePullRequestLocked+        , "base"                 .= simplePullRequestBase+        , "body"                 .= simplePullRequestBody+        , "head"                 .= simplePullRequestHead+        , "url"                  .= simplePullRequestUrl+        , "milestone"            .= simplePullRequestMilestone+        , "statuses_url"         .= simplePullRequestStatusesUrl+        , "merged_at"            .= simplePullRequestMergedAt+        , "commits_url"          .= simplePullRequestCommitsUrl+        , "assignee"             .= simplePullRequestAssignee+        , "diff_url"             .= simplePullRequestDiffUrl+        , "user"                 .= simplePullRequestUser+        , "comments_url"         .= simplePullRequestCommentsUrl+        , "_links"               .= simplePullRequestLinks+        , "updated_at"           .= simplePullRequestUpdatedAt+        , "patch_url"            .= simplePullRequestPatchUrl+        , "created_at"           .= simplePullRequestCreatedAt+        , "id"                   .= simplePullRequestId+        , "node_id"              .= simplePullRequestNodeId+        , "issue_url"            .= simplePullRequestIssueUrl+        , "title"                .= simplePullRequestTitle+        , "closed_at"            .= simplePullRequestClosedAt+        , "number"               .= simplePullRequestNumber+        , "merge_commit_sha"     .= simplePullRequestMergeCommitSha+        , "review_comments_url"  .= simplePullRequestReviewCommentsUrl+        , "html_url"             .= simplePullRequestHtmlUrl+        , "requested_reviewers"  .= simplePullRequestRequestedReviewers+        , "requested_teams"      .= simplePullRequestRequestedTeams+        , "labels"               .= simplePullRequestLabels+        ]+++instance Arbitrary SimplePullRequest where+    arbitrary = SimplePullRequest+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/SimpleRepository.hs view
@@ -0,0 +1,216 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.SimpleRepository where++import           Data.Aeson                  (FromJSON (..), ToJSON (..),+                                              object)+import           Data.Aeson.Types            (Value (..), (.:), (.=))+import           Data.Text                   (Text)+import           Test.QuickCheck.Arbitrary   (Arbitrary (..))++import           GitHub.Types.Base.RepoOwner++------------------------------------------------------------------------------+-- SimpleRepository++data SimpleRepository = SimpleRepository+    { simpleRepositoryArchiveUrl       :: Text+    , simpleRepositoryAssigneesUrl     :: Text+    , simpleRepositoryBlobsUrl         :: Text+    , simpleRepositoryBranchesUrl      :: Text+    , simpleRepositoryCollaboratorsUrl :: Text+    , simpleRepositoryCommentsUrl      :: Text+    , simpleRepositoryCommitsUrl       :: Text+    , simpleRepositoryCompareUrl       :: Text+    , simpleRepositoryContentsUrl      :: Text+    , simpleRepositoryContributorsUrl  :: Text+    , simpleRepositoryDeploymentsUrl   :: Text+    , simpleRepositoryDescription      :: Maybe Text+    , simpleRepositoryDownloadsUrl     :: Text+    , simpleRepositoryEventsUrl        :: Text+    , simpleRepositoryFork             :: Bool+    , simpleRepositoryForksUrl         :: Text+    , simpleRepositoryFullName         :: Text+    , simpleRepositoryGitCommitsUrl    :: Text+    , simpleRepositoryGitRefsUrl       :: Text+    , simpleRepositoryGitTagsUrl       :: Text+    , simpleRepositoryHooksUrl         :: Text+    , simpleRepositoryHtmlUrl          :: Text+    , simpleRepositoryId               :: Int+    , simpleRepositoryIssueCommentUrl  :: Text+    , simpleRepositoryIssueEventsUrl   :: Text+    , simpleRepositoryIssuesUrl        :: Text+    , simpleRepositoryKeysUrl          :: Text+    , simpleRepositoryLabelsUrl        :: Text+    , simpleRepositoryLanguagesUrl     :: Text+    , simpleRepositoryMergesUrl        :: Text+    , simpleRepositoryMilestonesUrl    :: Text+    , simpleRepositoryName             :: Text+    , simpleRepositoryNodeId           :: Text+    , simpleRepositoryNotificationsUrl :: Text+    , simpleRepositoryOwner            :: RepoOwner+    , simpleRepositoryPrivate          :: Bool+    , simpleRepositoryPullsUrl         :: Text+    , simpleRepositoryReleasesUrl      :: Text+    , simpleRepositoryStargazersUrl    :: Text+    , simpleRepositoryStatusesUrl      :: Text+    , simpleRepositorySubscribersUrl   :: Text+    , simpleRepositorySubscriptionUrl  :: Text+    , simpleRepositoryTagsUrl          :: Text+    , simpleRepositoryTeamsUrl         :: Text+    , simpleRepositoryTreesUrl         :: Text+    , simpleRepositoryUrl              :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON SimpleRepository where+    parseJSON (Object x) = SimpleRepository+        <$> x .: "archive_url"+        <*> x .: "assignees_url"+        <*> x .: "blobs_url"+        <*> x .: "branches_url"+        <*> x .: "collaborators_url"+        <*> x .: "comments_url"+        <*> x .: "commits_url"+        <*> x .: "compare_url"+        <*> x .: "contents_url"+        <*> x .: "contributors_url"+        <*> x .: "deployments_url"+        <*> x .: "description"+        <*> x .: "downloads_url"+        <*> x .: "events_url"+        <*> x .: "fork"+        <*> x .: "forks_url"+        <*> x .: "full_name"+        <*> x .: "git_commits_url"+        <*> x .: "git_refs_url"+        <*> x .: "git_tags_url"+        <*> x .: "hooks_url"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "issue_comment_url"+        <*> x .: "issue_events_url"+        <*> x .: "issues_url"+        <*> x .: "keys_url"+        <*> x .: "labels_url"+        <*> x .: "languages_url"+        <*> x .: "merges_url"+        <*> x .: "milestones_url"+        <*> x .: "name"+        <*> x .: "node_id"+        <*> x .: "notifications_url"+        <*> x .: "owner"+        <*> x .: "private"+        <*> x .: "pulls_url"+        <*> x .: "releases_url"+        <*> x .: "stargazers_url"+        <*> x .: "statuses_url"+        <*> x .: "subscribers_url"+        <*> x .: "subscription_url"+        <*> x .: "tags_url"+        <*> x .: "teams_url"+        <*> x .: "trees_url"+        <*> x .: "url"++    parseJSON _ = fail "SimpleRepository"++instance ToJSON SimpleRepository where+    toJSON SimpleRepository{..} = object+        [ "archive_url"       .= simpleRepositoryArchiveUrl+        , "assignees_url"     .= simpleRepositoryAssigneesUrl+        , "blobs_url"         .= simpleRepositoryBlobsUrl+        , "branches_url"      .= simpleRepositoryBranchesUrl+        , "collaborators_url" .= simpleRepositoryCollaboratorsUrl+        , "comments_url"      .= simpleRepositoryCommentsUrl+        , "commits_url"       .= simpleRepositoryCommitsUrl+        , "compare_url"       .= simpleRepositoryCompareUrl+        , "contents_url"      .= simpleRepositoryContentsUrl+        , "contributors_url"  .= simpleRepositoryContributorsUrl+        , "deployments_url"   .= simpleRepositoryDeploymentsUrl+        , "description"       .= simpleRepositoryDescription+        , "downloads_url"     .= simpleRepositoryDownloadsUrl+        , "events_url"        .= simpleRepositoryEventsUrl+        , "fork"              .= simpleRepositoryFork+        , "forks_url"         .= simpleRepositoryForksUrl+        , "full_name"         .= simpleRepositoryFullName+        , "git_commits_url"   .= simpleRepositoryGitCommitsUrl+        , "git_refs_url"      .= simpleRepositoryGitRefsUrl+        , "git_tags_url"      .= simpleRepositoryGitTagsUrl+        , "hooks_url"         .= simpleRepositoryHooksUrl+        , "html_url"          .= simpleRepositoryHtmlUrl+        , "id"                .= simpleRepositoryId+        , "issue_comment_url" .= simpleRepositoryIssueCommentUrl+        , "issue_events_url"  .= simpleRepositoryIssueEventsUrl+        , "issues_url"        .= simpleRepositoryIssuesUrl+        , "keys_url"          .= simpleRepositoryKeysUrl+        , "labels_url"        .= simpleRepositoryLabelsUrl+        , "languages_url"     .= simpleRepositoryLanguagesUrl+        , "merges_url"        .= simpleRepositoryMergesUrl+        , "milestones_url"    .= simpleRepositoryMilestonesUrl+        , "name"              .= simpleRepositoryName+        , "node_id"           .= simpleRepositoryNodeId+        , "notifications_url" .= simpleRepositoryNotificationsUrl+        , "owner"             .= simpleRepositoryOwner+        , "private"           .= simpleRepositoryPrivate+        , "pulls_url"         .= simpleRepositoryPullsUrl+        , "releases_url"      .= simpleRepositoryReleasesUrl+        , "stargazers_url"    .= simpleRepositoryStargazersUrl+        , "statuses_url"      .= simpleRepositoryStatusesUrl+        , "subscribers_url"   .= simpleRepositorySubscribersUrl+        , "subscription_url"  .= simpleRepositorySubscriptionUrl+        , "tags_url"          .= simpleRepositoryTagsUrl+        , "teams_url"         .= simpleRepositoryTeamsUrl+        , "trees_url"         .= simpleRepositoryTreesUrl+        , "url"               .= simpleRepositoryUrl+        ]+++instance Arbitrary SimpleRepository where+    arbitrary = SimpleRepository+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/StatusCommit.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.StatusCommit where++import           Data.Aeson                      (FromJSON (..), ToJSON (..),+                                                  object)+import           Data.Aeson.Types                (Value (..), (.:), (.=))+import           Data.Text                       (Text)+import           Test.QuickCheck.Arbitrary       (Arbitrary (..))++import           GitHub.Types.Base.CommitDetails+import           GitHub.Types.Base.CommitRefHtml+import           GitHub.Types.Base.User++------------------------------------------------------------------------------+-- StatusCommit++data StatusCommit = StatusCommit+    { statusCommitAuthor      :: Maybe User+    , statusCommitCommentsUrl :: Text+    , statusCommitCommit      :: CommitDetails+    , statusCommitCommitter   :: Maybe User+    , statusCommitHtmlUrl     :: Text+    , statusCommitNodeId      :: Text+    , statusCommitParents     :: [CommitRefHtml]+    , statusCommitSha         :: Text+    , statusCommitUrl         :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON StatusCommit where+    parseJSON (Object x) = StatusCommit+        <$> x .: "author"+        <*> x .: "comments_url"+        <*> x .: "commit"+        <*> x .: "committer"+        <*> x .: "html_url"+        <*> x .: "node_id"+        <*> x .: "parents"+        <*> x .: "sha"+        <*> x .: "url"++    parseJSON _ = fail "StatusCommit"+++instance ToJSON StatusCommit where+    toJSON StatusCommit{..} = object+        [ "author"       .= statusCommitAuthor+        , "comments_url" .= statusCommitCommentsUrl+        , "commit"       .= statusCommitCommit+        , "committer"    .= statusCommitCommitter+        , "html_url"     .= statusCommitHtmlUrl+        , "node_id"      .= statusCommitNodeId+        , "parents"      .= statusCommitParents+        , "sha"          .= statusCommitSha+        , "url"          .= statusCommitUrl+        ]+++instance Arbitrary StatusCommit where+    arbitrary = StatusCommit+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Team.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Team where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- Team++data Team = Team+    { teamDescription     :: Text+    , teamId              :: Int+    , teamHtmlUrl         :: Text+    , teamMembersUrl      :: Text+    , teamName            :: Text+    , teamNodeId          :: Text+    , teamParent          :: Maybe Team+    , teamPermission      :: Text+    , teamPrivacy         :: Text+    , teamRepositoriesUrl :: Text+    , teamSlug            :: Text+    , teamUrl             :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON Team where+    parseJSON (Object x) = Team+        <$> x .: "description"+        <*> x .: "id"+        <*> x .: "html_url"+        <*> x .: "members_url"+        <*> x .: "name"+        <*> x .: "node_id"+        <*> x .:? "parent"+        <*> x .: "permission"+        <*> x .: "privacy"+        <*> x .: "repositories_url"+        <*> x .: "slug"+        <*> x .: "url"++    parseJSON _ = fail "Team"+++instance ToJSON Team where+    toJSON Team{..} = object+        [ "description"      .= teamDescription+        , "id"               .= teamId+        , "html_url"         .= teamHtmlUrl+        , "members_url"      .= teamMembersUrl+        , "name"             .= teamName+        , "node_id"          .= teamNodeId+        , "parent"           .= teamParent+        , "permission"       .= teamPermission+        , "privacy"          .= teamPrivacy+        , "repositories_url" .= teamRepositoriesUrl+        , "slug"             .= teamSlug+        , "url"              .= teamUrl+        ]+++instance Arbitrary Team where+    arbitrary = Team+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/User.hs view
@@ -0,0 +1,111 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.User where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- User++data User = User+    { userAvatarUrl         :: Text+    , userEmail             :: Maybe Text+    , userEventsUrl         :: Text+    , userFollowersUrl      :: Text+    , userFollowingUrl      :: Text+    , userGistsUrl          :: Text+    , userGravatarId        :: Text+    , userHtmlUrl           :: Text+    , userId                :: Int+    , userLogin             :: Text+    , userName              :: Maybe Text+    , userNodeId            :: Text+    , userOrganizationsUrl  :: Text+    , userReceivedEventsUrl :: Text+    , userReposUrl          :: Text+    , userSiteAdmin         :: Bool+    , userStarredUrl        :: Text+    , userSubscriptionsUrl  :: Text+    , userType              :: Text+    , userUrl               :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON User where+    parseJSON (Object x) = User+        <$> x .: "avatar_url"+        <*> x .:? "email"+        <*> x .: "events_url"+        <*> x .: "followers_url"+        <*> x .: "following_url"+        <*> x .: "gists_url"+        <*> x .: "gravatar_id"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "login"+        <*> x .:? "name"+        <*> x .: "node_id"+        <*> x .: "organizations_url"+        <*> x .: "received_events_url"+        <*> x .: "repos_url"+        <*> x .: "site_admin"+        <*> x .: "starred_url"+        <*> x .: "subscriptions_url"+        <*> x .: "type"+        <*> x .: "url"++    parseJSON _ = fail "User"+++instance ToJSON User where+    toJSON User{..} = object+        [ "avatar_url"          .= userAvatarUrl+        , "email"               .= userEmail+        , "events_url"          .= userEventsUrl+        , "followers_url"       .= userFollowersUrl+        , "following_url"       .= userFollowingUrl+        , "gists_url"           .= userGistsUrl+        , "gravatar_id"         .= userGravatarId+        , "html_url"            .= userHtmlUrl+        , "id"                  .= userId+        , "login"               .= userLogin+        , "name"                .= userName+        , "node_id"             .= userNodeId+        , "organizations_url"   .= userOrganizationsUrl+        , "received_events_url" .= userReceivedEventsUrl+        , "repos_url"           .= userReposUrl+        , "site_admin"          .= userSiteAdmin+        , "starred_url"         .= userStarredUrl+        , "subscriptions_url"   .= userSubscriptionsUrl+        , "type"                .= userType+        , "url"                 .= userUrl+        ]+++instance Arbitrary User where+    arbitrary = User+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/UserRef.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.UserRef where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- UserRef++data UserRef = UserRef+    { userRefName  :: Text+    , userRefEmail :: Maybe Text+    } deriving (Eq, Show, Read)+++instance FromJSON UserRef where+    parseJSON (Object x) = UserRef+        <$> x .: "name"+        <*> x .: "email"++    parseJSON _ = fail "UserRef"+++instance ToJSON UserRef where+    toJSON UserRef{..} = object+        [ "name"  .= userRefName+        , "email" .= userRefEmail+        ]+++instance Arbitrary UserRef where+    arbitrary = UserRef+        <$> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/UserStamp.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.UserStamp where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- UserStamp++data UserStamp = UserStamp+    { userStampName  :: Text+    , userStampEmail :: Text+    , userStampDate  :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON UserStamp where+    parseJSON (Object x) = UserStamp+        <$> x .: "name"+        <*> x .: "email"+        <*> x .: "date"++    parseJSON _ = fail "UserStamp"+++instance ToJSON UserStamp where+    toJSON UserStamp{..} = object+        [ "name"  .= userStampName+        , "email" .= userStampEmail+        , "date"  .= userStampDate+        ]+++instance Arbitrary UserStamp where+    arbitrary = UserStamp+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Verification.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Verification where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- Verification++data Verification = Verification+    { verificationPayload   :: Maybe Text+    , verificationReason    :: Text+    , verificationSignature :: Maybe Text+    , verificationVerified  :: Bool+    } deriving (Eq, Show, Read)+++instance FromJSON Verification where+    parseJSON (Object x) = Verification+        <$> x .: "payload"+        <*> x .: "reason"+        <*> x .: "signature"+        <*> x .: "verified"++    parseJSON _ = fail "Verification"+++instance ToJSON Verification where+    toJSON Verification{..} = object+        [ "payload"   .= verificationPayload+        , "reason"    .= verificationReason+        , "signature" .= verificationSignature+        , "verified"  .= verificationVerified+        ]++instance Arbitrary Verification where+    arbitrary = Verification+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/Workflow.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.Workflow where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- Workflow++data Workflow = Workflow+    { workflowBadgeUrl  :: Text+    , workflowCreatedAt :: Text+    , workflowHtmlUrl   :: Text+    , workflowId        :: Int+    , workflowName      :: Text+    , workflowNodeId    :: Text+    , workflowPath      :: Text+    , workflowState     :: Text+    , workflowUpdatedAt :: Text+    , workflowUrl       :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON Workflow where+    parseJSON (Object x) = Workflow+        <$> x .: "badge_url"+        <*> x .: "created_at"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "name"+        <*> x .: "node_id"+        <*> x .: "path"+        <*> x .: "state"+        <*> x .: "updated_at"+        <*> x .: "url"++    parseJSON _ = fail "Workflow"+++instance ToJSON Workflow where+    toJSON Workflow{..} = object+        [ "badge_url"  .= workflowBadgeUrl+        , "created_at" .= workflowCreatedAt+        , "html_url"   .= workflowHtmlUrl+        , "id"         .= workflowId+        , "name"       .= workflowName+        , "node_id"    .= workflowNodeId+        , "path"       .= workflowPath+        , "state"      .= workflowState+        , "updated_at" .= workflowUpdatedAt+        , "url"        .= workflowUrl+        ]+++instance Arbitrary Workflow where+    arbitrary = Workflow+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/WorkflowJob.hs view
@@ -0,0 +1,113 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.WorkflowJob where++import           Data.Aeson                     (FromJSON (..), ToJSON (..),+                                                 object)+import           Data.Aeson.Types               (Value (..), (.:), (.=))+import           Data.Text                      (Text)+import           Test.QuickCheck.Arbitrary      (Arbitrary (..))++import           GitHub.Types.Base.WorkflowStep++------------------------------------------------------------------------------+-- WorkflowJob++data WorkflowJob = WorkflowJob+    { workflowJobConclusion      :: Maybe Text+    , workflowJobHeadSha         :: Text+    , workflowJobRunAttempt      :: Int+    , workflowJobRunId           :: Int+    , workflowJobRunUrl          :: Text+    , workflowJobCheckRunUrl     :: Text+    , workflowJobHtmlUrl         :: Text+    , workflowJobId              :: Int+    , workflowJobNodeId          :: Text+    , workflowJobName            :: Text+    , workflowJobLabels          :: [Text]+    , workflowJobSteps           :: [WorkflowStep]+    , workflowJobStatus          :: Text+    , workflowJobUrl             :: Text+    , workflowJobStartedAt       :: Text+    , workflowJobCompletedAt     :: Maybe Text+    , workflowJobRunnerId        :: Maybe Int+    , workflowJobRunnerName      :: Maybe Text+    , workflowJobRunnerGroupId   :: Maybe Int+    , workflowJobRunnerGroupName :: Maybe Text+    } deriving (Eq, Show, Read)+++instance FromJSON WorkflowJob where+    parseJSON (Object x) = WorkflowJob+        <$> x .: "conclusion"+        <*> x .: "head_sha"+        <*> x .: "run_attempt"+        <*> x .: "run_id"+        <*> x .: "run_url"+        <*> x .: "check_run_url"+        <*> x .: "html_url"+        <*> x .: "id"+        <*> x .: "node_id"+        <*> x .: "name"+        <*> x .: "labels"+        <*> x .: "steps"+        <*> x .: "status"+        <*> x .: "url"+        <*> x .: "started_at"+        <*> x .: "completed_at"+        <*> x .: "runner_id"+        <*> x .: "runner_name"+        <*> x .: "runner_group_id"+        <*> x .: "runner_group_name"++    parseJSON _ = fail "WorkflowJob"+++instance ToJSON WorkflowJob where+    toJSON WorkflowJob{..} = object+        [ "conclusion"        .= workflowJobConclusion+        , "head_sha"          .= workflowJobHeadSha+        , "run_attempt"       .= workflowJobRunAttempt+        , "run_id"            .= workflowJobRunId+        , "run_url"           .= workflowJobRunUrl+        , "check_run_url"     .= workflowJobCheckRunUrl+        , "html_url"          .= workflowJobHtmlUrl+        , "id"                .= workflowJobId+        , "node_id"           .= workflowJobNodeId+        , "name"              .= workflowJobName+        , "labels"            .= workflowJobLabels+        , "steps"             .= workflowJobSteps+        , "status"            .= workflowJobStatus+        , "url"               .= workflowJobUrl+        , "started_at"        .= workflowJobStartedAt+        , "completed_at"      .= workflowJobCompletedAt+        , "runner_id"         .= workflowJobRunnerId+        , "runner_name"       .= workflowJobRunnerName+        , "runner_group_id"   .= workflowJobRunnerGroupId+        , "runner_group_name" .= workflowJobRunnerGroupName+        ]+++instance Arbitrary WorkflowJob where+    arbitrary = WorkflowJob+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/WorkflowRun.hs view
@@ -0,0 +1,155 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.WorkflowRun where++import           Data.Aeson                         (FromJSON (..), ToJSON (..),+                                                     object)+import           Data.Aeson.Types                   (Value (..), (.:), (.=))+import           Data.Text                          (Text)+import           Test.QuickCheck.Arbitrary          (Arbitrary (..))++import           GitHub.Types.Base.CheckCommit+import           GitHub.Types.Base.CheckPullRequest+import           GitHub.Types.Base.SimpleRepository++------------------------------------------------------------------------------+-- WorkflowRun++data WorkflowRun = WorkflowRun+    { workflowRunConclusion         :: Maybe Text+    , workflowRunRepository         :: SimpleRepository+    , workflowRunHeadRepository     :: SimpleRepository+    , workflowRunHeadBranch         :: Text+    , workflowRunHeadCommit         :: CheckCommit+    , workflowRunHeadSha            :: Text+    , workflowRunId                 :: Int+    , workflowRunWorkflowId         :: Int+    , workflowRunNodeId             :: Text+    , workflowRunCheckSuiteId       :: Int+    , workflowRunCheckSuiteNodeId   :: Text+    , workflowRunPullRequests       :: [CheckPullRequest]+    , workflowRunStatus             :: Text+    , workflowRunUrl                :: Text+    , workflowRunJobsUrl            :: Text+    , workflowRunLogsUrl            :: Text+    , workflowRunCheckSuiteUrl      :: Text+    , workflowRunArtifactsUrl       :: Text+    , workflowRunCancelUrl          :: Text+    , workflowRunPreviousAttemptUrl :: Maybe Text+    , workflowRunWorkflowUrl        :: Text+    , workflowRunRerunUrl           :: Text+    , workflowRunHtmlUrl            :: Text+    , workflowRunRunStartedAt       :: Text+    , workflowRunUpdatedAt          :: Text+    , workflowRunCreatedAt          :: Text+    , workflowRunRunNumber          :: Int+    , workflowRunRunAttempt         :: Int+    , workflowRunEvent              :: Text+    , workflowRunName               :: Text+    } deriving (Eq, Show, Read)+++instance FromJSON WorkflowRun where+    parseJSON (Object x) = WorkflowRun+        <$> x .: "conclusion"+        <*> x .: "repository"+        <*> x .: "head_repository"+        <*> x .: "head_branch"+        <*> x .: "head_commit"+        <*> x .: "head_sha"+        <*> x .: "id"+        <*> x .: "workflow_id"+        <*> x .: "node_id"+        <*> x .: "check_suite_id"+        <*> x .: "check_suite_node_id"+        <*> x .: "pull_requests"+        <*> x .: "status"+        <*> x .: "url"+        <*> x .: "jobs_url"+        <*> x .: "logs_url"+        <*> x .: "check_suite_url"+        <*> x .: "artifacts_url"+        <*> x .: "cancel_url"+        <*> x .: "previous_attempt_url"+        <*> x .: "workflow_url"+        <*> x .: "rerun_url"+        <*> x .: "html_url"+        <*> x .: "run_started_at"+        <*> x .: "updated_at"+        <*> x .: "created_at"+        <*> x .: "run_number"+        <*> x .: "run_attempt"+        <*> x .: "event"+        <*> x .: "name"++    parseJSON _ = fail "WorkflowRun"+++instance ToJSON WorkflowRun where+    toJSON WorkflowRun{..} = object+        [ "conclusion"              .= workflowRunConclusion+        , "repository"              .= workflowRunRepository+        , "head_repository"         .= workflowRunHeadRepository+        , "head_branch"             .= workflowRunHeadBranch+        , "head_commit"             .= workflowRunHeadCommit+        , "head_sha"                .= workflowRunHeadSha+        , "id"                      .= workflowRunId+        , "workflow_id"             .= workflowRunWorkflowId+        , "node_id"                 .= workflowRunNodeId+        , "check_suite_id"          .= workflowRunCheckSuiteId+        , "check_suite_node_id"     .= workflowRunCheckSuiteNodeId+        , "pull_requests"           .= workflowRunPullRequests+        , "status"                  .= workflowRunStatus+        , "url"                     .= workflowRunUrl+        , "jobs_url"                .= workflowRunJobsUrl+        , "logs_url"                .= workflowRunLogsUrl+        , "check_suite_url"         .= workflowRunCheckSuiteUrl+        , "artifacts_url"           .= workflowRunArtifactsUrl+        , "cancel_url"              .= workflowRunCancelUrl+        , "previous_attempt_url"    .= workflowRunPreviousAttemptUrl+        , "workflow_url"            .= workflowRunWorkflowUrl+        , "rerun_url"               .= workflowRunRerunUrl+        , "html_url"                .= workflowRunHtmlUrl+        , "run_started_at"          .= workflowRunRunStartedAt+        , "updated_at"              .= workflowRunUpdatedAt+        , "created_at"              .= workflowRunCreatedAt+        , "run_number"              .= workflowRunRunNumber+        , "run_attempt"             .= workflowRunRunAttempt+        , "event"                   .= workflowRunEvent+        , "name"                    .= workflowRunName+        ]+++instance Arbitrary WorkflowRun where+    arbitrary = WorkflowRun+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Base/WorkflowStep.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Base.WorkflowStep where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.=))+import           Data.Text                 (Text)+import           Data.Text.Arbitrary       ()+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++------------------------------------------------------------------------------+-- WorkflowStep++data WorkflowStep = WorkflowStep+    { workflowStepName        :: Text+    , workflowStepStatus      :: Text+    , workflowStepConclusion  :: Maybe Text+    , workflowStepNumber      :: Int+    , workflowStepStartedAt   :: Maybe Text+    , workflowStepCompletedAt :: Maybe Text+    } deriving (Eq, Show, Read)+++instance FromJSON WorkflowStep where+    parseJSON (Object x) = WorkflowStep+        <$> x .: "name"+        <*> x .: "status"+        <*> x .: "conclusion"+        <*> x .: "number"+        <*> x .: "started_at"+        <*> x .: "completed_at"++    parseJSON _ = fail "WorkflowStep"+++instance ToJSON WorkflowStep where+    toJSON WorkflowStep{..} = object+        [ "name"         .= workflowStepName+        , "status"       .= workflowStepStatus+        , "conclusion"   .= workflowStepConclusion+        , "number"       .= workflowStepNumber+        , "started_at"   .= workflowStepStartedAt+        , "completed_at" .= workflowStepCompletedAt+        ]+++instance Arbitrary WorkflowStep where+    arbitrary = WorkflowStep+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Event.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE StrictData #-}+module GitHub.Types.Event where++import           Data.Text (Text)+++newtype TypeName  a = TypeName  Text+newtype EventName a = EventName Text++class Event a where+    typeName  :: TypeName a+    eventName :: EventName a
+ src/GitHub/Types/Events.hs view
@@ -0,0 +1,31 @@+module GitHub.Types.Events (module X) where++import           GitHub.Types.Events.CheckRunEvent                 as X+import           GitHub.Types.Events.CheckSuiteEvent               as X+import           GitHub.Types.Events.CommitCommentEvent            as X+import           GitHub.Types.Events.CreateEvent                   as X+import           GitHub.Types.Events.DeleteEvent                   as X+import           GitHub.Types.Events.DeploymentEvent               as X+import           GitHub.Types.Events.DeploymentStatusEvent         as X+import           GitHub.Types.Events.ForkEvent                     as X+import           GitHub.Types.Events.GollumEvent                   as X+import           GitHub.Types.Events.IssueCommentEvent             as X+import           GitHub.Types.Events.IssuesEvent                   as X+import           GitHub.Types.Events.LabelEvent                    as X+import           GitHub.Types.Events.MemberEvent                   as X+import           GitHub.Types.Events.MembershipEvent               as X+import           GitHub.Types.Events.MilestoneEvent                as X+import           GitHub.Types.Events.OrganizationEvent             as X+import           GitHub.Types.Events.PageBuildEvent                as X+import           GitHub.Types.Events.PingEvent                     as X+import           GitHub.Types.Events.PullRequestEvent              as X+import           GitHub.Types.Events.PullRequestReviewCommentEvent as X+import           GitHub.Types.Events.PullRequestReviewEvent        as X+import           GitHub.Types.Events.PushEvent                     as X+import           GitHub.Types.Events.ReleaseEvent                  as X+import           GitHub.Types.Events.RepositoryEvent               as X+import           GitHub.Types.Events.StarEvent                     as X+import           GitHub.Types.Events.StatusEvent                   as X+import           GitHub.Types.Events.WatchEvent                    as X+import           GitHub.Types.Events.WorkflowJobEvent              as X+import           GitHub.Types.Events.WorkflowRunEvent              as X
+ src/GitHub/Types/Events/CheckRunEvent.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.CheckRunEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data CheckRunEvent = CheckRunEvent+    { checkRunEventInstallation :: Maybe Installation+    , checkRunEventOrganization :: Organization+    , checkRunEventRepository   :: Repository+    , checkRunEventSender       :: User++    , checkRunEventAction       :: Text+    , checkRunEventCheckRun     :: CheckRun+    } deriving (Eq, Show, Read)++instance Event CheckRunEvent where+    typeName = TypeName "CheckRunEvent"+    eventName = EventName "check_run"++instance FromJSON CheckRunEvent where+    parseJSON (Object x) = CheckRunEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .: "check_run"++    parseJSON _ = fail "CheckRunEvent"++instance ToJSON CheckRunEvent where+    toJSON CheckRunEvent{..} = object+        [ "installation" .= checkRunEventInstallation+        , "organization" .= checkRunEventOrganization+        , "repository"   .= checkRunEventRepository+        , "sender"       .= checkRunEventSender++        , "action"       .= checkRunEventAction+        , "check_run"    .= checkRunEventCheckRun+        ]+++instance Arbitrary CheckRunEvent where+    arbitrary = CheckRunEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/CheckSuiteEvent.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.CheckSuiteEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data CheckSuiteEvent = CheckSuiteEvent+    { checkSuiteEventInstallation :: Maybe Installation+    , checkSuiteEventOrganization :: Organization+    , checkSuiteEventRepository   :: Repository+    , checkSuiteEventSender       :: User++    , checkSuiteEventAction       :: Text+    , checkSuiteEventCheckSuite   :: CheckSuite+    } deriving (Eq, Show, Read)++instance Event CheckSuiteEvent where+    typeName = TypeName "CheckSuiteEvent"+    eventName = EventName "check_suite"++instance FromJSON CheckSuiteEvent where+    parseJSON (Object x) = CheckSuiteEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .: "check_suite"++    parseJSON _ = fail "CheckSuiteEvent"++instance ToJSON CheckSuiteEvent where+    toJSON CheckSuiteEvent{..} = object+        [ "installation" .= checkSuiteEventInstallation+        , "organization" .= checkSuiteEventOrganization+        , "repository"   .= checkSuiteEventRepository+        , "sender"       .= checkSuiteEventSender++        , "action"       .= checkSuiteEventAction+        , "check_suite"  .= checkSuiteEventCheckSuite+        ]+++instance Arbitrary CheckSuiteEvent where+    arbitrary = CheckSuiteEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/CommitCommentEvent.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.CommitCommentEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data CommitCommentEvent = CommitCommentEvent+    { commitCommentEventInstallation :: Maybe Installation+    , commitCommentEventOrganization :: Organization+    , commitCommentEventRepository   :: Repository+    , commitCommentEventSender       :: User++    , commitCommentEventAction       :: Text+    , commitCommentEventComment      :: CommitComment+    } deriving (Eq, Show, Read)++instance Event CommitCommentEvent where+    typeName = TypeName "CommitCommentEvent"+    eventName = EventName "commit_comment"++instance FromJSON CommitCommentEvent where+    parseJSON (Object x) = CommitCommentEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .: "comment"++    parseJSON _ = fail "CommitCommentEvent"++instance ToJSON CommitCommentEvent where+    toJSON CommitCommentEvent{..} = object+        [ "installation" .= commitCommentEventInstallation+        , "organization" .= commitCommentEventOrganization+        , "repository"   .= commitCommentEventRepository+        , "sender"       .= commitCommentEventSender++        , "action"       .= commitCommentEventAction+        , "comment"      .= commitCommentEventComment+        ]+++instance Arbitrary CommitCommentEvent where+    arbitrary = CommitCommentEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/CreateEvent.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.CreateEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data CreateEvent = CreateEvent+    { createEventInstallation :: Maybe Installation+    , createEventOrganization :: Organization+    , createEventRepository   :: Repository+    , createEventSender       :: User++    , createEventDescription  :: Text+    , createEventMasterBranch :: Text+    , createEventPusherType   :: Text+    , createEventRef          :: Text+    , createEventRefType      :: Text+    } deriving (Eq, Show, Read)++instance Event CreateEvent where+    typeName = TypeName "CreateEvent"+    eventName = EventName "create"++instance FromJSON CreateEvent where+    parseJSON (Object x) = CreateEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "description"+        <*> x .: "master_branch"+        <*> x .: "pusher_type"+        <*> x .: "ref"+        <*> x .: "ref_type"++    parseJSON _ = fail "CreateEvent"++instance ToJSON CreateEvent where+    toJSON CreateEvent{..} = object+        [ "installation"  .= createEventInstallation+        , "organization"  .= createEventOrganization+        , "repository"    .= createEventRepository+        , "sender"        .= createEventSender++        , "description"   .= createEventDescription+        , "master_branch" .= createEventMasterBranch+        , "pusher_type"   .= createEventPusherType+        , "ref"           .= createEventRef+        , "ref_type"      .= createEventRefType+        ]+++instance Arbitrary CreateEvent where+    arbitrary = CreateEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/DeleteEvent.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.DeleteEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data DeleteEvent = DeleteEvent+    { deleteEventInstallation :: Maybe Installation+    , deleteEventOrganization :: Organization+    , deleteEventRepository   :: Repository+    , deleteEventSender       :: User++    , deleteEventPusherType   :: Text+    , deleteEventRef          :: Text+    , deleteEventRefType      :: Text+    } deriving (Eq, Show, Read)++instance Event DeleteEvent where+    typeName = TypeName "DeleteEvent"+    eventName = EventName "delete"++instance FromJSON DeleteEvent where+    parseJSON (Object x) = DeleteEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "pusher_type"+        <*> x .: "ref"+        <*> x .: "ref_type"++    parseJSON _ = fail "DeleteEvent"++instance ToJSON DeleteEvent where+    toJSON DeleteEvent{..} = object+        [ "installation" .= deleteEventInstallation+        , "organization" .= deleteEventOrganization+        , "repository"   .= deleteEventRepository+        , "sender"       .= deleteEventSender++        , "pusher_type"  .= deleteEventPusherType+        , "ref"          .= deleteEventRef+        , "ref_type"     .= deleteEventRefType+        ]+++instance Arbitrary DeleteEvent where+    arbitrary = DeleteEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/DeploymentEvent.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.DeploymentEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data DeploymentEvent = DeploymentEvent+    { deploymentEventInstallation :: Maybe Installation+    , deploymentEventOrganization :: Organization+    , deploymentEventRepository   :: Repository+    , deploymentEventSender       :: User++    , deploymentEventAction       :: Text+    , deploymentEventDeployment   :: Deployment+    } deriving (Eq, Show, Read)++instance Event DeploymentEvent where+    typeName = TypeName "DeploymentEvent"+    eventName = EventName "deployment"++instance FromJSON DeploymentEvent where+    parseJSON (Object x) = DeploymentEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .: "deployment"++    parseJSON _ = fail "DeploymentEvent"++instance ToJSON DeploymentEvent where+    toJSON DeploymentEvent{..} = object+        [ "installation" .= deploymentEventInstallation+        , "organization" .= deploymentEventOrganization+        , "repository"   .= deploymentEventRepository+        , "sender"       .= deploymentEventSender++        , "action"       .= deploymentEventAction+        , "deployment"   .= deploymentEventDeployment+        ]+++instance Arbitrary DeploymentEvent where+    arbitrary = DeploymentEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/DeploymentStatusEvent.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.DeploymentStatusEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data DeploymentStatusEvent = DeploymentStatusEvent+    { deploymentStatusEventInstallation     :: Maybe Installation+    , deploymentStatusEventOrganization     :: Organization+    , deploymentStatusEventRepository       :: Repository+    , deploymentStatusEventSender           :: User++    , deploymentStatusEventAction           :: Text+    , deploymentStatusEventDeployment       :: Deployment+    , deploymentStatusEventDeploymentStatus :: DeploymentStatus+    } deriving (Eq, Show, Read)++instance Event DeploymentStatusEvent where+    typeName = TypeName "DeploymentStatusEvent"+    eventName = EventName "deployment_status"++instance FromJSON DeploymentStatusEvent where+    parseJSON (Object x) = DeploymentStatusEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .: "deployment"+        <*> x .: "deployment_status"++    parseJSON _ = fail "DeploymentStatusEvent"++instance ToJSON DeploymentStatusEvent where+    toJSON DeploymentStatusEvent{..} = object+        [ "installation"       .= deploymentStatusEventInstallation+        , "organization"       .= deploymentStatusEventOrganization+        , "repository"         .= deploymentStatusEventRepository+        , "sender"             .= deploymentStatusEventSender++        , "action"             .= deploymentStatusEventAction+        , "deployment"         .= deploymentStatusEventDeployment+        , "deployment_status"  .= deploymentStatusEventDeploymentStatus+        ]+++instance Arbitrary DeploymentStatusEvent where+    arbitrary = DeploymentStatusEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/ForkEvent.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.ForkEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data ForkEvent = ForkEvent+    { forkEventInstallation :: Maybe Installation+    , forkEventOrganization :: Organization+    , forkEventRepository   :: Repository+    , forkEventSender       :: User++    , forkEventForkee       :: Repository+    } deriving (Eq, Show, Read)++instance Event ForkEvent where+    typeName = TypeName "ForkEvent"+    eventName = EventName "fork"++instance FromJSON ForkEvent where+    parseJSON (Object x) = ForkEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "forkee"++    parseJSON _ = fail "ForkEvent"++instance ToJSON ForkEvent where+    toJSON ForkEvent{..} = object+        [ "installation" .= forkEventInstallation+        , "organization" .= forkEventOrganization+        , "repository"   .= forkEventRepository+        , "sender"       .= forkEventSender++        , "forkee"       .= forkEventForkee+        ]+++instance Arbitrary ForkEvent where+    arbitrary = ForkEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary
+ src/GitHub/Types/Events/GollumEvent.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.GollumEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data GollumEvent = GollumEvent+    { gollumEventInstallation :: Maybe Installation+    , gollumEventOrganization :: Organization+    , gollumEventRepository   :: Repository+    , gollumEventSender       :: User++    , gollumEventPages        :: Text+    } deriving (Eq, Show, Read)++instance Event GollumEvent where+    typeName = TypeName "GollumEvent"+    eventName = EventName "gollum"++instance FromJSON GollumEvent where+    parseJSON (Object x) = GollumEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "pages"++    parseJSON _ = fail "GollumEvent"++instance ToJSON GollumEvent where+    toJSON GollumEvent{..} = object+        [ "installation" .= gollumEventInstallation+        , "organization" .= gollumEventOrganization+        , "repository"   .= gollumEventRepository+        , "sender"       .= gollumEventSender++        , "pages"      .= gollumEventPages+        ]+++instance Arbitrary GollumEvent where+    arbitrary = GollumEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary
+ src/GitHub/Types/Events/IssueCommentEvent.hs view
@@ -0,0 +1,69 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.IssueCommentEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data IssueCommentEvent = IssueCommentEvent+    { issueCommentEventInstallation :: Maybe Installation+    , issueCommentEventOrganization :: Organization+    , issueCommentEventRepository   :: Repository+    , issueCommentEventSender       :: User++    , issueCommentEventAction       :: Text+    , issueCommentEventChanges      :: Maybe Changes+    , issueCommentEventComment      :: IssueComment+    , issueCommentEventIssue        :: Issue+    } deriving (Eq, Show, Read)++instance Event IssueCommentEvent where+    typeName = TypeName "IssueCommentEvent"+    eventName = EventName "issue_comment"++instance FromJSON IssueCommentEvent where+    parseJSON (Object x) = IssueCommentEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .:? "changes"+        <*> x .: "comment"+        <*> x .: "issue"++    parseJSON _ = fail "IssueCommentEvent"++instance ToJSON IssueCommentEvent where+    toJSON IssueCommentEvent{..} = object+        [ "installation" .= issueCommentEventInstallation+        , "organization" .= issueCommentEventOrganization+        , "repository"   .= issueCommentEventRepository+        , "sender"       .= issueCommentEventSender++        , "action"       .= issueCommentEventAction+        , "changes"      .= issueCommentEventChanges+        , "comment"      .= issueCommentEventComment+        , "issue"        .= issueCommentEventIssue+        ]+++instance Arbitrary IssueCommentEvent where+    arbitrary = IssueCommentEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/IssuesEvent.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.IssuesEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data IssuesEvent = IssuesEvent+    { issuesEventInstallation :: Maybe Installation+    , issuesEventOrganization :: Organization+    , issuesEventRepository   :: Repository+    , issuesEventSender       :: User++    , issuesEventAction       :: Text+    , issuesEventAssignee     :: Maybe User+    , issuesEventChanges      :: Maybe Changes+    , issuesEventIssue        :: Issue+    , issuesEventLabel        :: Maybe Label+    , issuesEventMilestone    :: Maybe Milestone+    } deriving (Eq, Show, Read)++instance Event IssuesEvent where+    typeName = TypeName "IssuesEvent"+    eventName = EventName "issues"++instance FromJSON IssuesEvent where+    parseJSON (Object x) = IssuesEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .:? "assignee"+        <*> x .:? "changes"+        <*> x .: "issue"+        <*> x .:? "label"+        <*> x .:? "milestone"++    parseJSON _ = fail "IssuesEvent"++instance ToJSON IssuesEvent where+    toJSON IssuesEvent{..} = object+        [ "installation" .= issuesEventInstallation+        , "organization" .= issuesEventOrganization+        , "repository"   .= issuesEventRepository+        , "sender"       .= issuesEventSender++        , "action"       .= issuesEventAction+        , "assignee"     .= issuesEventAssignee+        , "changes"      .= issuesEventChanges+        , "issue"        .= issuesEventIssue+        , "label"        .= issuesEventLabel+        , "milestone"    .= issuesEventMilestone+        ]+++instance Arbitrary IssuesEvent where+    arbitrary = IssuesEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/LabelEvent.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.LabelEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data LabelEvent = LabelEvent+    { labelEventInstallation :: Maybe Installation+    , labelEventOrganization :: Organization+    , labelEventRepository   :: Repository+    , labelEventSender       :: User++    , labelEventAction       :: Text+    , labelEventLabel        :: Label+    } deriving (Eq, Show, Read)++instance Event LabelEvent where+    typeName = TypeName "LabelEvent"+    eventName = EventName "label"++instance FromJSON LabelEvent where+    parseJSON (Object x) = LabelEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .: "label"++    parseJSON _ = fail "LabelEvent"++instance ToJSON LabelEvent where+    toJSON LabelEvent{..} = object+        [ "installation"     .= labelEventInstallation+        , "organization"     .= labelEventOrganization+        , "repository"       .= labelEventRepository+        , "sender"           .= labelEventSender++        , "action"           .= labelEventAction+        , "label"            .= labelEventLabel+        ]+++instance Arbitrary LabelEvent where+    arbitrary = LabelEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/MemberEvent.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.MemberEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data MemberEvent = MemberEvent+    { memberEventInstallation :: Maybe Installation+    , memberEventOrganization :: Organization+    , memberEventRepository   :: Repository+    , memberEventSender       :: User++    , memberEventAction       :: Text+    } deriving (Eq, Show, Read)++instance Event MemberEvent where+    typeName = TypeName "MemberEvent"+    eventName = EventName "member"++instance FromJSON MemberEvent where+    parseJSON (Object x) = MemberEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"++    parseJSON _ = fail "MemberEvent"++instance ToJSON MemberEvent where+    toJSON MemberEvent{..} = object+        [ "installation" .= memberEventInstallation+        , "organization" .= memberEventOrganization+        , "repository"   .= memberEventRepository+        , "sender"       .= memberEventSender++        , "action"      .= memberEventAction+        ]+++instance Arbitrary MemberEvent where+    arbitrary = MemberEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary
+ src/GitHub/Types/Events/MembershipEvent.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.MembershipEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data MembershipEvent = MembershipEvent+    { membershipEventInstallation :: Maybe Installation+    , membershipEventOrganization :: Organization+    , membershipEventSender       :: User++    , membershipEventAction       :: Text+    , membershipEventMember       :: User+    , membershipEventScope        :: Text+    , membershipEventTeam         :: Team+    } deriving (Eq, Show, Read)++instance Event MembershipEvent where+    typeName = TypeName "MembershipEvent"+    eventName = EventName "membership"++instance FromJSON MembershipEvent where+    parseJSON (Object x) = MembershipEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .: "member"+        <*> x .: "scope"+        <*> x .: "team"++    parseJSON _ = fail "MembershipEvent"++instance ToJSON MembershipEvent where+    toJSON MembershipEvent{..} = object+        [ "installation" .= membershipEventInstallation+        , "organization" .= membershipEventOrganization+        , "sender"       .= membershipEventSender++        , "action"       .= membershipEventAction+        , "member"       .= membershipEventMember+        , "scope"        .= membershipEventScope+        , "team"         .= membershipEventTeam+        ]+++instance Arbitrary MembershipEvent where+    arbitrary = MembershipEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/MilestoneEvent.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.MilestoneEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data MilestoneEvent = MilestoneEvent+    { milestoneEventInstallation :: Maybe Installation+    , milestoneEventOrganization :: Organization+    , milestoneEventRepository   :: Repository+    , milestoneEventSender       :: User++    , milestoneEventAction       :: Text+    , milestoneEventMilestone    :: Milestone+    } deriving (Eq, Show, Read)++instance Event MilestoneEvent where+    typeName = TypeName "MilestoneEvent"+    eventName = EventName "milestone"++instance FromJSON MilestoneEvent where+    parseJSON (Object x) = MilestoneEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .: "milestone"++    parseJSON _ = fail "MilestoneEvent"++instance ToJSON MilestoneEvent where+    toJSON MilestoneEvent{..} = object+        [ "installation" .= milestoneEventInstallation+        , "organization" .= milestoneEventOrganization+        , "repository"   .= milestoneEventRepository+        , "sender"       .= milestoneEventSender++        , "action"       .= milestoneEventAction+        , "milestone"    .= milestoneEventMilestone+        ]+++instance Arbitrary MilestoneEvent where+    arbitrary = MilestoneEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/OrganizationEvent.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.OrganizationEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data OrganizationEvent = OrganizationEvent+    { organizationEventInstallation :: Maybe Installation+    , organizationEventOrganization :: Organization+    , organizationEventSender       :: User++    , organizationEventAction       :: Text+    , organizationEventInvitation   :: Maybe Invitation+    , organizationEventMembership   :: Maybe Membership+    , organizationEventUser         :: Maybe User+    } deriving (Eq, Show, Read)++instance Event OrganizationEvent where+    typeName = TypeName "OrganizationEvent"+    eventName = EventName "organization"++instance FromJSON OrganizationEvent where+    parseJSON (Object x) = OrganizationEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .:? "invitation"+        <*> x .:? "membership"+        <*> x .:? "user"++    parseJSON _ = fail "OrganizationEvent"++instance ToJSON OrganizationEvent where+    toJSON OrganizationEvent{..} = object+        [ "installation" .= organizationEventInstallation+        , "organization" .= organizationEventOrganization+        , "sender"       .= organizationEventSender++        , "action"       .= organizationEventAction+        , "invitation"   .= organizationEventInvitation+        , "membership"   .= organizationEventMembership+        , "user"         .= organizationEventUser+        ]+++instance Arbitrary OrganizationEvent where+    arbitrary = OrganizationEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/PageBuildEvent.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.PageBuildEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data PageBuildEvent = PageBuildEvent+    { pageBuildEventInstallation :: Maybe Installation+    , pageBuildEventOrganization :: Organization+    , pageBuildEventRepository   :: Repository+    , pageBuildEventSender       :: User++    , pageBuildEventId           :: Int+    , pageBuildEventBuild        :: PageBuild+    } deriving (Eq, Show, Read)++instance Event PageBuildEvent where+    typeName = TypeName "PageBuildEvent"+    eventName = EventName "page_build"++instance FromJSON PageBuildEvent where+    parseJSON (Object x) = PageBuildEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "id"+        <*> x .: "build"++    parseJSON _ = fail "PageBuildEvent"++instance ToJSON PageBuildEvent where+    toJSON PageBuildEvent{..} = object+        [ "installation" .= pageBuildEventInstallation+        , "organization" .= pageBuildEventOrganization+        , "repository"   .= pageBuildEventRepository+        , "sender"       .= pageBuildEventSender++        , "id"           .= pageBuildEventId+        , "build"        .= pageBuildEventBuild+        ]+++instance Arbitrary PageBuildEvent where+    arbitrary = PageBuildEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/PingEvent.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.PingEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data PingEvent = PingEvent+    { pingEventInstallation :: Maybe Installation+    , pingEventOrganization :: Organization+    , pingEventSender       :: User++    , pingEventHook         :: Hook+    , pingEventHookId       :: Int+    , pingEventZen          :: Text+    } deriving (Eq, Show, Read)++instance Event PingEvent where+    typeName = TypeName "PingEvent"+    eventName = EventName "ping"++instance FromJSON PingEvent where+    parseJSON (Object x) = PingEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "sender"++        <*> x .: "hook"+        <*> x .: "hook_id"+        <*> x .: "zen"++    parseJSON _ = fail "PingEvent"++instance ToJSON PingEvent where+    toJSON PingEvent{..} = object+        [ "installation" .= pingEventInstallation+        , "organization" .= pingEventOrganization+        , "sender"       .= pingEventSender++        , "hook"         .= pingEventHook+        , "hook_id"      .= pingEventHookId+        , "zen"          .= pingEventZen+        ]+++instance Arbitrary PingEvent where+    arbitrary = PingEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/PullRequestEvent.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.PullRequestEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data PullRequestEvent = PullRequestEvent+    { pullRequestEventInstallation      :: Maybe Installation+    , pullRequestEventOrganization      :: Organization+    , pullRequestEventRepository        :: Repository+    , pullRequestEventSender            :: User++    , pullRequestEventAction            :: Text+    , pullRequestEventAfter             :: Maybe Text+    , pullRequestEventAssignee          :: Maybe User+    , pullRequestEventBefore            :: Maybe Text+    , pullRequestEventChanges           :: Maybe Changes+    , pullRequestEventLabel             :: Maybe Label+    , pullRequestEventNumber            :: Int+    , pullRequestEventPullRequest       :: PullRequest+    , pullRequestEventRequestedReviewer :: Maybe User+    , pullRequestEventRequestedTeam     :: Maybe Team+    } deriving (Eq, Show, Read)++instance Event PullRequestEvent where+    typeName = TypeName "PullRequestEvent"+    eventName = EventName "pull_request"++instance FromJSON PullRequestEvent where+    parseJSON (Object x) = PullRequestEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .:? "after"+        <*> x .:? "assignee"+        <*> x .:? "before"+        <*> x .:? "changes"+        <*> x .:? "label"+        <*> x .: "number"+        <*> x .: "pull_request"+        <*> x .:? "requested_reviewer"+        <*> x .:? "requested_team"++    parseJSON _ = fail "PullRequestEvent"++instance ToJSON PullRequestEvent where+    toJSON PullRequestEvent{..} = object+        [ "installation"       .= pullRequestEventInstallation+        , "organization"       .= pullRequestEventOrganization+        , "repository"         .= pullRequestEventRepository+        , "sender"             .= pullRequestEventSender++        , "action"             .= pullRequestEventAction+        , "after"              .= pullRequestEventAfter+        , "assignee"           .= pullRequestEventAssignee+        , "before"             .= pullRequestEventBefore+        , "changes"            .= pullRequestEventChanges+        , "label"              .= pullRequestEventLabel+        , "number"             .= pullRequestEventNumber+        , "pull_request"       .= pullRequestEventPullRequest+        , "requested_reviewer" .= pullRequestEventRequestedReviewer+        , "requested_team"     .= pullRequestEventRequestedTeam+        ]+++instance Arbitrary PullRequestEvent where+    arbitrary = PullRequestEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/PullRequestReviewCommentEvent.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.PullRequestReviewCommentEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data PullRequestReviewCommentEvent = PullRequestReviewCommentEvent+    { pullRequestReviewCommentEventInstallation :: Maybe Installation+    , pullRequestReviewCommentEventOrganization :: Organization+    , pullRequestReviewCommentEventRepository   :: Repository+    , pullRequestReviewCommentEventSender       :: User++    , pullRequestReviewCommentEventAction       :: Text+    , pullRequestReviewCommentEventComment      :: ReviewComment+    , pullRequestReviewCommentEventPullRequest  :: SimplePullRequest+    } deriving (Eq, Show, Read)++instance Event PullRequestReviewCommentEvent where+    typeName = TypeName "PullRequestReviewCommentEvent"+    eventName = EventName "pull_request_review_comment"++instance FromJSON PullRequestReviewCommentEvent where+    parseJSON (Object x) = PullRequestReviewCommentEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .: "comment"+        <*> x .: "pull_request"++    parseJSON _ = fail "PullRequestReviewCommentEvent"++instance ToJSON PullRequestReviewCommentEvent where+    toJSON PullRequestReviewCommentEvent{..} = object+        [ "installation" .= pullRequestReviewCommentEventInstallation+        , "organization" .= pullRequestReviewCommentEventOrganization+        , "repository"   .= pullRequestReviewCommentEventRepository+        , "sender"       .= pullRequestReviewCommentEventSender++        , "action"       .= pullRequestReviewCommentEventAction+        , "comment"      .= pullRequestReviewCommentEventComment+        , "pull_request" .= pullRequestReviewCommentEventPullRequest+        ]+++instance Arbitrary PullRequestReviewCommentEvent where+    arbitrary = PullRequestReviewCommentEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/PullRequestReviewEvent.hs view
@@ -0,0 +1,69 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.PullRequestReviewEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data PullRequestReviewEvent = PullRequestReviewEvent+    { pullRequestReviewEventInstallation :: Maybe Installation+    , pullRequestReviewEventOrganization :: Organization+    , pullRequestReviewEventRepository   :: Repository+    , pullRequestReviewEventSender       :: User++    , pullRequestReviewEventAction       :: Text+    , pullRequestReviewEventChanges      :: Maybe Changes+    , pullRequestReviewEventPullRequest  :: SimplePullRequest+    , pullRequestReviewEventReview       :: Review+    } deriving (Eq, Show, Read)++instance Event PullRequestReviewEvent where+    typeName = TypeName "PullRequestReviewEvent"+    eventName = EventName "pull_request_review"++instance FromJSON PullRequestReviewEvent where+    parseJSON (Object x) = PullRequestReviewEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .:? "changes"+        <*> x .: "pull_request"+        <*> x .: "review"++    parseJSON _ = fail "PullRequestReviewEvent"++instance ToJSON PullRequestReviewEvent where+    toJSON PullRequestReviewEvent{..} = object+        [ "installation" .= pullRequestReviewEventInstallation+        , "organization" .= pullRequestReviewEventOrganization+        , "repository"   .= pullRequestReviewEventRepository+        , "sender"       .= pullRequestReviewEventSender++        , "action"       .= pullRequestReviewEventAction+        , "changes"      .= pullRequestReviewEventChanges+        , "pull_request" .= pullRequestReviewEventPullRequest+        , "review"       .= pullRequestReviewEventReview+        ]+++instance Arbitrary PullRequestReviewEvent where+    arbitrary = PullRequestReviewEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/PushEvent.hs view
@@ -0,0 +1,105 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.PushEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data PushEvent = PushEvent+    { pushEventInstallation    :: Maybe Installation+    , pushEventOrganization    :: Organization+    , pushEventRepository      :: Repository+    , pushEventSender          :: User++    , pushEventAfter           :: Text+    , pushEventBaseRef         :: Maybe Text+    , pushEventBefore          :: Text+    , pushEventCommits         :: [PushCommit]+    , pushEventCompare         :: Text+    , pushEventCreated         :: Bool+    , pushEventDeleted         :: Bool+    , pushEventDistinctCommits :: Maybe [PushCommit]+    , pushEventForced          :: Bool+    , pushEventHeadCommit      :: Maybe PushCommit+    , pushEventPusher          :: UserRef+    , pushEventRef             :: Text+    , pushEventRefName         :: Maybe Text+    } deriving (Eq, Show, Read)++instance Event PushEvent where+    typeName = TypeName "PushEvent"+    eventName = EventName "push"++instance FromJSON PushEvent where+    parseJSON (Object x) = PushEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "after"+        <*> x .: "base_ref"+        <*> x .: "before"+        <*> x .: "commits"+        <*> x .: "compare"+        <*> x .: "created"+        <*> x .: "deleted"+        <*> x .:? "distinct_commits"+        <*> x .: "forced"+        <*> x .: "head_commit"+        <*> x .: "pusher"+        <*> x .: "ref"+        <*> x .:? "ref_name"++    parseJSON _ = fail "PushEvent"++instance ToJSON PushEvent where+    toJSON PushEvent{..} = object+        [ "installation"     .= pushEventInstallation+        , "organization"     .= pushEventOrganization+        , "repository"       .= pushEventRepository+        , "sender"           .= pushEventSender++        , "after"            .= pushEventAfter+        , "base_ref"         .= pushEventBaseRef+        , "before"           .= pushEventBefore+        , "commits"          .= pushEventCommits+        , "compare"          .= pushEventCompare+        , "created"          .= pushEventCreated+        , "deleted"          .= pushEventDeleted+        , "distinct_commits" .= pushEventDistinctCommits+        , "forced"           .= pushEventForced+        , "head_commit"      .= pushEventHeadCommit+        , "pusher"           .= pushEventPusher+        , "ref"              .= pushEventRef+        , "ref_name"         .= pushEventRefName+        ]+++instance Arbitrary PushEvent where+    arbitrary = PushEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/ReleaseEvent.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.ReleaseEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data ReleaseEvent = ReleaseEvent+    { releaseEventInstallation :: Maybe Installation+    , releaseEventOrganization :: Organization+    , releaseEventRepository   :: Repository+    , releaseEventSender       :: User++    , releaseEventAction       :: Text+    , releaseEventChanges      :: Maybe Changes+    , releaseEventRelease      :: Release+    } deriving (Eq, Show, Read)++instance Event ReleaseEvent where+    typeName = TypeName "ReleaseEvent"+    eventName = EventName "release"++instance FromJSON ReleaseEvent where+    parseJSON (Object x) = ReleaseEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .:? "changes"+        <*> x .: "release"++    parseJSON _ = fail "ForkEvent"++instance ToJSON ReleaseEvent where+    toJSON ReleaseEvent{..} = object+        [ "installation" .= releaseEventInstallation+        , "organization" .= releaseEventOrganization+        , "repository"   .= releaseEventRepository+        , "sender"       .= releaseEventSender++        , "action"       .= releaseEventAction+        , "changes"      .= releaseEventChanges+        , "release"      .= releaseEventRelease+        ]+++instance Arbitrary ReleaseEvent where+    arbitrary = ReleaseEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/RepositoryEvent.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.RepositoryEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data RepositoryEvent = RepositoryEvent+    { repositoryEventInstallation :: Maybe Installation+    , repositoryEventOrganization :: Organization+    , repositoryEventRepository   :: Repository+    , repositoryEventSender       :: User++    , repositoryEventAction       :: Text+    } deriving (Eq, Show, Read)++instance Event RepositoryEvent where+    typeName = TypeName "RepositoryEvent"+    eventName = EventName "repository"++instance FromJSON RepositoryEvent where+    parseJSON (Object x) = RepositoryEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"++    parseJSON _ = fail "RepositoryEvent"++instance ToJSON RepositoryEvent where+    toJSON RepositoryEvent{..} = object+        [ "installation"     .= repositoryEventInstallation+        , "organization"     .= repositoryEventOrganization+        , "repository"       .= repositoryEventRepository+        , "sender"           .= repositoryEventSender++        , "action"           .= repositoryEventAction+        ]+++instance Arbitrary RepositoryEvent where+    arbitrary = RepositoryEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary
+ src/GitHub/Types/Events/StarEvent.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.StarEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data StarEvent = StarEvent+    { starEventInstallation :: Maybe Installation+    , starEventOrganization :: Organization+    , starEventRepository   :: Repository+    , starEventSender       :: User++    , starEventAction       :: Text+    , starEventStarredAt    :: Text+    } deriving (Eq, Show, Read)++instance Event StarEvent where+    typeName = TypeName "StarEvent"+    eventName = EventName "star"++instance FromJSON StarEvent where+    parseJSON (Object x) = StarEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .: "starred_at"++    parseJSON _ = fail "StarEvent"++instance ToJSON StarEvent where+    toJSON StarEvent{..} = object+        [ "installation" .= starEventInstallation+        , "organization" .= starEventOrganization+        , "repository"   .= starEventRepository+        , "sender"       .= starEventSender++        , "action"       .= starEventAction+        , "starred_at"   .= starEventStarredAt+        ]+++instance Arbitrary StarEvent where+    arbitrary = StarEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/StatusEvent.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.StatusEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data StatusEvent = StatusEvent+    { statusEventInstallation :: Maybe Installation+    , statusEventOrganization :: Organization+    , statusEventRepository   :: Repository+    , statusEventSender       :: User++    , statusEventAvatarUrl    :: Maybe Text+    , statusEventBranches     :: [Branch]+    , statusEventCommit       :: StatusCommit+    , statusEventContext      :: Text+    , statusEventCreatedAt    :: DateTime+    , statusEventDescription  :: Text+    , statusEventId           :: Int+    , statusEventName         :: Text+    , statusEventSha          :: Text+    , statusEventState        :: Text+    , statusEventTargetUrl    :: Maybe Text+    , statusEventUpdatedAt    :: DateTime+    } deriving (Eq, Show, Read)++instance Event StatusEvent where+    typeName = TypeName "StatusEvent"+    eventName = EventName "status"++instance FromJSON StatusEvent where+    parseJSON (Object x) = StatusEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "avatar_url"+        <*> x .: "branches"+        <*> x .: "commit"+        <*> x .: "context"+        <*> x .: "created_at"+        <*> x .: "description"+        <*> x .: "id"+        <*> x .: "name"+        <*> x .: "sha"+        <*> x .: "state"+        <*> x .: "target_url"+        <*> x .: "updated_at"++    parseJSON _ = fail "StatusEvent"++instance ToJSON StatusEvent where+    toJSON StatusEvent{..} = object+        [ "installation" .= statusEventInstallation+        , "organization" .= statusEventOrganization+        , "repository"   .= statusEventRepository+        , "sender"       .= statusEventSender++        , "avatar_url"   .= statusEventAvatarUrl+        , "branches"     .= statusEventBranches+        , "commit"       .= statusEventCommit+        , "context"      .= statusEventContext+        , "created_at"   .= statusEventCreatedAt+        , "description"  .= statusEventDescription+        , "id"           .= statusEventId+        , "name"         .= statusEventName+        , "sha"          .= statusEventSha+        , "state"        .= statusEventState+        , "target_url"   .= statusEventTargetUrl+        , "updated_at"   .= statusEventUpdatedAt+        ]+++instance Arbitrary StatusEvent where+    arbitrary = StatusEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/WatchEvent.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.WatchEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data WatchEvent = WatchEvent+    { watchEventInstallation :: Maybe Installation+    , watchEventOrganization :: Organization+    , watchEventRepository   :: Repository+    , watchEventSender       :: User++    , watchEventAction       :: Text+    } deriving (Eq, Show, Read)++instance Event WatchEvent where+    typeName = TypeName "WatchEvent"+    eventName = EventName "watch"++instance FromJSON WatchEvent where+    parseJSON (Object x) = WatchEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"++    parseJSON _ = fail "WatchEvent"++instance ToJSON WatchEvent where+    toJSON WatchEvent{..} = object+        [ "installation" .= watchEventInstallation+        , "organization" .= watchEventOrganization+        , "repository"   .= watchEventRepository+        , "sender"       .= watchEventSender++        , "action"       .= watchEventAction+        ]+++instance Arbitrary WatchEvent where+    arbitrary = WatchEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary
+ src/GitHub/Types/Events/WorkflowJobEvent.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.WorkflowJobEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data WorkflowJobEvent = WorkflowJobEvent+    { workflowJobEventInstallation :: Maybe Installation+    , workflowJobEventOrganization :: Organization+    , workflowJobEventRepository   :: Repository+    , workflowJobEventSender       :: User++    , workflowJobEventAction       :: Text+    , workflowJobEventWorkflowJob  :: WorkflowJob+    } deriving (Eq, Show, Read)++instance Event WorkflowJobEvent where+    typeName = TypeName "WorkflowJobEvent"+    eventName = EventName "workflow_job"++instance FromJSON WorkflowJobEvent where+    parseJSON (Object x) = WorkflowJobEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .: "workflow_job"++    parseJSON _ = fail "WorkflowJobEvent"++instance ToJSON WorkflowJobEvent where+    toJSON WorkflowJobEvent{..} = object+        [ "installation" .= workflowJobEventInstallation+        , "organization" .= workflowJobEventOrganization+        , "repository"   .= workflowJobEventRepository+        , "sender"       .= workflowJobEventSender++        , "action"       .= workflowJobEventAction+        , "workflow_job" .= workflowJobEventWorkflowJob+        ]+++instance Arbitrary WorkflowJobEvent where+    arbitrary = WorkflowJobEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/Events/WorkflowRunEvent.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}+module GitHub.Types.Events.WorkflowRunEvent where++import           Data.Aeson                (FromJSON (..), ToJSON (..), object)+import           Data.Aeson.Types          (Value (..), (.:), (.:?), (.=))+import           Data.Text                 (Text)+import           Test.QuickCheck.Arbitrary (Arbitrary (..))++import           GitHub.Types.Base+import           GitHub.Types.Event+++data WorkflowRunEvent = WorkflowRunEvent+    { workflowRunEventInstallation :: Maybe Installation+    , workflowRunEventOrganization :: Organization+    , workflowRunEventRepository   :: Repository+    , workflowRunEventSender       :: User++    , workflowRunEventAction       :: Text+    , workflowRunEventWorkflow     :: Workflow+    , workflowRunEventWorkflowRun  :: WorkflowRun+    } deriving (Eq, Show, Read)++instance Event WorkflowRunEvent where+    typeName = TypeName "WorkflowRunEvent"+    eventName = EventName "workflow_run"++instance FromJSON WorkflowRunEvent where+    parseJSON (Object x) = WorkflowRunEvent+        <$> x .:? "installation"+        <*> x .: "organization"+        <*> x .: "repository"+        <*> x .: "sender"++        <*> x .: "action"+        <*> x .: "workflow"+        <*> x .: "workflow_run"++    parseJSON _ = fail "WorkflowRunEvent"++instance ToJSON WorkflowRunEvent where+    toJSON WorkflowRunEvent{..} = object+        [ "installation" .= workflowRunEventInstallation+        , "organization" .= workflowRunEventOrganization+        , "repository"   .= workflowRunEventRepository+        , "sender"       .= workflowRunEventSender++        , "action"       .= workflowRunEventAction+        , "workflow"     .= workflowRunEventWorkflow+        , "workflow_run" .= workflowRunEventWorkflowRun+        ]+++instance Arbitrary WorkflowRunEvent where+    arbitrary = WorkflowRunEvent+        <$> arbitrary+        <*> arbitrary+        <*> arbitrary+        <*> arbitrary++        <*> arbitrary+        <*> arbitrary+        <*> arbitrary
+ src/GitHub/Types/PayloadParser.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE StrictData #-}+module GitHub.Types.PayloadParser where++import           Data.Aeson          (FromJSON (..), ToJSON (..))+import           Data.Aeson.Types    (Parser, Value (..))+import qualified Data.List           as List+import           Data.Text           (Text)+import qualified Data.Text           as Text++import           GitHub.Types.Event+import           GitHub.Types.Events+++data Payload+    = CheckRunEventPayload                 CheckRunEvent+    | CheckSuiteEventPayload               CheckSuiteEvent+    | CommitCommentEventPayload            CommitCommentEvent+    | CreateEventPayload                   CreateEvent+    | DeleteEventPayload                   DeleteEvent+    | DeploymentEventPayload               DeploymentEvent+    | DeploymentStatusEventPayload         DeploymentStatusEvent+    | ForkEventPayload                     ForkEvent+    | GollumEventPayload                   GollumEvent+    | IssueCommentEventPayload             IssueCommentEvent+    | IssuesEventPayload                   IssuesEvent+    | LabelEventPayload                    LabelEvent+    | MemberEventPayload                   MemberEvent+    | MembershipEventPayload               MembershipEvent+    | MilestoneEventPayload                MilestoneEvent+    | OrganizationEventPayload             OrganizationEvent+    | PageBuildEventPayload                PageBuildEvent+    | PingEventPayload                     PingEvent+    | PullRequestEventPayload              PullRequestEvent+    | PullRequestReviewCommentEventPayload PullRequestReviewCommentEvent+    | PullRequestReviewEventPayload        PullRequestReviewEvent+    | PushEventPayload                     PushEvent+    | ReleaseEventPayload                  ReleaseEvent+    | RepositoryEventPayload               RepositoryEvent+    | StarEventPayload                     StarEvent+    | StatusEventPayload                   StatusEvent+    | WatchEventPayload                    WatchEvent+    | WorkflowJobEventPayload              WorkflowJobEvent+    | WorkflowRunEventPayload              WorkflowRunEvent+    deriving (Eq, Show, Read)+++instance ToJSON Payload where+    toJSON (CheckRunEventPayload                 x) = toJSON x+    toJSON (CheckSuiteEventPayload               x) = toJSON x+    toJSON (CommitCommentEventPayload            x) = toJSON x+    toJSON (CreateEventPayload                   x) = toJSON x+    toJSON (DeleteEventPayload                   x) = toJSON x+    toJSON (DeploymentEventPayload               x) = toJSON x+    toJSON (DeploymentStatusEventPayload         x) = toJSON x+    toJSON (ForkEventPayload                     x) = toJSON x+    toJSON (GollumEventPayload                   x) = toJSON x+    toJSON (IssueCommentEventPayload             x) = toJSON x+    toJSON (IssuesEventPayload                   x) = toJSON x+    toJSON (LabelEventPayload                    x) = toJSON x+    toJSON (MemberEventPayload                   x) = toJSON x+    toJSON (MembershipEventPayload               x) = toJSON x+    toJSON (MilestoneEventPayload                x) = toJSON x+    toJSON (OrganizationEventPayload             x) = toJSON x+    toJSON (PageBuildEventPayload                x) = toJSON x+    toJSON (PingEventPayload                     x) = toJSON x+    toJSON (PullRequestEventPayload              x) = toJSON x+    toJSON (PullRequestReviewCommentEventPayload x) = toJSON x+    toJSON (PullRequestReviewEventPayload        x) = toJSON x+    toJSON (PushEventPayload                     x) = toJSON x+    toJSON (ReleaseEventPayload                  x) = toJSON x+    toJSON (RepositoryEventPayload               x) = toJSON x+    toJSON (StatusEventPayload                   x) = toJSON x+    toJSON (StarEventPayload                     x) = toJSON x+    toJSON (WatchEventPayload                    x) = toJSON x+    toJSON (WorkflowJobEventPayload              x) = toJSON x+    toJSON (WorkflowRunEventPayload              x) = toJSON x+++data PayloadParser = PayloadParser+    { payloadParserTypeName    :: Text+    , payloadParserWebhookName :: Text+    , payloadParser            :: Value -> Parser Payload+    }+++payloadParsers :: [PayloadParser]+payloadParsers =+    [ eventParser CheckRunEventPayload+    , eventParser CheckSuiteEventPayload+    , eventParser CommitCommentEventPayload+    , eventParser CreateEventPayload+    , eventParser DeleteEventPayload+    , eventParser DeploymentEventPayload+    , eventParser DeploymentStatusEventPayload+    , eventParser ForkEventPayload+    , eventParser GollumEventPayload+    , eventParser IssueCommentEventPayload+    , eventParser IssuesEventPayload+    , eventParser LabelEventPayload+    , eventParser MemberEventPayload+    , eventParser MembershipEventPayload+    , eventParser MilestoneEventPayload+    , eventParser OrganizationEventPayload+    , eventParser PageBuildEventPayload+    , eventParser PingEventPayload+    , eventParser PullRequestEventPayload+    , eventParser PullRequestReviewCommentEventPayload+    , eventParser PullRequestReviewEventPayload+    , eventParser PushEventPayload+    , eventParser ReleaseEventPayload+    , eventParser RepositoryEventPayload+    , eventParser StatusEventPayload+    , eventParser StarEventPayload+    , eventParser WatchEventPayload+    , eventParser WorkflowJobEventPayload+    , eventParser WorkflowRunEventPayload+    ]+  where+    eventParser' :: FromJSON a => TypeName a -> EventName a -> (a -> Payload) -> PayloadParser+    eventParser' (TypeName ty) (EventName ev) tycon =+        PayloadParser ty ev (fmap tycon . parseJSON)++    eventParser :: (FromJSON a, Event a) => (a -> Payload) -> PayloadParser+    eventParser = eventParser' typeName eventName++++eventPayloadParser :: Text -> Value -> Parser Payload+eventPayloadParser eventType x =+    case List.find ((== eventType) . payloadParserTypeName) payloadParsers of+        Nothing -> fail $ "eventPayloadParser: unknown event type: " ++ Text.unpack eventType+        Just p  -> payloadParser p x++-- | Since the event type is included through different means (X-GitHub-Event+-- header, or inline in the JSON object), it's not possible to make 'Event'+-- an instance of 'FromJSON'. But if you know the type, you can use this+-- parser.+webhookPayloadParser :: Text -> Value -> Parser Payload+webhookPayloadParser eventType x =+    case List.find ((== eventType) . payloadParserWebhookName) payloadParsers of+        Nothing -> fail $ "webhookPayloadParser: unknown event type: " ++ Text.unpack eventType+        Just p  -> payloadParser p x
+ src/GitHub/WebHook/Handler.hs view
@@ -0,0 +1,141 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StrictData        #-}+{-# LANGUAGE TupleSections     #-}+module GitHub.WebHook.Handler+  ( Handler (..)+  , Error (..)+  , runHandler+  , removeNulls+  ) where++import           Crypto.Hash           (HMAC, SHA1, digestToHexByteString, hmac,+                                        hmacGetDigest)+import           Data.Aeson            (ToJSON (..), Value (..),+                                        eitherDecodeStrict')+import qualified Data.Aeson.KeyMap     as KeyMap+import           Data.Aeson.Types      (parseEither)+import           Data.ByteString       (ByteString)+import qualified Data.ByteString.Char8 as BC8+import           Data.Text             (Text)+import qualified Data.Text             as Text+import           Data.Text.Encoding    (decodeUtf8)+import           Data.UUID             (UUID, fromASCIIBytes)+import qualified Data.Vector           as Vector++import           GitHub.Types++++data Handler m = Handler+    { hSecretKeys :: [String]+      -- ^ Secret keys which are used to authenticate the incoming request.+      -- If the list is empty then no authentication is required. The handler+      -- tries each key until it finds one which works. This makes it easier+      -- to rotate keys because you can have multiple ones active at any given+      -- point in time.++    , hBody       :: m ByteString+      -- ^ Action which is used to read the request body.++    , hHeader     :: ByteString -> m (Maybe ByteString)+      -- ^ Action which is used to retrieve a particular header from the+      -- request.+    }+++data Error+    = InvalidRequest+      -- ^ The incoming request is not well-formed. If that happens it means+      -- GitHub screwed something up, or changed the format of the request.++    | ParseError !Text+      -- ^ The request looks valid but we failed to parse the payload. This+      -- could be because our parsing code is wrong, or because GitHub added+      -- a new event type which we don't handle yet.++    | IncompleteParse Value Payload+      -- ^ The request looks valid but we failed to parse the payload. This+      -- could be because our parsing code is wrong, or because GitHub added+      -- a new event type which we don't handle yet.++    | UnsignedRequest+      -- ^ We were expecting a signed request but no signature was included.+      -- Such requests are rejected beause we don't want to accept requests from+      -- untrusted sources.++    | InvalidSignature+      -- ^ A signature was included in the request but it did not match the+      -- secret key which was providid to the handler. Usually points to+      -- a configuration error on either end.+++toParseError :: String -> Either Error Payload+toParseError = Left . ParseError . Text.pack+++removeNulls :: ToJSON a => a -> Value+removeNulls = go . toJSON+  where+    go (Array  x) = Array . Vector.map go $ x+    go (Object x) = Object . KeyMap.map go . KeyMap.filter (not . isEmpty) $ x+    go         x  = x++    isEmpty Null      = True+    isEmpty (Array x) = null x+    isEmpty _         = False+++toSuccess :: Value -> Payload -> Either Error Payload+toSuccess value payload =+  if removeNulls payload == removeNulls value+    then Right payload+    else Left $ IncompleteParse value payload+++verifySecretKey :: ByteString -> ByteString -> String -> Bool+verifySecretKey rawBody sig key = sig == ("sha1=" <> digestToHexByteString+    (hmacGetDigest (hmac (BC8.pack key) rawBody :: HMAC SHA1)))+++runHandler :: (Applicative m, Monad m) => Handler m -> m (Either Error (UUID, Payload))+runHandler h = do+    mbDelivery <- (fromASCIIBytes =<<) <$> hHeader h "X-GitHub-Delivery"++    res <- do+        rawBody     <- hBody h+        mbSignature <- hHeader h "X-Hub-Signature"++        let authenticatedBody+              = case (hSecretKeys h, mbSignature) of+                  -- No secret key and no signature. Pass along the body+                  -- unverified.+                  ([], Nothing) -> Right rawBody++                  -- Signature is available but no secret keys to verify it.+                  -- This is not a fatal error, we can still process the event.+                  ([], Just _) -> Right rawBody++                  -- Secret keys are available but the request is not signed.+                  -- Reject the request.+                  (_, Nothing) -> Left UnsignedRequest++                  -- Both the signature and secret keys are available. Verify+                  -- the signature with the first key which works, otherwise+                  -- reject the request.+                  (secretKeys, Just sig) ->+                      if any (verifySecretKey rawBody sig) secretKeys+                          then Right rawBody+                          else Left InvalidSignature++        mbEventName <- hHeader h "X-GitHub-Event"+        pure $ do+            eventName <- maybe (Left InvalidRequest) Right mbEventName+            body      <- authenticatedBody+            case eitherDecodeStrict' body of+                Left e -> toParseError e+                Right value -> either toParseError (toSuccess value) $+                    parseEither (webhookPayloadParser $ decodeUtf8 eventName) value++    pure $ case mbDelivery of+        Nothing   -> Left InvalidRequest+        Just uuid -> fmap (uuid,) res
− src/PullRequestInfo.hs
@@ -1,74 +0,0 @@-module PullRequestInfo where--import           Control.Monad         (join)-import qualified Data.Maybe            as Maybe-import qualified Data.Text             as Text-import           Data.Time.Clock       (UTCTime, diffUTCTime)-import qualified GitHub-import qualified Review-import           Text.Html             (prettyHtml, toHtml)-import           Text.Tabular          (Header (..), Properties (..),-                                        Table (..))-import qualified Text.Tabular.AsciiArt as AsciiArt-import qualified Text.Tabular.Html     as Html---data PullRequestInfo = PullRequestInfo-  { repoName     :: GitHub.Name GitHub.Repo-  , reviewStatus :: [Review.Status]-  , pullRequest  :: GitHub.PullRequest-  }---formatPR :: Bool -> UTCTime -> [[PullRequestInfo]] -> String-formatPR False now = AsciiArt.render id id id . prToTable now-formatPR True  now = prettyHtml . Html.render toHtml toHtml toHtml . prToTable now---prToTable :: UTCTime -> [[PullRequestInfo]] -> Table String String String-prToTable now prss = Table rowNames columnNames rows-  where-    rowNames = Group SingleLine-      . map (Group NoLine . map (Header . getRowName))-      . filter (not . null)-      $ prss--    getRowName pr =-      let repo num = getRepoName pr ++ " " ++ num in-      repo . show . GitHub.pullRequestNumber . pullRequest $ pr--    getRepoName = Text.unpack . GitHub.untagName . repoName--    columnNames =  Group SingleLine-      [ Header "branch"-      , Header "age"-      , Header "title"-      , Header "mergeable"-      , Header "mergeable_state"-      , Header "review_status"-      ]--    rows = map (\pr ->-      [ getPrBranch         $ pullRequest pr-      , getPrAge            $ pullRequest pr-      , getPrTitle          $ pullRequest pr-      , getPrMergeable      $ pullRequest pr-      , getPrMergeableState $ pullRequest pr-      , show $ reviewStatus pr-      ]) $ join prss--    getPrTitle = Text.unpack . GitHub.pullRequestTitle-    getPrMergeable = show . Maybe.fromMaybe False . GitHub.pullRequestMergeable-    getPrMergeableState = show . GitHub.pullRequestMergeableState--    getPrBranch =-      Text.unpack-        . GitHub.pullRequestCommitLabel-        . GitHub.pullRequestHead--    getPrAge =-      (++ "d") . show . diffInDays now . GitHub.pullRequestCreatedAt---diffInDays :: UTCTime -> UTCTime -> Int-diffInDays a b = round $ diffUTCTime a b / (60 * 60 * 24)
− src/Requests.hs
@@ -1,24 +0,0 @@-{-# LANGUAGE DataKinds #-}-module Requests where--import           Control.Monad.Catch (throwM)-import qualified GitHub-import           Network.HTTP.Client (Manager)---request-  :: Maybe GitHub.Auth-  -> Manager-  -> GitHub.Request GitHub.RO a-  -> IO a-request auth mgr req = do-  response <- executeRequest-  case response of-    Left  err -> throwM err-    Right res -> return res--  where-    executeRequest =-      case auth of-        Nothing -> GitHub.executeRequestWithMgr' mgr req-        Just tk -> GitHub.executeRequestWithMgr mgr tk req
− src/Review.hs
@@ -1,71 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-module Review where--import           Control.Applicative    ((<$>))-import qualified Data.ByteString.Lazy   as LBS-import qualified Data.List              as List-import           Data.Text              (Text)-import qualified Data.Text              as Text-import           Data.Text.Encoding     (decodeUtf8)-import qualified GitHub-import           Network.HTTP.Client    (Manager, httpLbs, parseRequest,-                                         responseBody)-import           Text.HTML.TagSoup      (parseTags)-import           Text.HTML.TagSoup.Tree (TagTree (..), tagTree)---data Approval-  = Approved-  | Rejected-  | Unknown-  deriving (Show)--data Status = Status-  { _reviewerStatus :: Approval-  , reviewerName    :: Text-  }--instance Show Status where-  show (Status Approved name) = '+' : read (show name)-  show (Status Rejected name) = '-' : read (show name)-  show (Status Unknown  name) =       read (show name)---fetchHtml :: Manager -> GitHub.SimplePullRequest -> IO Text-fetchHtml mgr pr = do-  let url = Text.unpack $ GitHub.getUrl $ GitHub.simplePullRequestHtmlUrl pr-  -- hPutStrLn stderr $ "fetching " ++ url-  req <- parseRequest url-  decodeUtf8 . LBS.toStrict . responseBody <$> httpLbs req mgr---collectDiscussionItems :: TagTree Text -> [(Text, Text)]-collectDiscussionItems = reverse . go []-  where-    go acc TagLeaf {} = acc--    go acc (TagBranch "div" [("class", cls)] (_ : TagBranch "div" _ (_ : TagBranch "a" [("href", name)] _ : _) : _))-      | Text.isInfixOf "discussion-item-review" cls = (cls, Text.tail name) : acc-    go acc (TagBranch _ _ body) =-      foldl go acc body---extractApprovals :: [Status] -> [(Text, Text)] -> [Status]-extractApprovals = foldl extract-  where-    extract acc (cls, name)-      | Text.isInfixOf "is-rejected" cls = Status Rejected name : acc-      | Text.isInfixOf "is-approved" cls = Status Approved name : acc-      | otherwise = acc---approvalsFromHtml :: [Status] -> Text -> [Status]-approvalsFromHtml statuses =-  nubWith reviewerName-  . extractApprovals statuses-  . collectDiscussionItems-  . TagBranch "xml" []-  . tagTree-  . parseTags-  where-    nubWith f = List.nubBy (\x y -> f x == f y)
− src/changelog.hs
@@ -1,158 +0,0 @@-{-# LANGUAGE LambdaCase        #-}-{-# LANGUAGE OverloadedStrings #-}-module Main (main) where--import           Control.Applicative     ((<$>), (<*>))-import           Control.Arrow           (first, second, (&&&))-import qualified Data.ByteString.Char8   as BS8-import           Data.List               (foldl')-import qualified Data.Map                as Map-import qualified Data.Maybe              as Maybe-import           Data.Monoid             ((<>))-import           Data.String             (fromString)-import           Data.Text               (Text)-import qualified Data.Text               as Text-import qualified Data.Vector             as V-import qualified GitHub-import           Network.HTTP.Client     (newManager)-import           Network.HTTP.Client.TLS (tlsManagerSettings)-import           System.Environment      (getArgs, lookupEnv)--- import           Text.Groom              (groom)--import           Requests---type ChangeLog = [(Text, [Text], [Text])]---formatChangeLog :: Text -> ChangeLog -> Text-formatChangeLog name = (<> "\n") . foldl' (<>) ("# Changelog for " <> name) . map formatMilestone-  where-    formatMilestone (milestone, issues, pulls) =-      "\n\n## " <> milestone-      <> closedIssues issues-      <> mergedPrs pulls--    closedIssues [] = ""-    closedIssues issues =-      foldl' (<>) "\n\n### Closed issues:\n" . itemise $ issues--    mergedPrs [] = ""-    mergedPrs pulls =-      foldl' (<>) "\n\n### Merged PRs:\n" . itemise $ pulls--    itemise = map ("\n- " <>)---data ChangeLogItemKind-  = PullRequest-  | Issue-  deriving Show---data ChangeLogItem = ChangeLogItem-  { clMilestone :: Text-  , clTitle     :: Text-  , clNumber    :: Int-  }---formatChangeLogItem :: GitHub.Name GitHub.Owner -> GitHub.Name GitHub.Repo -> ChangeLogItem -> Text-formatChangeLogItem ownerName repoName item =-  "[#" <> number <> "](https://github.com/" <> GitHub.untagName ownerName <> "/" <> GitHub.untagName repoName <> "/issues/" <> number <> ") " <> clTitle item-  where-    number = Text.pack . show . clNumber $ item---makeChangeLog :: GitHub.Name GitHub.Owner -> GitHub.Name GitHub.Repo -> [GitHub.SimplePullRequest] -> [GitHub.Issue] -> ChangeLog-makeChangeLog ownerName repoName pulls issues =-  Map.foldlWithKey (\changes milestone (msIssues, msPulls) ->-      ( milestone-      , map (formatChangeLogItem ownerName repoName) msIssues-      , map (formatChangeLogItem ownerName repoName) msPulls-      ) : changes-    ) []-  . groupByMilestone (first  . (:)) changeLogIssues-  . groupByMilestone (second . (:)) changeLogPrs-  $ Map.empty-  where-    mergedPrs = filter (\case-        GitHub.SimplePullRequest-          { GitHub.simplePullRequestMergedAt = Just _-          } -> True-        _ -> False-      ) pulls--    closedItems = filter (\case-        GitHub.Issue-          { GitHub.issueMilestone = Just GitHub.Milestone-            { GitHub.milestoneState = "closed" }-          } -> True-        _ -> False-      ) issues--    milestoneByIssueId =-      Map.fromList-      . map (GitHub.issueNumber &&& GitHub.milestoneTitle . Maybe.fromJust . GitHub.issueMilestone)-      $ closedItems--    changeLogIssues :: [ChangeLogItem]-    changeLogIssues = Maybe.mapMaybe (\case-        -- filter out PRs-        GitHub.Issue { GitHub.issuePullRequest = Just _ } -> Nothing-        issue -> Just $ ChangeLogItem-          { clMilestone = GitHub.milestoneTitle . Maybe.fromJust . GitHub.issueMilestone $ issue-          , clTitle     = GitHub.issueTitle issue-          , clNumber    = GitHub.issueNumber issue-          }-      ) closedItems--    changeLogPrs :: [ChangeLogItem]-    changeLogPrs = Maybe.mapMaybe (\issue -> do-        milestone <- flip Map.lookup milestoneByIssueId . GitHub.simplePullRequestNumber $ issue-        return $ ChangeLogItem-          { clMilestone = milestone-          , clTitle     = GitHub.simplePullRequestTitle issue-          , clNumber    = GitHub.simplePullRequestNumber issue-          }-      ) mergedPrs--    groupByMilestone add = flip $ foldr (\item group ->-        Map.insert (clMilestone item) (-            case Map.lookup (clMilestone item) group of-              Just old -> add item old-              Nothing  -> add item ([], [])-          ) group-      )---fetchChangeLog :: GitHub.Name GitHub.Owner -> GitHub.Name GitHub.Repo -> IO ChangeLog-fetchChangeLog ownerName repoName = do-  -- Get auth token from the $GITHUB_TOKEN environment variable.-  auth <- fmap (GitHub.OAuth . BS8.pack) <$> lookupEnv "GITHUB_TOKEN"--  -- Initialise HTTP manager so we can benefit from keep-alive connections.-  mgr <- newManager tlsManagerSettings--  let pulls  = V.toList <$> request auth mgr (GitHub.pullRequestsForR ownerName repoName GitHub.stateClosed GitHub.FetchAll)-  let issues = V.toList <$> request auth mgr (GitHub.issuesForRepoR   ownerName repoName (GitHub.stateClosed <> GitHub.optionsAnyMilestone) GitHub.FetchAll)--  -- issues >>= putStrLn . groom--  makeChangeLog ownerName repoName <$> pulls <*> issues---main :: IO ()-main = do-  (ownerName, repoName) <- getArgs >>= repoLocation-  let name = (GitHub.untagName ownerName) <> "/" <> (GitHub.untagName repoName)--  fetchChangeLog ownerName repoName >>= putStr . Text.unpack . formatChangeLog name--  where-    repoLocation [] =-      return ("TokTok", "c-toxcore")-    repoLocation [ownerName, repoName] =-      return (fromString ownerName, fromString repoName)-    repoLocation _ =-      fail "Usage: changelog <owner> <repo>"
− src/pull-status.hs
@@ -1,92 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-module Main (main) where--import           Control.Applicative     ((<$>))-import qualified Control.Monad.Parallel  as Parallel-import qualified Data.ByteString.Char8   as BS8-import           Data.Time.Clock         (getCurrentTime)-import qualified Data.Vector             as V-import qualified GitHub-import qualified GitHub.Data.Id          as GitHub-import           Network.HTTP.Client     (Manager, newManager)-import           Network.HTTP.Client.TLS (tlsManagerSettings)-import           System.Environment      (getEnv, lookupEnv)--import           PullRequestInfo         (PullRequestInfo (PullRequestInfo))-import qualified PullRequestInfo-import           Requests-import qualified Review---getFullPr-  :: GitHub.Auth-  -> Manager-  -> GitHub.Name GitHub.Owner-  -> GitHub.Name GitHub.Repo-  -> GitHub.SimplePullRequest-  -> IO GitHub.PullRequest-getFullPr auth mgr owner repo simplePr = do-  request (Just auth) mgr-    . GitHub.pullRequestR owner repo-    . GitHub.Id-    . GitHub.simplePullRequestNumber-    $ simplePr---getPrInfo-  :: GitHub.Auth-  -> Manager-  -> GitHub.Name GitHub.Owner-  -> GitHub.Name GitHub.Repo-  -> GitHub.SimplePullRequest-  -> IO ([Review.Status], GitHub.PullRequest)-getPrInfo auth mgr ownerName repoName pr = do-  -- Use assignees as the initial approvals list, all responses unknown.-  let assignees = V.toList $ GitHub.simplePullRequestAssignees pr-  let initApprovals = map (Review.Status Review.Unknown . GitHub.untagName . GitHub.simpleUserLogin) assignees-  -- Fetch and parse HTML pages for this PR.-  approvals <- Review.approvalsFromHtml initApprovals <$> Review.fetchHtml mgr pr-  -- Get more information that is only in the PullRequest response.-  fullPr <- getFullPr auth mgr ownerName repoName pr-  return (approvals, fullPr)---getPrsForRepo-  :: GitHub.Auth-  -> Manager-  -> GitHub.Name GitHub.Owner-  -> GitHub.Name GitHub.Repo-  -> IO [PullRequestInfo]-getPrsForRepo auth mgr ownerName repoName = do-  -- Get PR list.-  simplePRs <- V.toList <$> request (Just auth) mgr (GitHub.pullRequestsForR ownerName repoName GitHub.stateOpen GitHub.FetchAll)--  prInfos <- Parallel.mapM (getPrInfo auth mgr ownerName repoName) simplePRs--  return $ map (uncurry $ PullRequestInfo repoName) prInfos---main :: IO ()-main = do-  let orgName = "TokTok"-  let ownerName = "TokTok"--  -- Get auth token from the $GITHUB_TOKEN environment variable.-  token <- BS8.pack <$> getEnv "GITHUB_TOKEN"-  let auth = GitHub.OAuth token--  -- Check if we need to produce HTML or ASCII art.-  wantHtml <- (/= Nothing) <$> lookupEnv "GITHUB_WANT_HTML"--  -- Initialise HTTP manager so we can benefit from keep-alive connections.-  mgr <- newManager tlsManagerSettings--  -- Get repo list.-  repos <- V.toList <$> request (Just auth) mgr (GitHub.organizationReposR orgName GitHub.RepoPublicityAll GitHub.FetchAll)-  let repoNames = map GitHub.repoName repos--  infos <- Parallel.mapM (getPrsForRepo auth mgr ownerName) repoNames--  -- Pretty-print table with information.-  now <- getCurrentTime-  putStrLn $ PullRequestInfo.formatPR wantHtml now infos
+ test/GitHub/Types/BaseSpec.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE Trustworthy         #-}+module GitHub.Types.BaseSpec where++import           Data.Aeson        (decode, encode)+import           Test.Hspec        (Spec, describe, it, parallel, shouldBe)+import qualified Test.QuickCheck   as QC++import           GitHub.Types.Base++property :: QC.Testable prop => prop -> QC.Property+property = QC.withMaxSuccess 20 . QC.property++spec :: Spec+spec =+  describe "identity JSON conversion" $ parallel $ do+    it "Author"             $ property $ \(x :: Author            ) -> decode (encode x) `shouldBe` Just x+    it "Branch"             $ property $ \(x :: Branch            ) -> decode (encode x) `shouldBe` Just x+    it "Change"             $ property $ \(x :: Change            ) -> decode (encode x) `shouldBe` Just x+    it "Changes"            $ property $ \(x :: Changes           ) -> decode (encode x) `shouldBe` Just x+    it "Commit"             $ property $ \(x :: Commit            ) -> decode (encode x) `shouldBe` Just x+    it "CommitComment"      $ property $ \(x :: CommitComment     ) -> decode (encode x) `shouldBe` Just x+    it "CommitDetails"      $ property $ \(x :: CommitDetails     ) -> decode (encode x) `shouldBe` Just x+    it "CommitRef"          $ property $ \(x :: CommitRef         ) -> decode (encode x) `shouldBe` Just x+    it "CommitRefHtml"      $ property $ \(x :: CommitRefHtml     ) -> decode (encode x) `shouldBe` Just x+    -- DateTime is not an object, so we put it in a list. Valid JSON starts with+    -- either { for object or [ for array. DateTime is either a plain int or a+    -- plain string.+    it "DateTime"           $ property $ \(x :: [DateTime]        ) -> decode (encode x) `shouldBe` Just x+    it "Deployment"         $ property $ \(x :: Deployment        ) -> decode (encode x) `shouldBe` Just x+    it "DeploymentStatus"   $ property $ \(x :: DeploymentStatus  ) -> decode (encode x) `shouldBe` Just x+    it "Hook"               $ property $ \(x :: Hook              ) -> decode (encode x) `shouldBe` Just x+    it "HookConfig"         $ property $ \(x :: HookConfig        ) -> decode (encode x) `shouldBe` Just x+    it "Invitation"         $ property $ \(x :: Invitation        ) -> decode (encode x) `shouldBe` Just x+    it "Issue"              $ property $ \(x :: Issue             ) -> decode (encode x) `shouldBe` Just x+    it "IssueComment"       $ property $ \(x :: IssueComment      ) -> decode (encode x) `shouldBe` Just x+    it "Label"              $ property $ \(x :: Label             ) -> decode (encode x) `shouldBe` Just x+    it "Link"               $ property $ \(x :: Link              ) -> decode (encode x) `shouldBe` Just x+    it "Membership"         $ property $ \(x :: Membership        ) -> decode (encode x) `shouldBe` Just x+    it "Milestone"          $ property $ \(x :: Milestone         ) -> decode (encode x) `shouldBe` Just x+    it "Organization"       $ property $ \(x :: Organization      ) -> decode (encode x) `shouldBe` Just x+    it "PageBuild"          $ property $ \(x :: PageBuild         ) -> decode (encode x) `shouldBe` Just x+    it "PageBuildError"     $ property $ \(x :: PageBuildError    ) -> decode (encode x) `shouldBe` Just x+    it "PullRequest"        $ property $ \(x :: PullRequest       ) -> decode (encode x) `shouldBe` Just x+    it "PullRequestLinks"   $ property $ \(x :: PullRequestLinks  ) -> decode (encode x) `shouldBe` Just x+    it "PullRequestRef"     $ property $ \(x :: PullRequestRef    ) -> decode (encode x) `shouldBe` Just x+    it "PushCommit"         $ property $ \(x :: PushCommit        ) -> decode (encode x) `shouldBe` Just x+    it "Release"            $ property $ \(x :: Release           ) -> decode (encode x) `shouldBe` Just x+    it "RepoOwner"          $ property $ \(x :: RepoOwner         ) -> decode (encode x) `shouldBe` Just x+    it "Repository"         $ property $ \(x :: Repository        ) -> decode (encode x) `shouldBe` Just x+    it "Review"             $ property $ \(x :: Review            ) -> decode (encode x) `shouldBe` Just x+    it "ReviewComment"      $ property $ \(x :: ReviewComment     ) -> decode (encode x) `shouldBe` Just x+    it "ReviewCommentLinks" $ property $ \(x :: ReviewCommentLinks) -> decode (encode x) `shouldBe` Just x+    it "ReviewLinks"        $ property $ \(x :: ReviewLinks       ) -> decode (encode x) `shouldBe` Just x+    it "SimplePullRequest"  $ property $ \(x :: SimplePullRequest ) -> decode (encode x) `shouldBe` Just x+    it "StatusCommit"       $ property $ \(x :: StatusCommit      ) -> decode (encode x) `shouldBe` Just x+    it "Team"               $ property $ \(x :: Team              ) -> decode (encode x) `shouldBe` Just x+    it "User"               $ property $ \(x :: User              ) -> decode (encode x) `shouldBe` Just x+    it "UserRef"            $ property $ \(x :: UserRef           ) -> decode (encode x) `shouldBe` Just x+    it "UserStamp"          $ property $ \(x :: UserStamp         ) -> decode (encode x) `shouldBe` Just x
+ test/GitHub/Types/EventsSpec.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE Trustworthy         #-}+module GitHub.Types.EventsSpec where++import           Data.Aeson          (decode, encode)+import           Test.Hspec          (Spec, describe, it, parallel, shouldBe)+import qualified Test.QuickCheck     as QC++import           GitHub.Types.Events++property :: QC.Testable prop => prop -> QC.Property+property = QC.withMaxSuccess 20 . QC.property+++spec :: Spec+spec =+  describe "identity JSON conversion" $ parallel $ do+    it "CommitCommentEvent"            $ property $ \(x :: CommitCommentEvent           ) -> decode (encode x) `shouldBe` Just x+    it "CreateEvent"                   $ property $ \(x :: CreateEvent                  ) -> decode (encode x) `shouldBe` Just x+    it "DeleteEvent"                   $ property $ \(x :: DeleteEvent                  ) -> decode (encode x) `shouldBe` Just x+    it "DeploymentEvent"               $ property $ \(x :: DeploymentEvent              ) -> decode (encode x) `shouldBe` Just x+    it "DeploymentStatusEvent"         $ property $ \(x :: DeploymentStatusEvent        ) -> decode (encode x) `shouldBe` Just x+    it "ForkEvent"                     $ property $ \(x :: ForkEvent                    ) -> decode (encode x) `shouldBe` Just x+    it "GollumEvent"                   $ property $ \(x :: GollumEvent                  ) -> decode (encode x) `shouldBe` Just x+    it "IssueCommentEvent"             $ property $ \(x :: IssueCommentEvent            ) -> decode (encode x) `shouldBe` Just x+    it "IssuesEvent"                   $ property $ \(x :: IssuesEvent                  ) -> decode (encode x) `shouldBe` Just x+    it "LabelEvent"                    $ property $ \(x :: LabelEvent                   ) -> decode (encode x) `shouldBe` Just x+    it "MemberEvent"                   $ property $ \(x :: MemberEvent                  ) -> decode (encode x) `shouldBe` Just x+    it "MembershipEvent"               $ property $ \(x :: MembershipEvent              ) -> decode (encode x) `shouldBe` Just x+    it "MilestoneEvent"                $ property $ \(x :: MilestoneEvent               ) -> decode (encode x) `shouldBe` Just x+    it "OrganizationEvent"             $ property $ \(x :: OrganizationEvent            ) -> decode (encode x) `shouldBe` Just x+    it "PageBuildEvent"                $ property $ \(x :: PageBuildEvent               ) -> decode (encode x) `shouldBe` Just x+    it "PingEvent"                     $ property $ \(x :: PingEvent                    ) -> decode (encode x) `shouldBe` Just x+    it "PullRequestEvent"              $ property $ \(x :: PullRequestEvent             ) -> decode (encode x) `shouldBe` Just x+    it "PullRequestReviewCommentEvent" $ property $ \(x :: PullRequestReviewCommentEvent) -> decode (encode x) `shouldBe` Just x+    it "PullRequestReviewEvent"        $ property $ \(x :: PullRequestReviewEvent       ) -> decode (encode x) `shouldBe` Just x+    it "PushEvent"                     $ property $ \(x :: PushEvent                    ) -> decode (encode x) `shouldBe` Just x+    it "ReleaseEvent"                  $ property $ \(x :: ReleaseEvent                 ) -> decode (encode x) `shouldBe` Just x+    it "RepositoryEvent"               $ property $ \(x :: RepositoryEvent              ) -> decode (encode x) `shouldBe` Just x+    it "StatusEvent"                   $ property $ \(x :: StatusEvent                  ) -> decode (encode x) `shouldBe` Just x+    it "WatchEvent"                    $ property $ \(x :: WatchEvent                   ) -> decode (encode x) `shouldBe` Just x
+ test/testsuite.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ tools/hub-automerge.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE NamedFieldPuns    #-}+{-# LANGUAGE OverloadedStrings #-}+module Main (main) where++import           Data.String            (fromString)+import           System.Environment     (getArgs, getEnv)++import           GitHub.Tools.AutoMerge (autoMergeAll, autoMergePullRequest)+++main :: IO ()+main = do+    -- Get auth token from the $GITHUB_TOKEN environment variable.+    args <- getArgs+    token <- getEnv "GITHUB_TOKEN"+    case args of+      []     -> autoMergeAll "TokTok" "TokTok" token+      [repo] -> autoMergePullRequest token "TokTok" (fromString repo)+      _      -> error "Usage: hub-automerge [repo] [author]"
+ tools/hub-changelog.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE OverloadedStrings #-}+module Main (main) where++import qualified Data.ByteString.Char8   as BS8+import           Data.String             (fromString)+import qualified Data.Text.IO            as Text+import qualified GitHub+import           System.Environment      (getArgs, lookupEnv)++import           GitHub.Tools.Changelogs+++main :: IO ()+main = do+  (ownerName, repoName) <- getArgs >>= repoLocation++  -- Get auth token from the $GITHUB_TOKEN environment variable.+  auth <- fmap (GitHub.OAuth . BS8.pack) <$> lookupEnv "GITHUB_TOKEN"++  fetchChangeLog False ownerName repoName auth >>= Text.putStr . formatChangeLog False++  where+    repoLocation [] =+      return ("TokTok", "c-toxcore")+    repoLocation [ownerName, repoName] =+      return (fromString ownerName, fromString repoName)+    repoLocation _ =+      fail "Usage: hub-changelog <owner> <repo>"
+ tools/hub-graph.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE OverloadedStrings #-}+module Main (main) where++import qualified Data.ByteString.Char8     as BS8+import qualified GitHub+import           System.Environment        (lookupEnv)++import           GitHub.Tools.NetworkGraph+++repos :: [(GitHub.Name GitHub.Owner, GitHub.Name GitHub.Repo)]+repos =+    [ ("TokTok", "c-toxcore")+    , ("irungentoo", "toxcore")+    ]++main :: IO ()+main = do+  -- Get auth token from the $GITHUB_TOKEN environment variable.+  auth <- fmap (GitHub.OAuth . BS8.pack) <$> lookupEnv "GITHUB_TOKEN"+  putStr =<< getNetworkGraph auth repos
+ tools/hub-pulls.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE OverloadedStrings #-}+module Main (main) where++import qualified Data.ByteString.Char8   as BS8+import qualified Data.Text.IO            as Text+import qualified GitHub+import           System.Environment      (getEnv, lookupEnv)++import           GitHub.Tools.PullStatus+++main :: IO ()+main = do+  -- Get auth token from the $GITHUB_TOKEN environment variable.+  auth <- Just . GitHub.OAuth . BS8.pack <$> getEnv "GITHUB_TOKEN"++  -- Check if we need to produce HTML or ASCII art.+  wantHtml <- (/= Nothing) <$> lookupEnv "GITHUB_WANT_HTML"++  Text.putStrLn =<< getPullStatus "TokTok" "TokTok" wantHtml auth
+ tools/hub-roadmap.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE OverloadedStrings #-}+module Main (main) where++import qualified Data.ByteString.Char8   as BS8+import           Data.String             (fromString)+import qualified Data.Text.IO            as Text+import qualified GitHub+import           System.Environment      (getArgs, lookupEnv)++import           GitHub.Tools.Changelogs+++main :: IO ()+main = do+  (ownerName, repoName) <- getArgs >>= repoLocation++  -- Get auth token from the $GITHUB_TOKEN environment variable.+  auth <- fmap (GitHub.OAuth . BS8.pack) <$> lookupEnv "GITHUB_TOKEN"++  fetchChangeLog True ownerName repoName auth >>= Text.putStr . formatChangeLog True++  where+    repoLocation [] =+      return ("TokTok", "c-toxcore")+    repoLocation [ownerName, repoName] =+      return (fromString ownerName, fromString repoName)+    repoLocation _ =+      fail "Usage: hub-roadmap <owner> <repo>"
+ web/TokTok/Handlers.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StrictData        #-}+module TokTok.Handlers+  ( handleEvent+  ) where++import           Data.Text              (Text)+import           GitHub.Data.Name       (Name (..))+import           GitHub.Tools.AutoMerge (autoMergePullRequest)+import           GitHub.Types           (CheckSuite (..), CheckSuiteEvent (..),+                                         Payload (..), Repository (..))+import           System.Environment     (getEnv)+++handleEvent :: Payload -> Maybe (Text, IO ())+handleEvent (CheckSuiteEventPayload (CheckSuiteEvent+    { checkSuiteEventCheckSuite = CheckSuite+        { checkSuiteConclusion = Just "success"+        , checkSuiteHeadBranch = branch+        }+    , checkSuiteEventRepository = Repository{ repositoryName = repo }+    })) | branch /= Just "master" =+        Just (repo, do+            -- Get auth token from the $GITHUB_TOKEN environment variable.+            token <- getEnv "GITHUB_TOKEN"+            autoMergePullRequest token "TokTok" (N repo))++handleEvent _ = Nothing
+ web/TokTok/Hello.hs view
@@ -0,0 +1,117 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE StrictData            #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+module TokTok.Hello (newApp) where++import           Caching.ExpiringCacheMap.HashECM (CacheSettings (..), ECM,+                                                   consistentDuration,+                                                   lookupECM, newECMIO)+import           Control.Concurrent.MVar          (MVar)+import           Control.Monad.IO.Class           (liftIO)+import qualified Data.ByteString.Char8            as BS8+import qualified Data.ByteString.Lazy             as LBS+import           Data.HashMap.Strict              (HashMap)+import           Data.Text                        (Text)+import           Data.Text.Encoding               (encodeUtf8)+import qualified Data.Time.Clock.POSIX            as POSIX+import qualified GitHub+import           Network.HTTP.Media               ((//), (/:))+import           Servant+import           System.Environment               (getEnv)++import qualified GitHub.Tools.Changelogs          as Changelogs+import qualified GitHub.Tools.NetworkGraph        as NetworkGraph+import           GitHub.Tools.PullRequestInfo     (PullRequestInfo)+import qualified GitHub.Tools.PullStatus          as PullStatus+++type GitHubCache a = ECM IO MVar () HashMap () a+++data ApiContext = ApiContext+    { changelogInfo :: GitHubCache Changelogs.ChangeLog+    , roadmapInfo   :: GitHubCache Changelogs.ChangeLog+    , pullInfos     :: GitHubCache [[PullRequestInfo]]+    , networkGraph  :: GitHubCache String+    }+++newGitHubCache :: Int -> IO a -> IO (GitHubCache a)+newGitHubCache timeout fetchUpdates = newECMIO+    (consistentDuration timeout $ \state () -> do+        infos <- fetchUpdates+        return (state, infos)+    )+    (round <$> POSIX.getPOSIXTime)+    1+    (CacheWithLRUList 1 1 1)+++newContext :: IO ApiContext+newContext = do+    auth <- Just . GitHub.OAuth . BS8.pack <$> getEnv "GITHUB_TOKEN"++    ApiContext+        <$> newGitHubCache 300 (Changelogs.fetchChangeLog False "TokTok" "c-toxcore" auth)+        <*> newGitHubCache 300 (Changelogs.fetchChangeLog True  "TokTok" "c-toxcore" auth)+        <*> newGitHubCache  30 (PullStatus.getPullInfos "TokTok" "TokTok" auth)+        <*> newGitHubCache 900 (NetworkGraph.getNetworkGraph auth [("TokTok", "c-toxcore"), ("irungentoo", "toxcore")])+++data HTML+instance Accept HTML where+    contentType _ = "text" // "html" /: ("charset", "utf-8")+instance MimeRender HTML Text where+    mimeRender _ = LBS.fromStrict . encodeUtf8++-- API specification+type TestApi =+       -- Link to the source code repository, to comply with AGPL.+       "source" :> Get '[PlainText] Text+  :<|> "changelog" :> Get '[PlainText] Text+  :<|> "roadmap" :> Get '[PlainText] Text+  :<|> "pulls.html" :> Get '[HTML] Text+  :<|> "pulls" :> Get '[JSON] [[PullRequestInfo]]+  :<|> "network" :> Get '[PlainText] String++testApi :: Proxy TestApi+testApi = Proxy++-- Server-side handlers.+--+-- There's one handler per endpoint, which, just like in the type+-- that represents the API, are glued together using :<|>.+--+-- Each handler runs in the 'Handler' monad.+server :: ApiContext -> Server TestApi+server ctx =+       sourceH+  :<|> changelogH+  :<|> roadmapH+  :<|> pullsHtmlH+  :<|> pullsH+  :<|> networkH+  where+    sourceH = return "https://github.com/TokTok/hs-github-tools"++    changelogH = liftIO $+        Changelogs.formatChangeLog False <$> lookupECM (changelogInfo ctx) ()+    roadmapH = liftIO $+        Changelogs.formatChangeLog True  <$> lookupECM (roadmapInfo   ctx) ()+    networkH = liftIO $+        lookupECM (networkGraph ctx) ()++    pullsHtmlH = liftIO $ lookupECM (pullInfos ctx) () >>= PullStatus.showPullInfos True+    pullsH = liftIO $ lookupECM (pullInfos ctx) ()++-- Turn the server into a WAI app. 'serve' is provided by servant,+-- more precisely by the Servant.Server module.+app :: ApiContext -> Application+app = serve testApi . server++newApp :: IO Application+newApp = app <$> newContext
+ web/TokTok/Webhooks.hs view
@@ -0,0 +1,152 @@+{-# LANGUAGE OverloadedStrings #-}+module TokTok.Webhooks (newApp) where++import           Control.Concurrent.MVar    (MVar, modifyMVar_, newMVar,+                                             swapMVar)+import           Control.Concurrent.Suspend (sDelay)+import           Control.Concurrent.Timer   (TimerIO, oneShotRestart,+                                             oneShotTimer)+import qualified Data.Aeson.Encode.Pretty   as Aeson+import qualified Data.Algorithm.DiffContext as Diff+import qualified Data.ByteString            as BS+import qualified Data.ByteString.Lazy       as LBS+import qualified Data.CaseInsensitive       as CI+import           Data.Map                   (Map)+import qualified Data.Map                   as Map+import qualified Data.Maybe                 as Maybe+import           Data.Text                  (Text)+import qualified Data.Text                  as Text+import qualified Data.Text.Encoding         as Text (decodeUtf8With, encodeUtf8)+import qualified Data.Text.Encoding.Error   as Text (lenientDecode)+import qualified Data.Text.IO               as Text+import           Data.UUID                  (UUID)+import           GitHub.Types               (Payload (..))+import           GitHub.WebHook.Handler     (Error (..), Handler (..),+                                             removeNulls, runHandler)+import           Network.HTTP.Types         (HeaderName, status200, status501)+import           Network.Wai                (Application, Request, Response,+                                             getRequestBodyChunk,+                                             requestHeaders, responseLBS)+import           System.Environment         (lookupEnv)+import qualified Text.PrettyPrint           as PP+import           TokTok.Handlers            (handleEvent)+++responseOK :: Response+responseOK = responseLBS status200 [("Content-Type", "text/plain")] "OK"++responseError :: LBS.ByteString -> Response+responseError = responseLBS status501 [("Content-Type", "text/plain")]+++decodeUtf8 :: BS.ByteString -> Text+decodeUtf8 = Text.decodeUtf8With Text.lenientDecode+++showDiff :: Text -> Text -> Text+showDiff a b = Text.pack . PP.render . toDoc $ diff+  where+    toDoc = Diff.prettyContextDiff (PP.text "payload")+                                   (PP.text "value")+                                   (PP.text . Text.unpack)+    diff = Diff.getContextDiff linesOfContext (Text.lines a) (Text.lines b)+    linesOfContext = 3+++showError :: Error -> Text+showError InvalidRequest   = "InvalidRequest"+showError UnsignedRequest  = "UnsignedRequest"+showError InvalidSignature = "InvalidSignature"+showError (ParseError err) = "ParseError " <> (Text.pack . show $ err)+showError (IncompleteParse value payload) =+    let a    = json . removeNulls $ payload+        b    = json . removeNulls $ value+        diff = showDiff a b+    in  "IncompleteParse:"+            <> "\n=== Diff ===\n"+            <> diff+            {-+            <> "\n=== Payload ===\n"+            <> a+            <> "\n=== Value ===\n"+            <> b+            -}+    where json = decodeUtf8 . LBS.toStrict . Aeson.encodePretty+++handleError+    :: BS.ByteString -> [(HeaderName, BS.ByteString)] -> Error -> IO Response+handleError event headers err = do+    let res = showError err+    Text.putStrLn $ "Failure in event " <> Text.pack (show event) <> ": " <> res+    Text.putStrLn $ "HTTP headers: " <> Text.pack (show headers)+    return . responseError . LBS.fromStrict . Text.encodeUtf8 $ res+++handlePayload :: (Payload -> IO Response) -> Bool -> BS.ByteString -> UUID -> Payload -> IO Response+handlePayload f isSigned event uuid payload = do+    Text.putStrLn+        $  unsignedMsg+        <> "Success in event "+        <> Text.pack (show event)+        <> ": UUID="+        <> Text.pack (show uuid)+    f payload+    where unsignedMsg = if isSigned then "" else "[UNSIGNED!] "+++handleRequest :: (Payload -> IO Response) -> BS.ByteString -> [String] -> Request -> IO Response+handleRequest f event secretKeys req = do+    body   <- fullRequestBody mempty+    parsed <- runHandler Handler+        { hSecretKeys = secretKeys+        , hBody       = return body+        , hHeader     = return . flip lookup (requestHeaders req) . CI.mk+        }+    case parsed of+        Left err -> handleError event (requestHeaders req) err+        Right (uuid, payload) ->+            handlePayload f (not $ null secretKeys) event uuid payload++  where+    fullRequestBody body = do+        chunk <- getRequestBodyChunk req+        if BS.null chunk then return body else fullRequestBody $ body <> chunk+++app :: (Payload -> IO Response) -> Application+app f req respond = case lookup "X-GitHub-Event" . requestHeaders $ req of+    Nothing -> do+        -- Respond OK if we don't get an event.+        putStrLn "Ignoring request without event type"+        respond responseOK+    Just event -> do+        putStrLn $ "Handling GitHub event: " ++ show event+        -- Get the github secret keys.+        secretKeys <- Maybe.maybeToList <$> lookupEnv "GITHUB_SECRET"+        respond =<< handleRequest f event secretKeys req++newApp :: IO Application+newApp = do+    -- Initialise task queue+    tasks <- newMVar Map.empty+    -- Start the task queue processing timer.+    timer <- oneShotTimer (processTasks tasks) (sDelay 30)  -- after 30 seconds+    return $ app (addTasks timer tasks)+  where+    processTasks :: MVar (Map Text (IO ())) -> IO ()+    processTasks tasks = do+        todo <- swapMVar tasks Map.empty+        putStrLn $ "processing " <> show (Map.size todo) <> " background tasks"+        sequence_ $ Map.elems todo++    addTasks :: TimerIO -> MVar (Map Text (IO ())) -> Payload -> IO Response+    addTasks timer tasks payload =+        case handleEvent payload of+            Nothing -> return responseOK+            Just (key, task) -> do+                modifyMVar_ tasks $ return . Map.insert key task+                success <- oneShotRestart timer+                return $ if success+                    then responseOK+                    else responseError "failed to start background processing task"
+ web/webservice.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE OverloadedStrings #-}+module Main (main) where++import           Control.Applicative         ((<|>))+import           Network.Wai                 (Application)+import           Network.Wai.Handler.Warp    (Port, run)+import           Network.Wai.Middleware.Cors (simpleCors)+import           Network.Wai.UrlMap          (mapUrls, mount)+import           System.Environment          (getArgs, getEnv)+import           System.IO                   (BufferMode (..), hSetBuffering,+                                              stdout)++import qualified TokTok.Hello                as Hello+import qualified TokTok.Webhooks             as Webhooks+++newApp :: IO Application+newApp = do+    hello <- simpleCors <$> Hello.newApp+    webhooks <- Webhooks.newApp+    return $ mapUrls $+            mount "hello" hello+        <|> mount "webhooks" webhooks+++-- Run the server.+runTestServer :: Port -> IO ()+runTestServer port = do+    putStrLn $ "Running webserver on port " ++ show port+    run port =<< newApp++-- Put this all to work!+main :: IO ()+main = do+  -- So real time logging works correctly.+    hSetBuffering stdout LineBuffering+    args <- getArgs+    case args of+        [port] -> runTestServer $ read port+        _      -> runTestServer =<< read <$> getEnv "PORT"