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 +30/−0
- README.md +9/−0
- Setup.hs +2/−0
- distribution-opensuse.cabal +64/−0
- guess-changelog.hs +38/−0
- src/OpenSuse/GuessChangeLog.hs +76/−0
- src/OpenSuse/Prelude.hs +79/−0
- src/OpenSuse/Prelude/Parser.hs +3/−0
- src/OpenSuse/Prelude/PrettyPrinting.hs +11/−0
- src/OpenSuse/Prelude/PrettyPrinting/Orphans.hs +9/−0
- src/OpenSuse/Types/ChangeLog.hs +77/−0
- src/OpenSuse/Types/EMailAddress.hs +41/−0
- src/OpenSuse/Types/Issue.hs +61/−0
- src/OpenSuse/Types/PackageName.hs +3/−0
- src/OpenSuse/Types/ProjectId.hs +59/−0
- src/OpenSuse/Types/RequestId.hs +39/−0
- src/OpenSuse/Types/UserName.hs +3/−0
- tests/guess-changelog/ignore-unrelated-whitespace-additions.test +43/−0
- tests/guess-changelog/undocumented-releases.test +11/−0
- tests/run-tests +4/−0
+ 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+=====================++[](http://hackage.haskell.org/package/distribution-opensuse)+[](http://stackage.org/lts/package/distribution-opensuse)+[](http://stackage.org/nightly/package/distribution-opensuse)+[](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
@@ -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 .