pagure-cli 0.2.1 → 0.2.2
raw patch · 4 files changed
+197/−111 lines, 4 filesdep +http-querydep +simple-cmddep ~pagure
Dependencies added: http-query, simple-cmd
Dependency ranges changed: pagure
Files
- CHANGELOG.md +5/−0
- README.md +66/−43
- pagure-cli.cabal +11/−7
- src/Main.hs +115/−61
CHANGELOG.md view
@@ -1,5 +1,10 @@ # Changelog +## 0.2.2 (2024-05-06)+- new add group and groupinfo commands+- help: order commands with better grouping+- update to Haskell pagure-0.2.0+ ## 0.2.1 (2022-02-17) - new commands: 'project', 'issue', 'userinfo' - drop --url and use aeson-pretty
README.md view
@@ -5,97 +5,120 @@ [](http://stackage.org/lts/package/pagure-cli) [](http://stackage.org/nightly/package/pagure-cli) -A [pagure](https://docs.pagure.org/pagure/) client for querying-projects and users.+A [pagure](https://docs.pagure.org/pagure/) gitforge client for querying+and listing projects (repos), users, groups, and issues. ## Usage By default it uses the [src.fedoraproject.org](https://src.fedoraproject.org/) Pagure server instance (aka Fedora dist-git), but this can be overriden by the `--server` option. -## List/search for repos+### List/search for repos +`$ pagure list rac\*`+ ```-$ pagure list emacs\*-emacs-:+rpms/raceintospace+rpms/racket ```+ Note by default 'orphan' owned packages are excluded. One can also filter by owner or committer. -## List user's projects+### List user's projects Count projects of a user:++`$ pagure user --server pagure.io --count mattdm`+ ```-$ pagure user -s pagure.io --count mattdm-93+120 ``` -## List groups:+### List groups: ``` $ pagure groups : ``` -## More commands+### List group packages+`$ pagure group budgie-sig` -- `branches` lists the git branches of a repo+```+rpms/libxfce4windowing+rpms/sassc+rpms/wlrctl+``` -- `issues` to query and list issues+`$ pagure group -c rust-sig` -- `users` to list usernames of users+```+3093+``` -- `username` shows the fullname of a user+## Help -- `git-url` shows the git urls for a repo+`$ pagure --version` -## Help+```+0.2.2+``` -Use `--help` to get help on individual commands:+`$ pagure --help` ```-$ pagure list --help-Usage: pagure list [-s|--server SERVER] [-c|--count] [(-j|--json) | (-y|--yaml)]- [(-F|--only-forks) | (-f|--include-forks)]- [-n|--namespace NAMESPACE]- [(-o|--owner OWNER) | (-u|--username USERNAME)] [PATTERN]- list projects+Pagure client +Usage: pagure [--version] COMMAND++ Simple pagure CLI+ Available options:- -s,--server SERVER Pagure server- -c,--count Show number only- -j,--json Output JSON- -y,--yaml YAML output- -F,--only-forks Only list forks- -f,--include-forks Include forks [default: ignore forks]- -n,--namespace NAMESPACE Specify project repo namespace- -o,--owner OWNER Projects with certain owner- -u,--username USERNAME Projects to which username can commit -h,--help Show this help text+ --version Show version++Available commands:+ list list projects+ user list user repos+ group list group repos+ project show project details+ branches list project branches+ git-url show project repo's git urls+ issues list project issues+ issue show project issue+ users list users+ username fullname of user+ userinfo show user details+ groups list groups+ groupinfo show group details ```+Use `--help` to get help on individual commands: + ## Installation+pagure-cli is packaged in Fedora and EPEL 9: <https://src.fedoraproject.org/rpms/pagure-cli> +## Build from source To build the latest release you will need cabal-install and ghc, or stack: -`stack install pagure-cli` or `cabal new-install pagure-cli`.--Or to build from the git source, run directly without the package name.--## Binaries+`stack install pagure-cli` or `cabal install pagure-cli`. -pagure-cli is packaged in Fedora (since F34).+Or to build from the git source, run the commands without the package name. ## Contributions- Pagure rest API can be found on pagure servers: eg <https://pagure.io/api/0>. There are still many unsupported commands and options.-Please open a ticket or PR to request adding more.+Please open a ticket or PR to request adding more at+<https://github.com/juhp/pagure-cli>. -## Other clients+Also part of this client uses the simple+[pagure-hs](https://hackage.haskell.org/package/pagure) bindings.++## Other pagure clients After writing the initial version I discovered that Ricky Elrod (relrod) had made <https://github.com/fedora-infra/pagure-cli>. -I discovered a client in Rust <https://pagure.io/ironthree/bodhi-cli> by decathorpe.+There is a library client in Rust <https://pagure.io/ironthree/pagure-rs>+by decathorpe.
pagure-cli.cabal view
@@ -1,21 +1,23 @@ cabal-version: 1.18 name: pagure-cli-version: 0.2.1-synopsis: Pagure client-description: A command-line Pagure client for querying projects and users.+version: 0.2.2+synopsis: A Pagure gitforge query tool+description: A command-line Pagure (gitforge) client for querying+ and listing projects, users, groups, and issues. homepage: https://github.com/juhp/pagure-cli bug-reports: https://github.com/juhp/pagure-cli/issues license: GPL-2 license-file: LICENSE author: Jens Petersen <juhpetersen@gmail.com> maintainer: Jens Petersen <juhpetersen@gmail.com>-copyright: 2019-2020,2022 Jens Petersen+copyright: 2019-2020,2022,2024 Jens Petersen category: Utility build-type: Simple extra-doc-files: README.md- , CHANGELOG.md+ CHANGELOG.md tested-with: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5,- GHC == 8.8.4, GHC == 8.10.4, GHC == 9.0.2+ GHC == 8.8.4, GHC == 8.10.4, GHC == 9.0.2, GHC == 9.2.8,+ GHC == 9.4.8, GHC == 9.6.5, GHC == 9.8.2 source-repository head type: git@@ -29,8 +31,10 @@ , base < 5 , bytestring , filepath+ , http-query , optparse-applicative- , pagure >= 0.1.1+ , pagure >= 0.2+ , simple-cmd , simple-cmd-args >= 0.1.6 , text , unordered-containers
src/Main.hs view
@@ -22,16 +22,13 @@ import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as BL import Data.Maybe-#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,11,0))-#else-import Data.Semigroup ((<>))-#endif import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.IO as T import Data.Yaml (encode)+import Network.HTTP.Query ((+/+))+import SimpleCmd (error', (+-+)) import SimpleCmdArgs-import System.FilePath ((</>)) import Fedora.Pagure import Paths_pagure_cli (version)@@ -41,27 +38,83 @@ simpleCmdArgs (Just version) "Pagure client" "Simple pagure CLI" $ subcommands [ Subcommand "list" "list projects" $- listProjects <$> serverOpt <*> countOpt <*> formatOpt <*> forksOpt <*> optional namespaceOpt <*> optional packagerOpt <*> optional (strArg "PATTERN")- , Subcommand "user" "user repos" $- userRepos <$> serverOpt <*> countOpt <*> switchWith 'f' "forks" "List user's forks" <*> strArg "USER"+ listProjects+ <$> serverOpt+ <*> countOpt+ <*> formatOpt+ <*> forksOpt+ <*> optional namespaceOpt+ <*> optional packagerOpt+ <*> optional (strArg "PATTERN")+ , Subcommand "user" "list user repos" $+ userRepos+ <$> serverOpt+ <*> countOpt+ <*> switchWith 'f' "forks" "List user's forks"+ <*> strArg "USER"+ , Subcommand "group" "list group repos" $+ groupProjects+ <$> serverOpt+ <*> switchWith 'c' "count" "Count projects"+ <*> strArg "GROUP"+ , Subcommand "project" "show project details" $+ projectInfo+ <$> serverOpt+ <*> formatOpt+ <*> strArg "PROJECT" , Subcommand "branches" "list project branches" $- repoBranches <$> serverOpt <*> formatOpt <*> strArg "REPO"+ repoBranches+ <$> serverOpt+ <*> formatOpt+ <*> strArg "REPO"+ , Subcommand "git-url" "show project repo's git urls" $+ gitUrl+ <$> serverOpt+ <*> formatOpt+ <*> strArg "REPO" , Subcommand "issues" "list project issues" $- projectIssues <$> serverOpt <*> countOpt <*> formatOpt <*> strArg "REPO" <*> switchWith 'A' "all" "list Open and Closed issues" <*> optional (strOptionWith 'a' "author" "AUTHOR" "Filter issues by creator") <*> optional (strOptionWith 'S' "since" "Y-M-D" "Filter issues updated after date") <*> optional (strOptionWith 't' "title" "pattern" "Filter issues by title")+ projectIssues+ <$> serverOpt+ <*> countOpt+ <*> formatOpt+ <*> strArg "REPO"+ <*> switchWith 'A' "all" "list Open and Closed issues"+ <*> optional (strOptionWith 'a' "author" "AUTHOR" "Filter issues by creator")+ <*> optional (strOptionWith 'S' "since" "Y-M-D" "Filter issues updated after date")+ <*> optional (strOptionWith 't' "title" "pattern" "Filter issues by title")+ , Subcommand "issue" "show project issue" $+ projectIssue+ <$> serverOpt+ <*> formatOpt+ <*> strArg "REPO"+ <*> argumentWith auto "ISSUE" , Subcommand "users" "list users" $- users <$> serverOpt <*> formatOpt <*> strArg "PATTERN"+ users+ <$> serverOpt+ <*> formatOpt+ <*> strArg "PATTERN" , Subcommand "username" "fullname of user" $- username <$> serverOpt <*> formatOpt <*> strArg "USERNAME"- , Subcommand "groups" "list groups" $- groups <$> serverOpt <*> countOpt <*> formatOpt <*> optional (strArg "PATTERN")- , Subcommand "git-url" "show project repo's git urls" $- gitUrl <$> serverOpt <*> formatOpt <*> strArg "REPO"- , Subcommand "project" "show project details" $- projectInfo <$> serverOpt <*> formatOpt <*> strArg "PROJECT"- , Subcommand "issue" "show project issue" $- projectIssue <$> serverOpt <*> formatOpt <*> strArg "REPO" <*> argumentWith auto "ISSUE"+ username+ <$> serverOpt+ <*> formatOpt+ <*> strArg "USERNAME" , Subcommand "userinfo" "show user details" $- userInfo <$> serverOpt <*> formatOpt <*> strArg "USERNAME"+ userInfo+ <$> serverOpt+ <*> formatOpt+ <*> strArg "USERNAME"+ , Subcommand "groups" "list groups" $+ groups+ <$> serverOpt+ <*> countOpt+ <*> formatOpt+ <*> optional (strArg "PATTERN")+ , Subcommand "groupinfo" "show group details" $+ groupInfo+ <$> serverOpt+ <*> switchWith 'p' "projects" "List projects"+ <*> formatOpt+ <*> strArg "GROUP" ] where countOpt = switchWith 'c' "count" "Show number only"@@ -94,7 +147,7 @@ error' "Please give a package pattern, --count, or --owner/--username" let path = "projects" params = makeKey "short" "1" ++ fork ++ packager ++ maybeKey "namespace" mnamespace ++ maybeKey "pattern" mpattern- pages <- queryPaged server count path params ("pagination", "page")+ pages <- queryPagureCountPaged server count path params ("pagination", "page") mapM_ (defaultPrinter format printPage) pages where -- (!orphan only works on pagure >=0.29)@@ -114,27 +167,21 @@ projects = lookupKey' "projects" result (mapM_ T.putStrLn . mapMaybe (lookupKey key')) projects +-- FIXME duplicates subset of listProjects userRepos :: String -> Bool -> Bool -> String -> IO () userRepos server count forks user = if count then do- let path = "user" </> user+ let path = "user" +/+ user mcnt <- queryPagureCount server path [] $ if forks then "forks_pagination" else "repos_pagination" print $ fromMaybe- (error' ("number of " ++ (if forks then "forks" else "repos") ++ " could not be determined"))+ (error' ("number of" +-+ (if forks then "forks" else "repos") +-+ "could not be determined")) mcnt else do repos <- (if forks then pagureUserForks else pagureUserRepos) server user mapM_ T.putStrLn repos --- maybeKey :: String -> Maybe String -> Query--- maybeKey _ Nothing = []--- maybeKey k mval = [(B.pack k, fmap B.pack mval)]---- makeKey :: String -> String -> Query--- makeKey k val = [(B.pack k, Just (B.pack val))]- boolKey :: String -> Bool -> String -> Query boolKey _ False _ = [] boolKey k True val = makeKey k val@@ -142,10 +189,10 @@ -- FIXME limit max number of issues projectIssues :: String -> Bool -> OutputFormat -> String -> Bool -> Maybe String -> Maybe String -> Maybe String -> IO () projectIssues server count format repo allstatus mauthor msince mpat = do- let path = repo </> "issues"- params = [("status", Just "all") | allstatus] +++ let path = repo +/+ "issues"+ params = [makeItem "status" "all" | allstatus] ++ maybeKey "author" mauthor ++ maybeKey "since" msince- pages <- queryPaged server count path params ("pagination", "page")+ pages <- queryPagureCountPaged server count path params ("pagination", "page") mapM_ (defaultPrinter format printIssues) pages where printIssues :: Object -> IO ()@@ -160,7 +207,7 @@ Nothing -> putStrLn "parsing issue failed" Just (id',title,status) -> when (isNothing mpat || T.pack (fromJust mpat) `T.isInfixOf` title) $- putStrLn $ "https://" <> server </> repo </> "issue" </> show id' <> " (" <> T.unpack status <> "): " <> T.unpack title+ putStrLn $ "https://" ++ server +/+ repo +/+ "issue" +/+ show id' +-+ "(" ++ T.unpack status ++ "):" +-+ T.unpack title parseIssue :: Object -> Maybe (Integer, Text, Text) parseIssue =@@ -170,24 +217,12 @@ status <- obj .: "status" return (id',title,status) --- FIXME limit max number of pages (10?) or --pages-queryPaged :: String -> Bool -> String -> Query -> (String,String)- -> IO [Object]-queryPaged server count path params (pagination,paging) =- if count- then do- mnum <- queryPagureCount server path params pagination- print $ fromMaybe (error' "pages not found") mnum- return []- else- queryPagurePaged server path params (pagination,paging)- repoBranches :: String -> OutputFormat -> String -> IO () repoBranches server format repo = do let namespace = if server == srcFedoraprojectOrg && '/' `notElem` repo then "rpms/" else ""- path = namespace ++ repo </> "git/branches"+ path = namespace ++ repo +/+ "git/branches" eres <- queryPagureSingle server path [] either error' (defaultPrinter format (printKeyList "branches")) eres @@ -200,9 +235,11 @@ username :: String -> OutputFormat -> String -> IO () username server format user = do- let path = "user" </> user- res <- queryPagure' server path $ makeKey "per_page" "1"- defaultPrinter format printName res+ let path = "user" +/+ user+ eres <- queryPagureSingle server path $ makeKey "per_page" "1"+ case eres of+ Left err -> error' err+ Right res -> defaultPrinter format printName res where printName res = case lookupKey "user" res >>= lookupKey "fullname" of@@ -213,7 +250,7 @@ groups server count format mpat = do let path = "groups" params = maybeKey "pattern" mpat- pages <- queryPaged server count path params ("pagination", "page")+ pages <- queryPagureCountPaged server count path params ("pagination", "page") mapM_ (defaultPrinter format (printKeyList "groups")) pages printKeyList :: String -> Object -> IO ()@@ -225,7 +262,7 @@ let namespace = if server == srcFedoraprojectOrg && '/' `notElem` repo then "rpms/" else ""- path = namespace ++ repo </> "git/urls"+ path = namespace ++ repo +/+ "git/urls" res <- queryPagure server path [] defaultPrinter format printURLs res where@@ -241,14 +278,6 @@ #endif localLookupKey = lookupKey' . T.pack --- from simple-cmd-error' :: String -> a-#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,9,0))-error' = errorWithoutStackTrace-#else-error' = error-#endif- yamlPrinter :: OutputFormat -> Object -> IO () yamlPrinter FormatDefault = yamlPrinter FormatYaml yamlPrinter FormatJson = BL.putStrLn . encodePretty@@ -272,3 +301,28 @@ userInfo server format user = do eval <- pagureUserInfo server user [] either error' (yamlPrinter format) eval++groupInfo :: String -> Bool -> OutputFormat -> String -> IO ()+groupInfo server projects format group = do+ let params = [makeItem "projects" "1" | projects]+ eval <- pagureGroupInfo server group params+ either error' (yamlPrinter format) eval++-- FIXME support acl parameter (admin, commit or ticket)+groupProjects :: String -> Bool -> String -> IO ()+groupProjects server count group = do+ let path = "group" +/+ group+ params = makeKey "projects" "1"+ pages <- queryPagureCountPaged server count path params ("pagination", "page")+ mapM_ (defaultPrinter FormatDefault printPage) pages+ where+ -- acl+ -- packager = case mpackager of+ -- Nothing -> boolKey "owner" (server == srcFedoraprojectOrg) "!orphan"+ -- Just (Owner o) -> makeKey "owner" o+ -- Just (Committer c) -> makeKey "username" c++ printPage :: Object -> IO ()+ printPage result = do+ let projects = lookupKey' "projects" result+ (mapM_ T.putStrLn . mapMaybe (lookupKey "fullname")) projects