packages feed

rhbzquery 0.1.1 → 0.2

raw patch · 9 files changed

+147/−70 lines, 9 files

Files

ChangeLog.md view
@@ -1,5 +1,8 @@ # rhbzquery releases +## 0.2 (2020-12-09)+- support most search type operators (regexp, substr, isempty, and negatives)+ ## 0.1.1 (2020-12-04) - --file a bug - --help: do not format FIELDS
README.md view
@@ -18,9 +18,9 @@  `rhbzquery "Package Review" reporter_realname="Your Name"` : open package reviews you reported -`rhbzquery --mine all flag=fedora-review+` : all your open and closed approved reviews+`rhbzquery --mine all flag~fedora-review+` : all your open and closed approved reviews -`rhbzquery summary=bugzilla` : open bugs with summary containing "bugzilla":+`rhbzquery component~bugzilla summary~bugzilla` : open bugs with component and summary containing "bugzilla"  `rhbzquery --file f33 xyz` : file a bug against the xyz package in F33 @@ -29,6 +29,8 @@  ## Installation Run `stack install` or `cabal install`.++Binary packages for Fedora are available from <https://copr.fedorainfracloud.org/coprs/petersen/rhbzquery/>.  ## Requests and feedback Feature requests, bug reports and contributions are welcome.
+ TODO view
@@ -0,0 +1,9 @@+- copy url to clipboard+- tui bug browser+- help: --fields-matching+- use NOT Closed ?+- cc=me, reporter=me+- config file: for defining "my team" etc+- --help: only show most important fields+  --help-all for all+- --count bugs
rhbzquery.cabal view
@@ -1,5 +1,5 @@ name:                rhbzquery-version:             0.1.1+version:             0.2 synopsis:            Bugzilla query tool description:         A CLI tool for creating bugzilla queries for bugzilla.redhat.com.@@ -14,6 +14,7 @@ build-type:          Simple extra-doc-files:     ChangeLog.md                      README.md+                     TODO cabal-version:       1.18 tested-with:         GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.4, GHC == 8.10.2 @@ -55,6 +56,8 @@   if impl(ghc >= 8.4)     ghc-options:       -Wmissing-export-lists                        -Wpartial-fields+  if impl(ghc >= 8.10)+    ghc-options:       -Wunused-packages  test-suite test     main-is: tests.hs
src/Fields.hs view
@@ -8,7 +8,7 @@ import Data.Version import Numeric.Natural -import ParseArg (ArgType(..), ProductVersion(..))+import ParseArg (ArgType(..), Operator(..), ProductVersion(..), showOp)  data BzFields = BzProduct               | BzVersion@@ -21,28 +21,27 @@   show BzProduct = "product"   show BzVersion = "version"   show BzComponent = "component"-  show (BzParameter f) = mapFields f+  show (BzParameter f) = f   show (BzMeta c n) = c: show n -mapFields :: String -> String-mapFields "itm" = "cf_internal_target_milestone"-mapFields "itr" = "cf_internal_target_release"-mapFields "status" = "bug_status"-mapFields "verified" = "cf_verified"-mapFields s = s--mapComplex :: String -> String-mapComplex "sst" = "agile_team.name"-mapComplex "summary" = "short_desc"-mapComplex "flag" = "flagtypes.name"-mapComplex "flags" = "flagtypes.name"-mapComplex p = p+mapField :: String -> String+mapField "itm" = "cf_internal_target_milestone"+mapField "itr" = "cf_internal_target_release"+mapField "status" = "bug_status"+mapField "verified" = "cf_verified"+mapField "sst" = "agile_team.name"+mapField "summary" = "short_desc"+mapField "flag" = "flagtypes.name"+mapField "flags" = "flagtypes.name"+mapField p = p  argToSimpleField :: ArgType -> [(BzFields,String)] argToSimpleField (ArgProdVer prodver) =   productVersionQuery prodver-argToSimpleField (ArgParameter p v) =-  [(BzParameter (mapComplex p), v)]+argToSimpleField (ArgParameter p Equals v) =+  [(BzParameter (mapField p), v)]+argToSimpleField (ArgParameter p _ v) =+  error $ "Only '" ++ p ++ "=" ++ v ++ "'allowed here" argToSimpleField (ArgOther c) =   [(BzComponent,c)] -- FIXME or error for "all"?@@ -53,21 +52,20 @@   case arg of     ArgProdVer prodver -> (i,productVersionQuery prodver)     ArgStatusAll  -> (i,[])-    ArgParameter "sst" v ->-      (i+1,[(BzMeta 'f' i, mapComplex "sst")-           ,(BzMeta 'o' i, "substr")-           ,(BzMeta 'v' i, "sst_" ++ v)])-    ArgParameter "summary" v ->-      (i+1,[(BzMeta 'f' i, mapComplex "summary")-           ,(BzMeta 'o' i, "substr")-           ,(BzMeta 'v' i, v)])-    ArgParameter param v ->-      let p = mapComplex param-      in if '.' `elem` p-         then (i+1,[(BzMeta 'f' i, p)-                   ,(BzMeta 'o' i, "substr")-                   ,(BzMeta 'v' i, v)])-         else (i,[(BzParameter p, v)])+    ArgParameter p op v ->+      let param = mapField p+          val = if p == "sst"+                then "sst_" ++ v+                else v+      in if '.' `elem` param || op /= Equals+         then (i+1,[(BzMeta 'f' i, param)+                   ,(BzMeta 'o' i, showOp op)+                   ,(BzMeta 'v' i, val)])+         else (i,[(BzParameter param, val)])+    ArgParameterEmpty p e ->+      let param = mapField p+      in (i+1,[(BzMeta 'f' i, param)+              ,(BzMeta 'o' i, if e then "isempty" else "isnotempty")])     ArgOther c -> (i,[(BzComponent,c)])  productVersionQuery :: ProductVersion -> [(BzFields,String)]
src/Help.hs view
@@ -21,6 +21,8 @@   , P.empty   , P.text "PRODUCTVERSION = " <> P.lbrace <> P.align (P.fillCat (P.punctuate P.comma (map P.text ["rawhide", "fedora", "fXY", "epel", "epelX", "rhel8", "rhel7", "rhelX.Z"])) <> P.rbrace)   , P.empty+  , P.text "'op' is " <> P.align (P.fillCat (P.punctuate P.comma (map P.text ["'='(equals)", "'!='(notequals)", "'~'(substring)", "'!~'(notsubstring)", "'=~'(regexp)", "'!=~'(notregexp)", "'~a~'(allwordssubstr)", "'!a~'(nowordssubstr)", "'~c~'(casesubstring)", "'~e~'(isempty)", "'!e~'(isnotempty)", "'~w~'(allwords)", "'!w~'(nowords)"])))+  , P.empty   , P.text "See https://github.com/juhp/rhbzquery#readme for examples"   ] 
src/Main.hs view
@@ -1,6 +1,9 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} +#if !MIN_VERSION_simple_cmd_args(0,1,3)+import Control.Applicative ((<|>))+#endif import Control.Monad.Extra import Data.Bifunctor import qualified Data.ByteString.Char8 as B@@ -26,31 +29,34 @@ import Paths_rhbzquery import User +data OtherQuery = CreateBug | APIQuery+ main :: IO () main =   simpleCmdArgsWithMods (Just version) (fullDesc <> header "Bugzilla query tool" <> progDescDoc (Just detailedHelp)) $   run <$>   switchWith 'n' "dryrun" "Do not open url" <*>   switchWith 'm' "mine" "My bugs" <*>-  switchWith 'f' "file" "File a bug" <*>+  optional (flagWith' CreateBug 'f' "file" "File a bug" <|>+            flagWith' APIQuery 'w' "api" "Web API query") <*>   some (strArg argHelp)   where-    run :: Bool -> Bool -> Bool -> [String] -> IO ()-    run dryrun mine file args = do-      user <- if mine && not file+    run :: Bool -> Bool -> Maybe OtherQuery -> [String] -> IO ()+    run dryrun mine mquery args = do+      user <- if mine         then do         mail <- getBzUser-        return [ArgParameter "assigned_to" mail]+        return [ArgParameter "assigned_to" Equals mail]         else return []       let argtypes = mapMaybe readBzQueryArg args-          url = if file-            then-            let query = L.nub $ concatMap argToSimpleField argtypes-            in "https://" <> B.pack brc <> "/enter_bug.cgi" <> renderQuery True (bzQuery query)-            else-            let status = [ArgParameter "bug_status" "__open__" | not (hasStatusSet argtypes)]-                query = L.nub $ numberMetaFields $ status ++ user ++ argtypes-            in "https://" <> B.pack brc <> "/buglist.cgi" <> renderQuery True (bzQuery query)+          url = case mquery of+            Just CreateBug ->+              let query = L.nub $ concatMap argToSimpleField argtypes+              in "https://" <> B.pack brc <> "/enter_bug.cgi" <> renderQuery True (bzQuery query)+            _ ->+              let status = [ArgParameter "bug_status" Equals "__open__" | not (hasStatusSet argtypes)]+                  query = L.nub $ numberMetaFields $ status ++ user ++ argtypes+              in "https://" <> B.pack brc <> "/" <> (if isNothing mquery then "buglist.cgi" else "rest/bug")<> renderQuery True (bzQuery query)       B.putStrLn url       unless dryrun $ do         whenJustM (findExecutable "xdg-open") $ \xdgOpen ->@@ -59,8 +65,8 @@     hasStatusSet :: [ArgType] -> Bool     hasStatusSet [] = False     hasStatusSet (ArgStatusAll:_) = True-    hasStatusSet ((ArgParameter "bug_status" _):_) = True-    hasStatusSet ((ArgParameter "status" _):_) = True+    hasStatusSet ((ArgParameter "bug_status" _ _):_) = True+    hasStatusSet ((ArgParameter "status" _ _):_) = True     hasStatusSet (_:rest) = hasStatusSet rest      numberMetaFields :: [ArgType] -> [(BzFields,String)]
src/ParseArg.hs view
@@ -2,6 +2,8 @@   argHelp,   readBzQueryArg,   ArgType(..),+  Operator(..),+  showOp,   ProductVersion(..),   statusList   )@@ -14,11 +16,36 @@ import Numeric.Natural  argHelp :: String-argHelp = "[COMPONENT|STATUS|PRODUCTVERSION|FIELD=VALUE]..."+argHelp = "[COMPONENT|STATUS|PRODUCTVERSION|FIELD=VALUE|FIELDopVALUE]..." +data Operator = Equals | NotEqual+              | Contains | NotContain+              | ContainsCase+              | Regexp |NotRegexp+              | ContainsAll | NotContainAll+              | ContainsWords | NotContainWords+              -- | ContentMatches | ContentNotMatch+  deriving Eq++showOp :: Operator -> String+showOp Equals = "equals"+showOp NotEqual = "notequals"+showOp Contains = "substring"+showOp NotContain = "notsubstring"+showOp ContainsCase = "casesubstring"+showOp Regexp = "regexp"+showOp NotRegexp = "notregexp"+showOp ContainsAll = "allwordssubstr"+showOp NotContainAll = "nowordssubstr"+showOp ContainsWords = "allwords"+showOp NotContainWords = "nowords"+--showOp IsEmpty = "isempty"+--showOp IsNotEmpty = "isnotempty"+ data ArgType = ArgProdVer ProductVersion              | ArgStatusAll-             | ArgParameter String String+             | ArgParameter String Operator String+             | ArgParameterEmpty String Bool              | ArgOther String  readBzQueryArg :: String -> Maybe ArgType@@ -51,12 +78,38 @@     if caps == "ALL"     then Just ArgStatusAll     else-      ArgParameter "bug_status" <$> find (== upper s) statusList+      ArgParameter "bug_status" Equals <$> find (== upper s) statusList  parseParam :: String -> Maybe ArgType parseParam ps =-  case splitOn "=" ps of-    [a,b] -> if null a || null b-             then error $ "bad parameter: " ++ ps-             else Just (ArgParameter a b)-    _ -> Nothing+  parseParamWith "!=~" NotRegexp <|>+  parseParamWith "=~" Regexp <|>+  parseParamWith "!=" NotEqual <|>+  parseParamWith "=" Equals <|>+  parseParamWith "!~" NotContain <|>+  parseParamWith "~a~" ContainsAll <|>+  parseParamWith "!a~" NotContainAll <|>+  parseParamWith "~c~" ContainsCase <|>+  parseParamEmpty "~e~" True <|>+  parseParamEmpty "!e~" False <|>+  parseParamWith "~w~" ContainsWords <|>+  parseParamWith "!w~" NotContainWords <|>+--  parseParamWith "~m~" ContentMatches <|>+--  parseParamWith "!m~" ContentNotMatch <|>+  parseParamWith "~" Contains+  where+    parseParamWith :: String -> Operator -> Maybe ArgType+    parseParamWith op oper =+      case splitOn op ps of+        [a,b] -> if null a || null b+                 then error $ "bad parameter: " ++ ps+                 else Just (ArgParameter a oper b)+        _ -> Nothing++    parseParamEmpty :: String -> Bool -> Maybe ArgType+    parseParamEmpty op empty =+      case stripSuffix op ps of+        Just a -> if null a+                  then error $ "bad parameter: " ++ ps+                  else Just (ArgParameterEmpty a empty)+        _ -> Nothing
test/tests.hs view
@@ -4,8 +4,7 @@ rhbzquery :: ([String], String) -> IO () rhbzquery (args,expect) = do   out <- cmd "rhbzquery" ("-n" : args)-  let cgi = if "--file" `elem` args then "enter_bug" else "buglist"-      req = removePrefix ("https://bugzilla.redhat.com/" ++ cgi ++ ".cgi?") out+  let req = removePrefix "https://bugzilla.redhat.com/" out   unless (req == expect) $ do     cmdN "rhbzquery" ("-n" : args)     putStrLn $ "returned> " ++ req@@ -15,21 +14,23 @@ tests :: [([String],String)] tests =   [(["f33", "pango"],-    "bug_status=__open__&product=Fedora&version=33&component=pango")+    "buglist.cgi?bug_status=__open__&product=Fedora&version=33&component=pango")   ,(["closed", "rawhide", "xyz"],-    "bug_status=CLOSED&product=Fedora&version=rawhide&component=xyz")+    "buglist.cgi?bug_status=CLOSED&product=Fedora&version=rawhide&component=xyz")   ,(["rhel8.3", "bash"],-    "bug_status=__open__&product=Red%20Hat%20Enterprise%20Linux%208&version=8.3&component=bash")+    "buglist.cgi?bug_status=__open__&product=Red%20Hat%20Enterprise%20Linux%208&version=8.3&component=bash")   ,(["rhel8", "bash"],-    "bug_status=__open__&product=Red%20Hat%20Enterprise%20Linux%208&component=bash")+    "buglist.cgi?bug_status=__open__&product=Red%20Hat%20Enterprise%20Linux%208&component=bash")   ,(["Package Review", "reporter_realname=Your Name"],-    "bug_status=__open__&component=Package%20Review&reporter_realname=Your%20Name")-  ,(["flag=fedora-review+"],-    "bug_status=__open__&f0=flagtypes.name&o0=substr&v0=fedora-review%2B")-  ,(["summary=bugzilla"],-    "bug_status=__open__&f0=short_desc&o0=substr&v0=bugzilla")+    "buglist.cgi?bug_status=__open__&component=Package%20Review&reporter_realname=Your%20Name")+  ,(["flag~fedora-review+"],+    "buglist.cgi?bug_status=__open__&f0=flagtypes.name&o0=substring&v0=fedora-review%2B")+  ,(["summary~bugzilla"],+    "buglist.cgi?bug_status=__open__&f0=short_desc&o0=substring&v0=bugzilla")   ,(["--file", "f33", "bugzilla"],-    "product=Fedora&version=33&component=bugzilla")+    "enter_bug.cgi?product=Fedora&version=33&component=bugzilla")+  ,(["--api", "fedora", "component~llvm"],+    "rest/bug?bug_status=__open__&product=Fedora&f0=component&o0=substring&v0=llvm")   ]  main :: IO ()