packages feed

distribution-opensuse (empty) → 1.0.0

raw patch · 20 files changed

+662/−0 lines, 20 filesdep +Diffdep +aesondep +basesetup-changed

Dependencies added: Diff, aeson, base, binary, bytestring, containers, deepseq, distribution-opensuse, extra, foldl, hashable, hsemail, mtl, parsec-class, pretty, text, time, turtle

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2018, Peter Simons++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Peter Simons nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,9 @@+distribution-opensuse+=====================++[![hackage release](https://img.shields.io/hackage/v/distribution-opensuse.svg?label=hackage)](http://hackage.haskell.org/package/distribution-opensuse)+[![stackage LTS package](http://stackage.org/package/distribution-opensuse/badge/lts)](http://stackage.org/lts/package/distribution-opensuse)+[![stackage Nightly package](http://stackage.org/package/distribution-opensuse/badge/nightly)](http://stackage.org/nightly/package/distribution-opensuse)+[![travis build status](https://img.shields.io/travis/peti/distribution-opensuse/master.svg?label=travis+build)](https://travis-ci.org/peti/distribution-opensuse)++Types, functions, and tools to manipulate the openSUSE distribution.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ distribution-opensuse.cabal view
@@ -0,0 +1,64 @@+name:               distribution-opensuse+version:            1.0.0+synopsis:           Types, functions, and tools to manipulate the openSUSE distribution+description:        Types, functions, and tools to manipulate the openSUSE distribution.+license:            BSD3+license-file:       LICENSE+author:             Peter Simons+maintainer:         simons@cryp.to+tested-with:        GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.3+category:           Distribution+homepage:           https://github.com/peti/distribution-opensuse/+build-type:         Simple+extra-source-files: README.md+                    tests/run-tests+                    tests/guess-changelog/*.test+cabal-version:      >= 1.10++source-repository head+  type:     git+  location: git://github.com/peti/distribution-opensuse.git++library+  exposed-modules:    OpenSuse.GuessChangeLog+                      OpenSuse.Prelude+                      OpenSuse.Prelude.Parser+                      OpenSuse.Prelude.PrettyPrinting+                      OpenSuse.Prelude.PrettyPrinting.Orphans+                      OpenSuse.Types.ChangeLog+                      OpenSuse.Types.EMailAddress+                      OpenSuse.Types.Issue+                      OpenSuse.Types.PackageName+                      OpenSuse.Types.ProjectId+                      OpenSuse.Types.RequestId+                      OpenSuse.Types.UserName+  hs-source-dirs:     src+  build-depends:      base         < 5+                    , Diff+                    , aeson+                    , binary+                    , bytestring+                    , containers+                    , deepseq+                    , extra+                    , foldl+                    , hashable+                    , hsemail+                    , mtl+                    , parsec-class+                    , pretty+                    , text+                    , time+                    , turtle+  default-language:   Haskell2010+  default-extensions: MonadFailDesugaring+  ghc-options:        -Wall -Wcompat -Wincomplete-uni-patterns -Wincomplete-record-updates+                      -Wredundant-constraints++executable guess-changelog+  main-is:            guess-changelog.hs+  build-depends:      base, containers, distribution-opensuse, text, turtle+  default-language:   Haskell2010+  default-extensions: MonadFailDesugaring+  ghc-options:        -Wall -Wcompat -Wincomplete-uni-patterns -Wincomplete-record-updates+                      -Wredundant-constraints -threaded
+ guess-changelog.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE ApplicativeDo #-}+{-# LANGUAGE OverloadedStrings #-}++module Main ( main ) where++import OpenSuse.GuessChangeLog++import Data.Set ( Set )+import qualified Data.Set as Set+import qualified Data.Text as Text+import qualified Data.Text.IO as Text+import Prelude hiding ( FilePath )+import Turtle hiding ( l )++parser :: Parser (FilePath, FilePath)+parser = do+  old <- argPath "old" "directory containing the old package version"+  new <- argPath "new" "directory containing the new package version"+  pure (old,new)++main :: IO ()+main = do+  (oldDir,newDir) <- options "Guess the change log entry between two version of a package." parser+  result <- guessChangeLog oldDir newDir+  case result of+    Right txt -> Text.putStrLn txt+    Left desc -> case desc of+      NoChangeLogFiles            -> eprintf "no change log files found\n"+      UndocumentedUpdate p        -> eprintf ("file "%fp%" has not changed between releases\n") p+      NoCommonChangeLogFiles l r  -> eprintf ("both directories have no files in common: "%fps%" vs. "%fps%"\n") l r+      MoreThanOneChangeLogFile p  -> eprintf ("too many changelog files: "%fps%"\n") p+      UnmodifiedTopIsTooLarge p n -> eprintf (fp%" has more than 10 unmodified lines at top: "%d%"\n") p n+      NotJustTopAdditions p       -> eprintf (fp%" has more edits than just adding at the top\n") p++-- * Utility Functions++fps :: Format r (Set FilePath -> r)+fps = makeFormat (Text.intercalate ", " . map (format fp) . Set.toAscList)
+ src/OpenSuse/GuessChangeLog.hs view
@@ -0,0 +1,76 @@+{-# LANGUAGE ApplicativeDo #-}+{-# LANGUAGE OverloadedStrings #-}++module OpenSuse.GuessChangeLog ( guessChangeLog, GuessedChangeLog(..) ) where++import qualified Control.Foldl as Fold+import Control.Monad.Except+import Data.Algorithm.Diff+import Data.Set ( Set )+import qualified Data.Set as Set+import qualified Data.Text as Text+import Prelude hiding ( FilePath )+import Turtle hiding ( l, x )++guessChangeLog :: FilePath -> FilePath -> IO (Either GuessedChangeLog Text)+guessChangeLog oldDir newDir = runExceptT $ do+  oldCLF <- Set.fromList <$> listShell (findChangeLogFiles oldDir)+  newCLF <- Set.fromList <$> listShell (findChangeLogFiles newDir)+  when (all null [oldCLF,newCLF]) (throwError NoChangeLogFiles)+  let clf' = oldCLF `Set.intersection` newCLF+  clf <- case Set.toAscList clf' of+           []    -> throwError (NoCommonChangeLogFiles oldCLF newCLF)+           [clf] -> return clf+           _     -> throwError (MoreThanOneChangeLogFile clf')+  (oec,old) <- shellStrict (format ("git stripspace < "%fp) (oldDir </> clf)) empty+  (nec,new) <- shellStrict (format ("git stripspace < "%fp) (newDir </> clf)) empty+  unless (all (== ExitSuccess) [oec,nec]) $+    -- TODO: Throw a proper exception here, or even don't even rely on git-stripspace.+    die (format ("git stripspace failed with "%w%"\n") oec)+  let changes    = cleanupEmptyLines (getDiff (Text.lines old) (Text.lines new))+      (top,diff) = span inBoth changes+      (add,foot) = span inSecond diff+      topAddOnly = all inBoth foot+  when (all inBoth changes) (throwError (UndocumentedUpdate clf))+  unless (length top < 10) (throwError (UnmodifiedTopIsTooLarge clf (fromIntegral (length top))))+  unless topAddOnly (throwError (NotJustTopAdditions clf))+  return (Text.strip (Text.unlines (map unDiff add)))++data GuessedChangeLog = NoChangeLogFiles+                      | UndocumentedUpdate FilePath+                      | NoCommonChangeLogFiles (Set FilePath) (Set FilePath)+                      | MoreThanOneChangeLogFile (Set FilePath)+                      | UnmodifiedTopIsTooLarge FilePath Word+                      | NotJustTopAdditions FilePath+  deriving (Show)++cleanupEmptyLines :: [Diff Text] -> [Diff Text]+cleanupEmptyLines []                                        = []+cleanupEmptyLines (Second t1 : Both "" "" : Second t2 : xs) = Second t1 : Second "" : Second t2 : cleanupEmptyLines xs+cleanupEmptyLines (First  t1 : Both "" "" : First  t2 : xs) = First  t1 : First  "" : First  t2 : cleanupEmptyLines xs+cleanupEmptyLines (x:xs)                                    = x : cleanupEmptyLines xs++inBoth :: Diff a -> Bool+inBoth (Both _ _)   = True+inBoth _            = False++inSecond :: Diff a -> Bool+inSecond (Second _) = True+inSecond _          = False++unDiff :: Diff a -> a+unDiff (First txt)  = txt+unDiff (Both txt _) = txt+unDiff (Second txt) = txt++findChangeLogFiles :: FilePath -> Shell FilePath+findChangeLogFiles dirPath =+  onFiles (grepText changelogFilePattern) (filename <$> ls dirPath)++changelogFilePattern :: Pattern Text+changelogFilePattern = star dot <> asciiCI "change" <> star dot++-- * Utility Functions++listShell :: MonadIO io => Shell a -> io [a]+listShell = flip fold Fold.list
+ src/OpenSuse/Prelude.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE CPP #-}++module OpenSuse.Prelude+  (+    -- * Standard Prelude+    module Prelude+  , module Control.Monad.Extra+  , module Control.Monad.Fail+  , module Control.Monad.IO.Class+  , module Data.Monoid+  , module Data.Semigroup+  , module Data.Word+  , module GHC.Generics+  , module Numeric.Natural++    -- * Parsing & Pretty Printing+  , Text, LazyText, ByteString, LazyByteString+  , packText, unpackText+  , module OpenSuse.Prelude.Parser+  , module OpenSuse.Prelude.PrettyPrinting+  , module Data.Aeson+  , module Data.String++    -- * Date & Time+  , module Data.Time.Clock++    -- * Container+  , module Data.Set++    -- * Miscellaneous+  , module Control.DeepSeq+  , module Data.Binary+  , module Data.Hashable+  , module Data.Maybe++  )+  where++import Prelude hiding ( fail+#if MIN_VERSION_base(4,11,0)+                      , (<>)  -- https://prime.haskell.org/wiki/Libraries/Proposals/SemigroupMonoid+#endif+                      )++import OpenSuse.Prelude.Parser ( CharParser, HasParser(..), ErrorContext, parseM, parse+                               , runParser, runParserT+                               )+import OpenSuse.Prelude.PrettyPrinting ( Doc, Pretty(pPrint), prettyShow )++import Control.DeepSeq ( NFData )+import Control.Monad.Extra hiding ( fail )+import Control.Monad.Fail+import Control.Monad.IO.Class ( MonadIO(..) )+import Data.Aeson ( FromJSON, ToJSON )+import Data.Binary ( Binary )+import Data.ByteString ( ByteString )+import qualified Data.ByteString.Lazy as LBS+import Data.Hashable ( Hashable )+import Data.Maybe ( fromMaybe )+import Data.Monoid ( Monoid(..) )+import Data.Semigroup ( Semigroup(..) )+import Data.Set ( Set )+import Data.String ( IsString(..) )+import Data.Text ( Text )+import qualified Data.Text as Text+import qualified Data.Text.Lazy as LText+import Data.Time.Clock ( UTCTime(..), DiffTime )+import Data.Word ( Word8 )+import GHC.Generics ( Generic )+import Numeric.Natural ( Natural )++type LazyText = LText.Text+type LazyByteString = LBS.ByteString++packText :: String -> Text+packText = Text.pack++unpackText :: Text -> String+unpackText = Text.unpack
+ src/OpenSuse/Prelude/Parser.hs view
@@ -0,0 +1,3 @@+module OpenSuse.Prelude.Parser ( module Text.Parsec.Class ) where++import Text.Parsec.Class
+ src/OpenSuse/Prelude/PrettyPrinting.hs view
@@ -0,0 +1,11 @@+-- | This is simply a re-export of the standard library @pretty@ with some+-- orphan instances added for convenience.++module OpenSuse.Prelude.PrettyPrinting+  ( module Text.PrettyPrint.HughesPJClass+  )+  where++import OpenSuse.Prelude.PrettyPrinting.Orphans ( )++import Text.PrettyPrint.HughesPJClass
+ src/OpenSuse/Prelude/PrettyPrinting/Orphans.hs view
@@ -0,0 +1,9 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++module OpenSuse.Prelude.PrettyPrinting.Orphans ( ) where++import Numeric.Natural+import Text.PrettyPrint.HughesPJClass++instance Pretty Natural where+  pPrint = text . show
+ src/OpenSuse/Types/ChangeLog.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE DeriveGeneric, GeneralizedNewtypeDeriving #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE NoImplicitPrelude #-}++module OpenSuse.Types.ChangeLog+  ( ChangeLog(..), Entry(..)+  , parseEntry, parseDashedLine, parseDateAddressLine, parseDescription+  )+  where++import OpenSuse.Prelude+import OpenSuse.Prelude.Parser as Parse+import qualified OpenSuse.Prelude.PrettyPrinting as Pretty ( )+import OpenSuse.Types.EMailAddress+import Data.Time.Format++newtype ChangeLog = ChangeLog [Entry]+  deriving (Show, Eq, Ord, Generic, NFData, Semigroup, Monoid)++instance HasParser ChangeLog where+  parser = ChangeLog <$> (parseDashedLine *> many parser)++data Entry = Entry+  { changedAt :: UTCTime+  , changedBy :: EMailAddress+  , changeDescription :: Text+  }+  deriving (Show, Eq, Ord, Generic)++instance NFData Entry++instance HasParser Entry where+  parser = parseEntry++-- * Useful parsers for ChangeLog elements++{-# ANN parseEntry "HLint: ignore Use <$>" #-}+parseEntry :: CharParser st input m Entry+parseEntry = do+  (ts,author) <- parseDateAddressLine+  parseEmptyLine+  txt <- parseDescription+  return (Entry ts author (packText txt))++parseDashedLine :: CharParser st input m ()+parseDashedLine = do+  _ <- string "------------------------------------------------------------"+  skipMany1 (char '-')+  _ <- endOfLine+  return ()++-- | Note that the input must be terminated by a newline.+--+-- >>> parseTest parseDateAddressLine "Wed Jun 27 09:25:07 UTC 2018 - foo@example.org\n"+-- (2018-06-27 09:25:07 UTC,EMailAddress "foo@example.org")+parseDateAddressLine :: CharParser st input m (UTCTime, EMailAddress)+parseDateAddressLine = do+  ts <- many1 (alphaNum <|> oneOf ": ")+  _ <- char '-'+  addr <- parser+  _ <- endOfLine+  utct <- parseTimeM True defaultTimeLocale changeLogDateFormat ts+  return (utct,addr)++-- | Consume an empty line, i.e. a line that contains only whitespace.+parseEmptyLine :: CharParser st input m ()+parseEmptyLine = skipMany (oneOf " \t") <* endOfLine++-- | Consume all text until the end of the file or a dashed line is found. In+-- the latter case, the dashed line is consumed as well. This is unfortunate,+-- but it's how the 'notFollowedBy' combinator works, unfortunately,+parseDescription :: CharParser st input m String+parseDescription = manyTill anyChar (try parseDashedLine <|> eof)++-- | Appropriate format parameter for 'formatTime' and 'parseTimeM'.+changeLogDateFormat :: String+changeLogDateFormat = "%a %b %e %H:%M:%S %Z %Y"
+ src/OpenSuse/Types/EMailAddress.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE DeriveGeneric, GeneralizedNewtypeDeriving #-}++module OpenSuse.Types.EMailAddress+  ( EMailAddress, mkEMailAddress, unEMailAddress+  )+  where++import OpenSuse.Prelude+import OpenSuse.Prelude.PrettyPrinting as Pretty+import Text.Parsec.Rfc2822 ( addr_spec )++-- |+--+-- >>> mkEMailAddress " accept . full (rfc822) . syntax @ example . org "+-- Just (EMailAddress "accept.full.syntax@example.org")+--+-- >>> mkEMailAddress "@this@is@not@good@"+-- Nothing+--+-- >>> prettyShow (fromString "joe @ example.net" :: EMailAddress)+-- "joe@example.net"+newtype EMailAddress = EMailAddress String+  deriving (Show, Eq, Ord, Generic, Hashable, Binary, NFData)++-- | Constructor function for e-mail addresses. Returns 'Nothing' if the input+-- is syntactically invalid.+mkEMailAddress :: String -> Maybe EMailAddress+mkEMailAddress = parseM "e-mail address"++-- | Accessor function for the underlying path of strings.+unEMailAddress :: EMailAddress -> String+unEMailAddress (EMailAddress str) = str++instance HasParser EMailAddress where+  parser = EMailAddress <$> addr_spec++instance IsString EMailAddress where+  fromString = parse "e-mail address"++instance Pretty EMailAddress where+  pPrint = Pretty.text . unEMailAddress
+ src/OpenSuse/Types/Issue.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE DeriveGeneric #-}++module OpenSuse.Types.Issue+  ( Issue(..), parseIssue, parseCve, parseBsc, showIssue+  , isCve, isBsc+  )+  where++import OpenSuse.Prelude++import Data.Aeson+import Data.List+import Data.Text ( unpack )+import GHC.Generics ( Generic )+import Text.Read++data Issue = Bsc Natural+           | Cve Natural Natural+  deriving (Show, Eq, Ord, Generic)++instance Hashable Issue+instance Binary Issue+instance NFData Issue++parseIssue :: String -> Issue+parseIssue ('C':'V':'E':'-':cve) = parseCve cve+parseIssue ('b':'s':'c':'#':bsc) = parseBsc bsc+parseIssue bsc                   = parseBsc bsc++showIssue :: Issue -> String+showIssue (Cve y n) = "CVE-" ++ show y ++ "-" ++ show n+showIssue (Bsc n) = "bsc#" ++ show n++parseCve :: String -> Issue+parseCve cve = Cve (safeRead "cve-year" y) (safeRead "cve-number" n)+  where (y,'-':n) = break (=='-') cve++parseBsc :: String -> Issue     -- TODO: https://gitlab.suse.de/l3ms/smelt/issues/184+parseBsc bsc = Bsc (safeRead "bsc number" (stripFixmeSuffix bsc))++instance FromJSON Issue where+  parseJSON = withText "Issue ID" (return . parseIssue . unpack)++instance FromJSONKey Issue where+  fromJSONKey = FromJSONKeyText (parseIssue . unpack)++safeRead :: Read a => String -> String -> a+safeRead ctx x = fromMaybe (error ("invalid " ++ ctx ++ ": " ++ show x)) (readMaybe x)++stripFixmeSuffix :: String -> String+stripFixmeSuffix x+  | "_FIXME" `isSuffixOf` x = reverse . drop 6 . reverse $ x+  | otherwise               = x++isCve :: Issue -> Bool+isCve (Cve _ _) = True+isCve _ = False++isBsc :: Issue -> Bool+isBsc (Bsc _) = True+isBsc _ = False
+ src/OpenSuse/Types/PackageName.hs view
@@ -0,0 +1,3 @@+module OpenSuse.Types.PackageName ( PackageName ) where++type PackageName = String
+ src/OpenSuse/Types/ProjectId.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE DeriveGeneric, GeneralizedNewtypeDeriving #-}+{-# LANGUAGE FlexibleContexts #-}++module OpenSuse.Types.ProjectId+  ( ProjectId, mkProjectId, unProjectId+  )+  where++import OpenSuse.Prelude+import OpenSuse.Prelude.Parser as Parse+import OpenSuse.Prelude.PrettyPrinting as Pretty++import Data.Aeson as Json+import Data.Aeson.Types as Json ( toJSONKeyText )++-- | Projects are identified on OBS by a string path.+--+-- >>> parse "project id" "SUSE:SLE-12-SP2:Update" :: ProjectId+-- ProjectId ["SUSE","SLE-12-SP2","Update"]+-- >>> parseM "project id" "SUSE::SLE-12-SP2" :: Maybe ProjectId+-- Nothing+-- >>> parseM "project id" ":SUSE" :: Maybe ProjectId+-- Nothing+-- >>> parseM "project id" "SUSE:" :: Maybe ProjectId+-- Nothing++newtype ProjectId = ProjectId [String]+  deriving (Show, Eq, Ord, Generic, Hashable, Binary, NFData, Semigroup, Monoid)++-- | Constructor function for project identifiers.+--+-- TODO: Figure out how to deal with the [] project.+mkProjectId :: [String] -> ProjectId+mkProjectId = ProjectId++-- | Accessor function for the underlying path of strings.+unProjectId :: ProjectId -> [String]+unProjectId (ProjectId str) = str++instance IsString ProjectId where+  fromString = parse "code stream"++instance Pretty ProjectId where+  pPrint = hcat . punctuate colon . map text . unProjectId++instance HasParser ProjectId where+  parser = mkProjectId <$> sepBy1 (many1 (alphaNum <|> oneOf "_-")) (Parse.char ':')++instance FromJSON ProjectId where+  parseJSON = withText "ProjectId" (parseM "project id")++instance FromJSONKey ProjectId where+  fromJSONKey = FromJSONKeyTextParser (parseM "project id")++instance ToJSON ProjectId where+  toJSON = fromString . prettyShow++instance ToJSONKey ProjectId where+  toJSONKey = toJSONKeyText (fromString . prettyShow)
+ src/OpenSuse/Types/RequestId.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE DeriveGeneric, GeneralizedNewtypeDeriving #-}++module OpenSuse.Types.RequestId+  ( RequestId, mkRequestId, unRequestId+  , ReleaseRequestId, MaintenanceRequestId+  )+  where++import OpenSuse.Prelude++-- An OBS request identifier that is, essentially, a natural number.+newtype RequestId = RequestId Natural+  deriving (Show, Eq, Ord, Enum, Generic, Hashable, Binary, NFData)++-- | Constructor function for typed request identifiers.+mkRequestId :: Natural -> RequestId+mkRequestId = RequestId++-- | Accessor function for the underlying natural number.+unRequestId :: RequestId -> Natural+unRequestId (RequestId n) = n++-- | Type synonym for convenience.+type MaintenanceRequestId = RequestId++-- | Type synonym for convenience.+type ReleaseRequestId = RequestId++instance FromJSON RequestId+instance ToJSON RequestId++instance IsString RequestId where+  fromString = parse "request id"++instance Pretty RequestId where+  pPrint = pPrint . unRequestId++instance HasParser RequestId where+  parser = mkRequestId <$> parser
+ src/OpenSuse/Types/UserName.hs view
@@ -0,0 +1,3 @@+module OpenSuse.Types.UserName ( UserName ) where++type UserName = String
+ tests/guess-changelog/ignore-unrelated-whitespace-additions.test view
@@ -0,0 +1,43 @@+# aeson has added whitespace in the middle of the file.+# Verify that our code isn't thrown off by that issue.++$$$ rm -rf _tmp+$$$ cabal -v0 unpack -d _tmp aeson-1.2.4.0+$$$ cabal -v0 unpack -d _tmp aeson-1.3.0.0+$$$ diff _tmp/aeson-1.2.4.0/changelog.md _tmp/aeson-1.3.0.0/changelog.md+>>>+2a3,16+> ### 1.3.0.0+> +> Breaking changes:+> * `GKeyValue` has been renamed to `KeyValuePair`, thanks to Xia Li-yao+> * Removed unused `FromJSON` constraint in `withEmbeddedJson`, thanks to Tristan Seligmann+> +> Other improvements:+> * Optimizations of TH toEncoding, thanks to Xia Li-yao+> * Optimizations of hex decoding when using the default/pure unescape implementation, thanks to Xia Li-yao+> * Improved error message on `Day` parse failures, thanks to Gershom Bazerman+> * Add `encodeFile` as well as `decodeFile*` variants, thanks to Markus Hauck+> * Documentation	fixes, thanks to Lennart Spitzner+> * CPP cleanup, thanks to Ryan Scott+> +5a20+> +>>>= 1++$$$ cabal -v0 new-run guess-changelog -- _tmp/aeson-1.2.4.0 _tmp/aeson-1.3.0.0+>>>+### 1.3.0.0++Breaking changes:+* `GKeyValue` has been renamed to `KeyValuePair`, thanks to Xia Li-yao+* Removed unused `FromJSON` constraint in `withEmbeddedJson`, thanks to Tristan Seligmann++Other improvements:+* Optimizations of TH toEncoding, thanks to Xia Li-yao+* Optimizations of hex decoding when using the default/pure unescape implementation, thanks to Xia Li-yao+* Improved error message on `Day` parse failures, thanks to Gershom Bazerman+* Add `encodeFile` as well as `decodeFile*` variants, thanks to Markus Hauck+* Documentation	fixes, thanks to Lennart Spitzner+* CPP cleanup, thanks to Ryan Scott+>>>= 0
+ tests/guess-changelog/undocumented-releases.test view
@@ -0,0 +1,11 @@+# haskell-src-meta has not documented the 0.8.0.3 release++$$$ rm -rf _tmp+$$$ cabal -v0 unpack -d _tmp haskell-src-meta-0.8.0.2+$$$ cabal -v0 unpack -d _tmp haskell-src-meta-0.8.0.3+$$$ diff _tmp/haskell-src-meta-0.8.0.2/ChangeLog _tmp/haskell-src-meta-0.8.0.3/ChangeLog++$$$ cabal -v0 new-run guess-changelog -- _tmp/haskell-src-meta-0.8.0.2 _tmp/haskell-src-meta-0.8.0.3+>>>2+file ChangeLog has not changed between releases+>>>= 0
+ tests/run-tests view
@@ -0,0 +1,4 @@+#! /bin/sh++cd "$(dirname "$0")" || exit 1+exec shelltest --execdir .