From e2092333f3c1baec665382cc74a61f5880fcb77f Mon Sep 17 00:00:00 2001 From: Daisuke Shimamoto Date: Sat, 11 Oct 2025 16:32:17 +0900 Subject: [PATCH 1/3] Refactor: Rename NewCommandLineParser to CommandLineParser in cabal config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the gwcli.cabal file to reflect the module rename from NewCommandLineParser to CommandLineParser, removing the old module from the exposed-modules list. Also add cabal.project.freeze to lock dependency versions for reproducible builds with GHC 9.12.1 and Cabal 3.14. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- cabal.project.freeze | 238 +++++++++++++++++++++++++++++++++++++++++++ gwcli.cabal | 7 +- 2 files changed, 241 insertions(+), 4 deletions(-) create mode 100644 cabal.project.freeze diff --git a/cabal.project.freeze b/cabal.project.freeze new file mode 100644 index 0000000..4c9cfba --- /dev/null +++ b/cabal.project.freeze @@ -0,0 +1,238 @@ +active-repositories: hackage.haskell.org:merge +constraints: any.Cabal ==3.14.1.0, + any.Cabal-syntax ==3.14.1.0, + any.HTTP ==4000.4.1, + HTTP -conduit10 +network-uri -warn-as-error -warp-tests, + any.OneTuple ==0.4.2, + any.QuickCheck ==2.16.0.0, + QuickCheck -old-random +templatehaskell, + any.RSA ==2.4.1, + any.SHA ==1.6.4.4, + SHA -exe, + any.StateVar ==1.2.2, + any.adjunctions ==4.4.3, + any.aeson ==2.2.3.0, + aeson +ordered-keymap, + any.aeson-casing ==0.2.0.0, + any.ansi-terminal ==1.1.3, + ansi-terminal -example, + any.ansi-terminal-types ==1.1.3, + any.appar ==0.1.8, + any.array ==0.5.8.0, + any.asn1-encoding ==0.9.6, + any.asn1-parse ==0.9.5, + any.asn1-types ==0.3.4, + any.assoc ==1.1.1, + assoc -tagged, + any.async ==2.2.5, + async -bench, + any.attoparsec ==0.14.4, + attoparsec -developer, + any.attoparsec-aeson ==2.2.2.0, + any.authenticate-oauth ==1.7, + any.base ==4.21.0.0, + any.base-orphans ==0.9.3, + any.base16-bytestring ==1.0.2.0, + any.base64 ==1.0, + any.base64-bytestring ==1.2.1.0, + any.basement ==0.0.16, + any.bifunctors ==5.6.2, + bifunctors +tagged, + any.binary ==0.8.9.2, + any.binary-instances ==1.0.6, + any.binary-orphans ==1.0.5, + any.bitvec ==1.1.5.0, + bitvec +simd, + any.blaze-builder ==0.4.4.1, + any.byteorder ==1.0.4, + any.bytestring ==0.12.2.0, + any.cabal-doctest ==1.0.11, + any.call-stack ==0.4.0, + any.case-insensitive ==1.2.1.0, + any.cborg ==0.2.10.0, + cborg +optimize-gmp, + any.cereal ==0.5.8.3, + cereal -bytestring-builder, + any.character-ps ==0.1, + any.colour ==2.3.6, + any.comonad ==5.0.9, + comonad +containers +distributive +indexed-traversable, + any.conduit ==1.3.6.1, + any.conduit-extra ==1.3.8, + any.containers ==0.7, + any.contravariant ==1.5.5, + contravariant +semigroups +statevar +tagged, + any.cookie ==0.5.1, + any.crypto-api ==0.13.3, + crypto-api -all_cpolys, + any.crypto-pubkey-types ==0.4.3, + any.crypton ==1.0.4, + crypton -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq +support_pclmuldq +support_rdrand -support_sse +use_target_attributes, + any.crypton-connection ==0.4.5, + any.crypton-socks ==0.6.2, + crypton-socks -example +network-3-0-0-0, + any.crypton-x509 ==1.7.7, + any.crypton-x509-store ==1.6.11, + any.crypton-x509-system ==1.6.7, + any.crypton-x509-validation ==1.6.14, + any.cryptonite ==0.30, + cryptonite -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq -support_pclmuldq +support_rdrand -support_sse +use_target_attributes, + any.data-default ==0.8.0.1, + any.data-default-class ==0.2.0.0, + any.data-fix ==0.3.4, + any.deepseq ==1.5.1.0, + any.directory ==1.3.9.0, + any.distributive ==0.6.2.1, + distributive +semigroups +tagged, + any.dlist ==1.0, + dlist -werror, + any.ech-config ==0.0.1, + ech-config -devel, + any.entropy ==0.4.1.11, + entropy -donotgetentropy, + any.exceptions ==0.10.9, + any.file-io ==0.1.5, + any.filepath ==1.5.4.0, + any.free ==5.2, + any.generically ==0.1.1, + any.ghc-bignum ==1.3, + any.ghc-boot-th ==9.12.1, + any.ghc-internal ==9.1201.0, + any.ghc-prim ==0.13.0, + any.git ==0.3.0, + any.half ==0.3.3, + any.hashable ==1.5.0.0, + hashable -arch-native -random-initial-seed, + any.hoauth2 ==2.14.3, + any.hourglass ==0.2.12, + any.hpke ==0.0.0, + any.hsc2hs ==0.68.10, + hsc2hs -in-ghc-tree, + any.http-client ==0.7.19, + http-client +network-uri, + any.http-client-tls ==0.3.6.4, + any.http-conduit ==2.3.9.1, + http-conduit +aeson, + any.http-types ==0.12.4, + any.indexed-traversable ==0.1.4, + any.indexed-traversable-instances ==0.1.2, + any.integer-conversion ==0.1.1, + any.integer-gmp ==1.1, + any.integer-logarithms ==1.0.4, + integer-logarithms -check-bounds +integer-gmp, + any.invariant ==0.6.4, + any.iproute ==1.7.15, + any.kan-extensions ==5.2.7, + any.lens ==5.3.5, + lens -benchmark-uniplate -dump-splices +inlining -j +test-hunit +test-properties +test-templates +trustworthy, + any.lens-aeson ==1.2.3, + any.libyaml ==0.1.4, + libyaml -no-unicode -system-libyaml, + any.libyaml-clib ==0.2.5, + any.memory ==0.18.0, + memory +support_bytestring +support_deepseq, + any.microlens ==0.4.14.0, + any.mime-types ==0.1.2.0, + any.mono-traversable ==1.0.21.0, + any.mtl ==2.3.1, + any.network ==3.2.8.0, + network -devel, + any.network-byte-order ==0.1.7, + any.network-uri ==2.6.4.2, + any.old-locale ==1.0.0.7, + any.old-time ==1.1.0.4, + any.optparse-applicative ==0.19.0.0, + optparse-applicative +process, + any.os-string ==2.0.7, + any.parallel ==3.2.2.0, + any.parsec ==3.1.17.0, + any.pem ==0.2.4, + any.pretty ==1.1.3.6, + any.prettyprinter ==1.7.1, + prettyprinter -buildreadme +text, + any.prettyprinter-ansi-terminal ==1.1.3, + any.primitive ==0.9.1.0, + any.process ==1.6.25.0, + any.profunctors ==5.6.3, + any.psqueues ==0.2.8.2, + any.random ==1.3.1, + any.raw-strings-qq ==1.1, + any.reflection ==2.1.9, + reflection -slow +template-haskell, + any.resourcet ==1.3.0, + any.rts ==1.0.2, + any.scientific ==0.3.8.0, + scientific -integer-simple, + any.semialign ==1.3.1, + semialign +semigroupoids, + any.semigroupoids ==6.0.1, + semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers, + any.semigroups ==0.20, + semigroups +binary +bytestring -bytestring-builder +containers +deepseq +hashable +tagged +template-haskell +text +transformers +unordered-containers, + any.serialise ==0.2.6.1, + serialise +newtime15, + any.split ==0.2.5, + any.splitmix ==0.1.3.1, + splitmix -optimised-mixer, + any.stm ==2.5.3.1, + any.streaming-commons ==0.2.3.0, + streaming-commons -use-bytestring-builder, + any.strict ==0.5.1, + any.string-conversions ==0.4.0.1, + any.system-fileio ==0.3.16.7, + any.system-filepath ==0.4.14.1, + any.tagged ==0.8.9, + tagged +deepseq +transformers, + any.tasty ==1.5.3, + tasty +unix, + any.template-haskell ==2.23.0.0, + any.temporary ==1.3, + any.text ==2.1.2, + any.text-iso8601 ==0.1.1, + any.text-short ==0.1.6, + text-short -asserts, + any.th-abstraction ==0.7.1.0, + any.th-compat ==0.1.6, + any.th-lift ==0.8.6, + any.th-lift-instances ==0.1.20, + any.these ==1.2.1, + any.time ==1.14, + any.time-compat ==1.9.8, + any.time-locale-compat ==0.1.1.5, + time-locale-compat -old-locale, + any.tls ==2.1.11, + tls -devel, + any.transformers ==0.6.1.2, + any.transformers-base ==0.4.6, + transformers-base +orphaninstances, + any.transformers-compat ==0.7.2, + transformers-compat -five +five-three -four +generic-deriving +mtl -three -two, + any.typed-process ==0.2.13.0, + any.unix ==2.8.6.0, + any.unix-compat ==0.7.4.1, + any.unix-time ==0.4.17, + any.unliftio-core ==0.2.1.0, + any.unordered-containers ==0.2.20, + unordered-containers -debug, + any.uri-bytestring ==0.4.0.1, + uri-bytestring -lib-werror, + any.uri-bytestring-aeson ==0.1.0.9, + any.utf8-string ==1.0.2, + any.uuid-types ==1.0.6, + any.vector ==0.13.2.0, + vector +boundschecks -internalchecks -unsafechecks -wall, + any.vector-algorithms ==0.9.1.0, + vector-algorithms +bench +boundschecks -internalchecks -llvm -unsafechecks, + any.vector-binary-instances ==0.2.5.2, + any.vector-stream ==0.1.0.1, + any.void ==0.7.3, + void -safe, + any.witherable ==0.5, + any.wreq ==0.5.4.3, + wreq -aws -developer +doctest -httpbin, + any.yaml ==0.11.11.2, + yaml +no-examples +no-exe, + any.zlib ==0.7.1.1, + zlib -bundled-c-zlib +non-blocking-ffi +pkg-config, + any.zlib-bindings ==0.1.1.5 +index-state: hackage.haskell.org 2025-09-28T05:10:57Z diff --git a/gwcli.cabal b/gwcli.cabal index 02be73b..cfccf64 100644 --- a/gwcli.cabal +++ b/gwcli.cabal @@ -21,7 +21,6 @@ source-repository head library exposed-modules: - NewCommandLineParser CommandLineParser CredentialUtils GitUtils @@ -48,7 +47,7 @@ library ghc-options: -Wall -O2 build-depends: base >=4.7 && <5 - , optparse-applicative >= 0.17 && < 0.19 + , optparse-applicative >= 0.17 && < 0.20 , HTTP , aeson , aeson-casing @@ -86,7 +85,7 @@ executable gwcli build-depends: gwcli , base >=4.7 && <5 - , optparse-applicative >= 0.17 && < 0.19 + , optparse-applicative >= 0.17 && < 0.20 , HTTP , aeson , aeson-casing @@ -131,7 +130,7 @@ test-suite gwcli-test , directory , filepath , git - , hoauth2 >= 2.4.0 + , hoauth2 >= 2.8.0 , http-conduit , http-types , lens From c313b0f08bd1658ce8b95e7ed95ef8c775853896 Mon Sep 17 00:00:00 2001 From: Daisuke Shimamoto Date: Sat, 11 Oct 2025 16:46:03 +0900 Subject: [PATCH 2/3] Refactor: Clean up code after optparse-applicative migration (#94) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refactor: Clean up code after optparse-applicative migration This commit performs code cleanup following the migration to optparse-applicative in PR #90: **Module Changes:** - Rename NewCommandLineParser.hs to CommandLineParser.hs - Remove old GetOpt-based CommandLineParser module **Main.hs Cleanup:** - Update import from NewCommandLineParser to CommandLineParser - Remove obsolete comments ("Old...", "Refactored...", "TODO...") - Remove commented-out imports (System.Console.GetOpt, System.Environment) - Improve code formatting and consistency - Remove unnecessary blank lines - Align guard clauses in remoteUrlToRemote All changes maintain backward compatibility while improving code readability and maintainability. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude * Bump version to 0.9.8.0 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --------- Co-authored-by: Claude --- app/Main.hs | 160 ++++++--------- gwcli.cabal | 2 +- src/CommandLineParser.hs | 383 +++++++++++++++++++++--------------- src/NewCommandLineParser.hs | 226 --------------------- 4 files changed, 290 insertions(+), 481 deletions(-) delete mode 100644 src/NewCommandLineParser.hs diff --git a/app/Main.hs b/app/Main.hs index 082a824..0e8a957 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -3,19 +3,15 @@ module Main where --- New Parser Imports -import NewCommandLineParser (CliArguments (..), Command (..), - GlobalOptions (..), AuthOptions (..), - BrowseOptionsCli (..), IssueCommand (..), - IssueListOptionsCli (..), +import CommandLineParser (AuthOptions (..), BrowseOptionsCli (..), + CliArguments (..), Command (..), + GlobalOptions (..), IssueCommand (..), IssueCreateOptionsCli (..), - IssueShowOptions (..), - PullRequestCommand (..), - PullRequestListOptionsCli (..), + IssueListOptionsCli (..), + IssueShowOptions (..), PullRequestCommand (..), PullRequestCreateOptionsCli (..), - PullRequestShowOptions (..), - parseCliArgs) --- Used by existing logic, keep for now + PullRequestListOptionsCli (..), + PullRequestShowOptions (..), parseCliArgs) import CredentialUtils (Credentials (..), credFilePath, readCredential, writeCredential) import Data.List (isInfixOf, isPrefixOf) @@ -33,18 +29,17 @@ import Remote (authenticate, createIssue, readPRTemplate) import RemoteTypes (Remote (..)) import qualified RemoteTypes as R --- import System.Console.GetOpt (ArgOrder (RequireOrder), getOpt) -- Removed import System.Directory (removeFile) --- import System.Environment (getArgs) -- Removed, parseCliArgs handles this import qualified Types.Issue as I import qualified Types.PullRequest as PR import WebUtils as WU --- Placeholder for old IssueCreateOptions type, will be replaced by IssueCreateOptionsCli --- This is needed because issueFromEditor still returns the old type. --- We will refactor issueFromEditor later. -data IssueCreateOptions = IssueCreateOptions { iscoTitle :: String, iscoBody :: String, iscoShowHelp :: Bool } +data IssueCreateOptions = IssueCreateOptions + { iscoTitle :: String + , iscoBody :: String + , iscoShowHelp :: Bool + } issueFromEditor :: String -> IO IssueCreateOptions issueFromEditor template = do @@ -60,151 +55,122 @@ candidateBaseBranches = ["develop", "main", "master"] printError :: String -> IO () printError = ioError . userError - - - paramsToIssue :: IssueCreateOptionsCli -> I.Issue paramsToIssue params = I.Issue Nothing (icoTitle params) (Just (icoBody params)) Nothing paramsToPullRequest :: PullRequestCreateOptionsCli -> IO PR.PullRequest paramsToPullRequest opts = do - maybeBranch <- getCurrentBranch - case maybeBranch of - Just src -> return $ PR.PullRequest Nothing (prcoTitle opts) src (prcoBase opts) (Just (prcoBody opts)) Nothing - Nothing -> error "Failed to retrieve source branch." + maybeBranch <- getCurrentBranch + case maybeBranch of + Just src -> return $ PR.PullRequest Nothing (prcoTitle opts) src (prcoBase opts) (Just (prcoBody opts)) Nothing + Nothing -> error "Failed to retrieve source branch." --- TODO: Refactor all handle* functions --- The old handleIssue function, to be refactored or replaced handleIssue :: Bool -> Remote -> IssueCommand -> IO () handleIssue _verbose remote issueCmd = case issueCmd of IssueList opts -> do issues <- listIssues remote (iloAll opts) putStrLn $ formatEachAndJoin issues I.formatIssue IssueCreate opts -> do - -- For now, assume icoTitle and icoBody are provided. - -- Logic for issueFromEditor will be integrated later if needed. let newIssue = paramsToIssue opts response <- createIssue remote newIssue putStrLn $ I.formatIssue response - IssueShow opts -> do + IssueShow opts -> getIssue remote (isoIssueNumber opts) >>= (putStrLn . I.formatIssue) --- The old handlePullRequest function, to be refactored or replaced handlePullRequest :: Bool -> Remote -> PullRequestCommand -> IO () handlePullRequest _verbose remote prCmd = case prCmd of PullRequestList opts -> do prs <- listPullRequests remote (prloAll opts) putStrLn $ formatEachAndJoin prs PR.formatPullRequest PullRequestCreate opts -> do - -- Logic for populateMissingPrco and paramsToPullRequest needs to be integrated - -- For now, directly use provided options. - -- prco <- populateMissingPrco opts remote -- This needs to be adapted - pr <- paramsToPullRequest opts -- This needs to be adapted + pr <- paramsToPullRequest opts response <- createPullRequest remote pr putStrLn $ PR.formatPullRequest response - PullRequestShow opts -> do + PullRequestShow opts -> getPullRequest remote (prsoPrNumber opts) >>= (putStrLn . PR.formatPullRequest) - --- Old populateMissingPrco, needs to be adapted or its logic moved populateMissingPrco :: PullRequestCreateOptionsCli -> Remote -> IO PullRequestCreateOptionsCli -populateMissingPrco PullRequestCreateOptionsCli{ prcoBase=base, prcoTitle=title, prcoBody=body } remote = do - newBase <- determineBaseBranch remote base - R.Message{ R.title=newTitle, R.body=newBody } <- determinePRBody remote title body - return $ PullRequestCreateOptionsCli { prcoBase=newBase, prcoTitle=newTitle, prcoBody=newBody } +populateMissingPrco PullRequestCreateOptionsCli{prcoBase=base, prcoTitle=title, prcoBody=body} remote = do + newBase <- determineBaseBranch remote base + R.Message{R.title=newTitle, R.body=newBody} <- determinePRBody remote title body + return $ PullRequestCreateOptionsCli {prcoBase=newBase, prcoTitle=newTitle, prcoBody=newBody} --- Old determineBaseBranch, seems okay for now determineBaseBranch :: Remote -> String -> IO Branch determineBaseBranch remote "" = do - remoteBase <- defaultBranch remote - case remoteBase of - Just base -> return base - Nothing -> do - remoteBranches <- listRemoteBranches - return $ fromMaybe "master" (firstMatching remoteBranches candidateBaseBranches) + remoteBase <- defaultBranch remote + case remoteBase of + Just base -> return base + Nothing -> do + remoteBranches <- listRemoteBranches + return $ fromMaybe "master" (firstMatching remoteBranches candidateBaseBranches) determineBaseBranch _ specifiedBranch = return specifiedBranch --- Old determinePRBody, seems okay for now determinePRBody :: Remote -> String -> String -> IO R.Message determinePRBody remote "" body = do - newBody <- case body of - "" -> readPRTemplate remote - b -> return b - fp <- openEditorWithTempFile (addEmptyTitle newBody) - content <- readFile fp - removeFile fp - return $ parseMessage content + newBody <- case body of + "" -> readPRTemplate remote + b -> return b + fp <- openEditorWithTempFile (addEmptyTitle newBody) + content <- readFile fp + removeFile fp + return $ parseMessage content determinePRBody _ title body = return $ R.Message title body --- Old addEmptyTitle, seems okay addEmptyTitle :: String -> String addEmptyTitle = (++) "\n\n" --- Refactored handleAuth handleAuth :: Bool -> Credentials -> FilePath -> Remote -> AuthOptions -> IO () -handleAuth _verbose creds credFP remote _authOpts = do -- _authOpts is empty for now +handleAuth _verbose creds credFP remote _authOpts = do tokens <- authenticate remote putStrLn "Fetched access token." - let newCreds = Credentials { github = github creds, bitbucket = tokens } + let newCreds = Credentials {github = github creds, bitbucket = tokens} writeCredential credFP newCreds --- Old remoteUrlToRemote, seems okay remoteUrlToRemote :: String -> Credentials -> Remote remoteUrlToRemote url cred - | "bitbucket" `isInfixOf` url = Bitbucket (WU.accessToken . bitbucket $ cred) - | "github.com" `isInfixOf` url = GitHub (github cred) - | otherwise = error "Could not determine remote URL" + | "bitbucket" `isInfixOf` url = Bitbucket (WU.accessToken . bitbucket $ cred) + | "github.com" `isInfixOf` url = GitHub (github cred) + | otherwise = error "Could not determine remote URL" --- Old chooseRemote, seems okay chooseRemote :: Credentials -> IO Remote chooseRemote c = do - remoteUrl <- getRemoteUrl - case remoteUrl of - Nothing -> error "Could not determine remote URL." - Just url -> return $ remoteUrlToRemote url c + remoteUrl <- getRemoteUrl + case remoteUrl of + Nothing -> error "Could not determine remote URL." + Just url -> return $ remoteUrlToRemote url c --- Old isPullRequestSubCommand, seems okay for now if used by refactored handlers isPullRequestSubCommand :: String -> Bool isPullRequestSubCommand cmd = isPrefixOf "pullrequest" cmd || cmd == "pr" --- Refactored handleBrowse handleBrowse :: Bool -> Remote -> BrowseOptionsCli -> IO () handleBrowse _verbose remote browseOpts = - open remote (boUrl browseOpts) (not (boPrint browseOpts)) -- Assuming open takes a boolean for 'open in browser' + open remote (boUrl browseOpts) (not (boPrint browseOpts)) --- Refactored handleShowVersion --- The actual version string is now handled by optparse-applicative's --version flag. --- This function is called if `gwcli version` subcommand is used. handleShowVersion :: IO () -handleShowVersion = putStrLn ("gwcli " ++ showVersion version) -- Or use a constant from NewCommandLineParser if desired +handleShowVersion = putStrLn ("gwcli " ++ showVersion version) --- Placeholder for globalOptionsToVerboseOpt globalOptionsToVerboseOpt :: GlobalOptions -> Bool globalOptionsToVerboseOpt = optVerbose --- New dispatch function executeCommand :: CliArguments -> Credentials -> FilePath -> Remote -> IO () executeCommand (CliArguments globalOpts cmd) creds credFP remote = case cmd of - AuthCmd authOpts -> handleAuth (globalOptionsToVerboseOpt globalOpts) creds credFP remote authOpts - BrowseCmd browseOpts -> handleBrowse (globalOptionsToVerboseOpt globalOpts) remote browseOpts - IssueCmd issueCmd -> handleIssue (globalOptionsToVerboseOpt globalOpts) remote issueCmd - PullRequestCmd prCmd -> handlePullRequest (globalOptionsToVerboseOpt globalOpts) remote prCmd - VersionCmd _ -> handleShowVersion -- Version is also handled by --version global flag + AuthCmd authOpts -> handleAuth (globalOptionsToVerboseOpt globalOpts) creds credFP remote authOpts + BrowseCmd browseOpts -> handleBrowse (globalOptionsToVerboseOpt globalOpts) remote browseOpts + IssueCmd issueCmd -> handleIssue (globalOptionsToVerboseOpt globalOpts) remote issueCmd + PullRequestCmd prCmd -> handlePullRequest (globalOptionsToVerboseOpt globalOpts) remote prCmd + VersionCmd _ -> handleShowVersion main :: IO () main = do - let versionStr = "gwcli " ++ showVersion version - parsedArgs <- parseCliArgs versionStr -- New parser call - - -- Credential loading (after parsing, before command execution) - credFP <- credFilePath - cred <- readCredential credFP - case cred of - Nothing -> printError "Failed to read credentials file. Please run 'gwcli auth' or check your .gwcli.yaml." - Just c -> do - remote <- chooseRemote c - -- Call the new dispatch function - executeCommand parsedArgs c credFP remote - --- Old functions like handleHelp, dispatchSubcommand, isGlobalHelp, and main's old parsing logic are removed. + let versionStr = "gwcli " ++ showVersion version + parsedArgs <- parseCliArgs versionStr + + credFP <- credFilePath + cred <- readCredential credFP + case cred of + Nothing -> printError "Failed to read credentials file. Please run 'gwcli auth' or check your .gwcli.yaml." + Just c -> do + remote <- chooseRemote c + executeCommand parsedArgs c credFP remote + diff --git a/gwcli.cabal b/gwcli.cabal index cfccf64..3fb4399 100644 --- a/gwcli.cabal +++ b/gwcli.cabal @@ -1,7 +1,7 @@ cabal-version: 3.14 name: gwcli -version: 0.9.7.0 +version: 0.9.8.0 description: Please see the README on GitHub at homepage: https://github.com/diskshima/gwcli-hs bug-reports: https://github.com/diskshima/gwcli-hs/issues diff --git a/src/CommandLineParser.hs b/src/CommandLineParser.hs index e1cd619..3538ee2 100644 --- a/src/CommandLineParser.hs +++ b/src/CommandLineParser.hs @@ -1,157 +1,226 @@ -module CommandLineParser - ( parseCommandLine - , Flag(..) - , IssueListOptions(..) - , IssueCreateOptions(..) - , PullRequestListOptions(..) - , PullRequestCreateOptions(..) - , BrowseOptions(..) -- Added BrowseOptions - , defaultIssueListOptions - , defaultIssueCreateOptions - , defaultPullRequestListOptions - , defaultPullRequestCreateOptions - , defaultBrowseOptions -- Added defaultBrowseOptions - , issueListOptions - , issueCreateOptions - , pullRequestListOptions - , pullRequestCreateOptions - , browseOptions -- Added browseOptions - , globalUsageInfo - , issueUsageHeader - , issueListUsageInfo - , issueCreateUsageInfo - , prUsageHeader - , prListUsageInfo - , prCreateUsageInfo - , browseUsageInfo - ) where - -import System.Console.GetOpt (ArgDescr (..), ArgOrder (RequireOrder), - OptDescr (..), getOpt, usageInfo) --- import Debug.Trace (trace) -- Removed debugging import - -data Flag = Help | Verbose | Version deriving (Show, Eq) -- Added deriving Eq for Flag - -options :: [OptDescr Flag] -options = - [ Option ['v']["verbose"] (NoArg Verbose) "Verbose output" - , Option ['h']["help"] (NoArg Help) "Help" - ] - --- Issue List Options -data IssueListOptions = IssueListOptions { iOptAll :: Bool, ilOptShowHelp :: Bool } -- Changed newtype to data - -defaultIssueListOptions :: IssueListOptions -defaultIssueListOptions = IssueListOptions { iOptAll = False, ilOptShowHelp = False } - -issueListOptions :: [OptDescr (IssueListOptions -> IssueListOptions)] -issueListOptions = - [ Option ['a']["all"] - (NoArg (\opts -> opts { iOptAll = True })) - "show all issues" - , Option ['h'] ["help"] (NoArg (\opts -> opts { ilOptShowHelp = True })) "Show help for list issues" - ] - --- Issue Create Options -data IssueCreateOptions = - IssueCreateOptions { iscoTitle :: String, iscoBody :: String, iscoShowHelp :: Bool } - -defaultIssueCreateOptions :: IssueCreateOptions -defaultIssueCreateOptions = IssueCreateOptions { iscoTitle = "", iscoBody = "", iscoShowHelp = False } - -issueCreateOptions :: [OptDescr (IssueCreateOptions -> IssueCreateOptions)] -issueCreateOptions = - [ Option ['t'] ["title"] - (ReqArg (\title opts -> opts { iscoTitle = title }) "TITLE") - "Issue title" - , Option ['m'] ["message"] - (ReqArg (\msg opts -> opts { iscoBody = msg }) "BODY") - "Issue message (body)" - , Option ['h'] ["help"] (NoArg (\opts -> opts { iscoShowHelp = True })) "Show help for create issue" - ] - --- Pull Request List Options -data PullRequestListOptions = PullRequestListOptions { prOptAll :: Bool, prOptShowHelp :: Bool } -- Changed newtype to data - -defaultPullRequestListOptions :: PullRequestListOptions -defaultPullRequestListOptions = PullRequestListOptions { prOptAll = False, prOptShowHelp = False } - -pullRequestListOptions :: [OptDescr (PullRequestListOptions -> PullRequestListOptions)] -pullRequestListOptions = - [ Option ['a']["all"] - (NoArg (\opts -> opts { prOptAll = True })) - "show all pull requests" - , Option ['h'] ["help"] (NoArg (\opts -> opts { prOptShowHelp = True })) "Show help for list pull requests" - ] - --- Pull Request Create Options -data PullRequestCreateOptions = - PullRequestCreateOptions { prcoBase :: String , prcoTitle :: String, prcoBody :: String, prcoShowHelp :: Bool } - -defaultPullRequestCreateOptions :: PullRequestCreateOptions -defaultPullRequestCreateOptions = - PullRequestCreateOptions { prcoBase = "", prcoTitle = "", prcoBody = "", prcoShowHelp = False } - -pullRequestCreateOptions :: [OptDescr (PullRequestCreateOptions -> PullRequestCreateOptions)] -pullRequestCreateOptions = - [ Option ['t'] ["title"] - (ReqArg (\title opts -> opts { prcoTitle = title }) "TITLE") - "Pull request title" - , Option ['b'] ["base"] - (ReqArg (\base opts -> opts { prcoBase = base }) "BRANCH") - "Base (destination) branch" - , Option ['m'] ["message"] - (ReqArg (\msg opts -> opts { prcoBody = msg }) "BODY") - "Pull request message (body)" - , Option ['h'] ["help"] (NoArg (\opts -> opts { prcoShowHelp = True })) "Show help for create pull request" - ] - --- Browse Options -data BrowseOptions = BrowseOptions { brOpenBrowser :: Bool, brShowHelp :: Bool } -- Changed newtype to data - -defaultBrowseOptions :: BrowseOptions -defaultBrowseOptions = BrowseOptions { brOpenBrowser = True, brShowHelp = False } - -browseOptions :: [OptDescr (BrowseOptions -> BrowseOptions)] -browseOptions = - [ Option ['p']["print"] - (NoArg (\opts -> opts { brOpenBrowser = False })) - "Only print the URL (instead of opening browser)." - , Option ['h'] ["help"] (NoArg (\opts -> opts { brShowHelp = True })) "Show help for browse" - ] - -parseCommandLine :: [String] -> ([Flag], [String]) -parseCommandLine args = - case getOpt RequireOrder options args of - (o, n, []) -> (o, n) - (_, _, errs) -> error $ concat errs ++ usageInfo header options - where header = "Usage: gwcli [GLOBAL OPTIONS] [SUBCOMMAND OPTIONS]" - --- Global options help -globalUsageInfo :: String -globalUsageInfo = usageInfo header options - where header = "Usage: gwcli [GLOBAL OPTIONS] [SUBCOMMAND OPTIONS]" - --- Issue subcommand help -issueUsageHeader :: String -issueUsageHeader = "Usage: gwcli issue [OPTIONS]" - -issueListUsageInfo :: String -issueListUsageInfo = usageInfo ("Usage: gwcli issue list [OPTIONS]") issueListOptions - -issueCreateUsageInfo :: String -issueCreateUsageInfo = usageInfo ("Usage: gwcli issue create [OPTIONS]") issueCreateOptions - --- Pull Request subcommand help -prUsageHeader :: String -prUsageHeader = "Usage: gwcli pullrequest [OPTIONS]" - -prListUsageInfo :: String -prListUsageInfo = usageInfo ("Usage: gwcli pullrequest list [OPTIONS]") pullRequestListOptions - -prCreateUsageInfo :: String -prCreateUsageInfo = usageInfo ("Usage: gwcli pullrequest create [OPTIONS]") pullRequestCreateOptions - --- Browse subcommand help -browseUsageInfo :: String -browseUsageInfo = usageInfo ("Usage: gwcli browse [OPTIONS] [page]") browseOptions -- Now uses the real browseOptions +module CommandLineParser ( + Command(..), + AuthOptions(..), + BrowseOptionsCli(..), + IssueCommand(..), + PullRequestCommand(..), + VersionOptions(..), + GlobalOptions(..), + CliArguments(..), + parseCliArgs, + IssueListOptionsCli(..), + IssueCreateOptionsCli(..), + IssueShowOptions(..), + -- Export new types for PullRequest subcommand + PullRequestListOptionsCli(..), + PullRequestCreateOptionsCli(..), + PullRequestShowOptions(..) +) where + +import Options.Applicative + +-- Global options +data GlobalOptions = GlobalOptions + { optVerbose :: Bool + } deriving (Show, Eq) + +globalOptionsParser :: Parser GlobalOptions +globalOptionsParser = GlobalOptions + <$> switch + ( long "verbose" + <> short 'v' + <> help "Enable verbose output" ) + +-- Define option types for each command +data AuthOptions = AuthOptions deriving (Show, Eq) +data BrowseOptionsCli = BrowseOptionsCli + { boUrl :: Maybe String + , boPrint :: Bool + } deriving (Show, Eq) + +-- IssueCommand and its options +data IssueShowOptions = IssueShowOptions + { isoIssueNumber :: String + } deriving (Show, Eq) + +data IssueListOptionsCli = IssueListOptionsCli + { iloAll :: Bool + } deriving (Show, Eq) + +data IssueCreateOptionsCli = IssueCreateOptionsCli + { icoTitle :: String + , icoBody :: String + } deriving (Show, Eq) + +data IssueCommand + = IssueList IssueListOptionsCli + | IssueCreate IssueCreateOptionsCli + | IssueShow IssueShowOptions + deriving (Show, Eq) + +-- PullRequestCommand and its options +data PullRequestShowOptions = PullRequestShowOptions + { prsoPrNumber :: String + } deriving (Show, Eq) + +data PullRequestListOptionsCli = PullRequestListOptionsCli + { prloAll :: Bool + } deriving (Show, Eq) + +data PullRequestCreateOptionsCli = PullRequestCreateOptionsCli + { prcoTitle :: String + , prcoBody :: String + , prcoBase :: String -- Base branch + } deriving (Show, Eq) + +data PullRequestCommand + = PullRequestList PullRequestListOptionsCli + | PullRequestCreate PullRequestCreateOptionsCli + | PullRequestShow PullRequestShowOptions + deriving (Show, Eq) + +data VersionOptions = VersionOptions deriving (Show, Eq) + + +-- Top-level command sum type +data Command + = AuthCmd AuthOptions + | BrowseCmd BrowseOptionsCli + | IssueCmd IssueCommand + | PullRequestCmd PullRequestCommand -- Updated + | VersionCmd VersionOptions + deriving (Show, Eq) + +-- Parsers for individual command options (auth, browse, version, issue actions already exist) +authOptionsParser :: Parser AuthOptions +authOptionsParser = pure AuthOptions + +browseOptionsCliParser :: Parser BrowseOptionsCli +browseOptionsCliParser = BrowseOptionsCli + <$> optional (argument str (metavar "PAGE" <> help "Page identifier (e.g., issue/PR number, specific path like 'pulls')")) + <*> switch + ( long "print" + <> short 'p' + <> help "Only print the URL, don't open in browser" ) + +versionOptionsParser :: Parser VersionOptions +versionOptionsParser = pure VersionOptions + +-- Parsers for issue actions +issueShowOptionsParser :: Parser IssueShowOptions +issueShowOptionsParser = IssueShowOptions + <$> argument str (metavar "ISSUE_NUMBER" <> help "Issue number to show") + +issueListOptionsParser :: Parser IssueListOptionsCli +issueListOptionsParser = IssueListOptionsCli + <$> switch + ( long "all" + <> short 'a' + <> help "Show all issues (including closed/resolved)" ) + +issueCreateOptionsParser :: Parser IssueCreateOptionsCli +issueCreateOptionsParser = IssueCreateOptionsCli + <$> strOption + ( long "title" + <> short 't' + <> metavar "TITLE" + <> help "Title of the issue" ) + <*> strOption + ( long "message" + <> short 'm' + <> metavar "BODY" + <> help "Body/description of the issue" ) + +-- Parser for the issue subcommand and its actions +issueCommandParser :: Parser IssueCommand +issueCommandParser = subparser + ( command "list" (info (IssueList <$> issueListOptionsParser <**> helper) + (progDesc "List issues. Use --all to show all issues.")) + <> command "create" (info (IssueCreate <$> issueCreateOptionsParser <**> helper) + (progDesc "Create a new issue.")) + <> command "show" (info (IssueShow <$> issueShowOptionsParser <**> helper) + (progDesc "Show a specific issue by its number.")) + ) + +-- Parsers for pull request actions +pullRequestShowOptionsParser :: Parser PullRequestShowOptions +pullRequestShowOptionsParser = PullRequestShowOptions + <$> argument str (metavar "PR_NUMBER" <> help "Pull request number to show") + +pullRequestListOptionsParser :: Parser PullRequestListOptionsCli +pullRequestListOptionsParser = PullRequestListOptionsCli + <$> switch + ( long "all" + <> short 'a' + <> help "Show all pull requests (including merged/closed)" ) + +pullRequestCreateOptionsParser :: Parser PullRequestCreateOptionsCli +pullRequestCreateOptionsParser = PullRequestCreateOptionsCli + <$> strOption + ( long "title" + <> short 't' + <> metavar "TITLE" + <> help "Title of the pull request" ) + <*> strOption + ( long "message" -- Or "body" + <> short 'm' -- Or 'd' for description + <> metavar "BODY" + <> help "Body/description of the pull request" ) + <*> strOption + ( long "base" + <> short 'b' + <> metavar "TARGET_BRANCH" + <> help "Base (target) branch for the pull request" ) + +-- Parser for the pullrequest subcommand and its actions +pullRequestCommandParser :: Parser PullRequestCommand +pullRequestCommandParser = subparser + ( command "list" (info (PullRequestList <$> pullRequestListOptionsParser <**> helper) + (progDesc "List pull requests. Use --all to show all PRs.")) + <> command "create" (info (PullRequestCreate <$> pullRequestCreateOptionsParser <**> helper) + (progDesc "Create a new pull request.")) + <> command "show" (info (PullRequestShow <$> pullRequestShowOptionsParser <**> helper) + (progDesc "Show a specific pull request by its number.")) + ) + +-- Combined command parser using subcommands +commandParser :: Parser Command +commandParser = subparser + ( command "auth" (info (AuthCmd <$> authOptionsParser <**> helper) (progDesc "Authenticate with services")) + <> command "browse" (info (BrowseCmd <$> browseOptionsCliParser <**> helper) (progDesc "Open repository page in browser")) + <> command "issue" (info (IssueCmd <$> issueCommandParser) (progDesc "Manage issues (list, create, show)")) + <> command "pullrequest" (info (PullRequestCmd <$> pullRequestCommandParser) (progDesc "Manage pull requests (list, create, show)")) -- Added + <> command "version" (info (VersionCmd <$> versionOptionsParser <**> helper) (progDesc "Show version (same as --version flag)")) + ) + +-- Top-level parser for all arguments (GlobalOptions + Command) +data CliArguments = CliArguments GlobalOptions Command deriving (Show, Eq) + +cliArgumentsParser :: Parser CliArguments +cliArgumentsParser = CliArguments <$> globalOptionsParser <*> commandParser + +-- Version option for --version flag (version string provided externally) +versionOption :: String -> Parser (a -> a) +versionOption versionStr = infoOption versionStr + ( long "version" + <> short 'V' -- Different from verbose 'v' + <> help "Show version information" + <> hidden ) -- Hidden because we also have a 'version' subcommand + +-- ParserInfo for the entire application +optsParserInfo :: String -> ParserInfo CliArguments +optsParserInfo versionStr = info (cliArgumentsParser <**> helper <**> versionOption versionStr) + ( fullDesc + <> progDesc ( + "CLI tool for interacting with Git services. " ++ + "Try 'gwcli --help' for command-specific help.\n\n" ++ -- Added newline for better formatting + "To generate completion scripts (redirect output to a file):\n" ++ + " gwcli --bash-completion-script gwcli\n" ++ + " gwcli --fish-completion-script gwcli\n" ++ + " gwcli --zsh-completion-script gwcli" + ) + <> header "gwcli - Git Workflow CLI" ) + +-- Main function to be called from Main.hs +parseCliArgs :: String -> IO CliArguments +parseCliArgs versionStr = execParser (optsParserInfo versionStr) diff --git a/src/NewCommandLineParser.hs b/src/NewCommandLineParser.hs deleted file mode 100644 index 45cb0e3..0000000 --- a/src/NewCommandLineParser.hs +++ /dev/null @@ -1,226 +0,0 @@ -module NewCommandLineParser ( - Command(..), - AuthOptions(..), - BrowseOptionsCli(..), - IssueCommand(..), - PullRequestCommand(..), - VersionOptions(..), - GlobalOptions(..), - CliArguments(..), - parseCliArgs, - IssueListOptionsCli(..), - IssueCreateOptionsCli(..), - IssueShowOptions(..), - -- Export new types for PullRequest subcommand - PullRequestListOptionsCli(..), - PullRequestCreateOptionsCli(..), - PullRequestShowOptions(..) -) where - -import Options.Applicative - --- Global options -data GlobalOptions = GlobalOptions - { optVerbose :: Bool - } deriving (Show, Eq) - -globalOptionsParser :: Parser GlobalOptions -globalOptionsParser = GlobalOptions - <$> switch - ( long "verbose" - <> short 'v' - <> help "Enable verbose output" ) - --- Define option types for each command -data AuthOptions = AuthOptions deriving (Show, Eq) -data BrowseOptionsCli = BrowseOptionsCli - { boUrl :: Maybe String - , boPrint :: Bool - } deriving (Show, Eq) - --- IssueCommand and its options -data IssueShowOptions = IssueShowOptions - { isoIssueNumber :: String - } deriving (Show, Eq) - -data IssueListOptionsCli = IssueListOptionsCli - { iloAll :: Bool - } deriving (Show, Eq) - -data IssueCreateOptionsCli = IssueCreateOptionsCli - { icoTitle :: String - , icoBody :: String - } deriving (Show, Eq) - -data IssueCommand - = IssueList IssueListOptionsCli - | IssueCreate IssueCreateOptionsCli - | IssueShow IssueShowOptions - deriving (Show, Eq) - --- PullRequestCommand and its options -data PullRequestShowOptions = PullRequestShowOptions - { prsoPrNumber :: String - } deriving (Show, Eq) - -data PullRequestListOptionsCli = PullRequestListOptionsCli - { prloAll :: Bool - } deriving (Show, Eq) - -data PullRequestCreateOptionsCli = PullRequestCreateOptionsCli - { prcoTitle :: String - , prcoBody :: String - , prcoBase :: String -- Base branch - } deriving (Show, Eq) - -data PullRequestCommand - = PullRequestList PullRequestListOptionsCli - | PullRequestCreate PullRequestCreateOptionsCli - | PullRequestShow PullRequestShowOptions - deriving (Show, Eq) - -data VersionOptions = VersionOptions deriving (Show, Eq) - - --- Top-level command sum type -data Command - = AuthCmd AuthOptions - | BrowseCmd BrowseOptionsCli - | IssueCmd IssueCommand - | PullRequestCmd PullRequestCommand -- Updated - | VersionCmd VersionOptions - deriving (Show, Eq) - --- Parsers for individual command options (auth, browse, version, issue actions already exist) -authOptionsParser :: Parser AuthOptions -authOptionsParser = pure AuthOptions - -browseOptionsCliParser :: Parser BrowseOptionsCli -browseOptionsCliParser = BrowseOptionsCli - <$> optional (argument str (metavar "PAGE" <> help "Page identifier (e.g., issue/PR number, specific path like 'pulls')")) - <*> switch - ( long "print" - <> short 'p' - <> help "Only print the URL, don't open in browser" ) - -versionOptionsParser :: Parser VersionOptions -versionOptionsParser = pure VersionOptions - --- Parsers for issue actions -issueShowOptionsParser :: Parser IssueShowOptions -issueShowOptionsParser = IssueShowOptions - <$> argument str (metavar "ISSUE_NUMBER" <> help "Issue number to show") - -issueListOptionsParser :: Parser IssueListOptionsCli -issueListOptionsParser = IssueListOptionsCli - <$> switch - ( long "all" - <> short 'a' - <> help "Show all issues (including closed/resolved)" ) - -issueCreateOptionsParser :: Parser IssueCreateOptionsCli -issueCreateOptionsParser = IssueCreateOptionsCli - <$> strOption - ( long "title" - <> short 't' - <> metavar "TITLE" - <> help "Title of the issue" ) - <*> strOption - ( long "message" - <> short 'm' - <> metavar "BODY" - <> help "Body/description of the issue" ) - --- Parser for the issue subcommand and its actions -issueCommandParser :: Parser IssueCommand -issueCommandParser = subparser - ( command "list" (info (IssueList <$> issueListOptionsParser <**> helper) - (progDesc "List issues. Use --all to show all issues.")) - <> command "create" (info (IssueCreate <$> issueCreateOptionsParser <**> helper) - (progDesc "Create a new issue.")) - <> command "show" (info (IssueShow <$> issueShowOptionsParser <**> helper) - (progDesc "Show a specific issue by its number.")) - ) - --- Parsers for pull request actions -pullRequestShowOptionsParser :: Parser PullRequestShowOptions -pullRequestShowOptionsParser = PullRequestShowOptions - <$> argument str (metavar "PR_NUMBER" <> help "Pull request number to show") - -pullRequestListOptionsParser :: Parser PullRequestListOptionsCli -pullRequestListOptionsParser = PullRequestListOptionsCli - <$> switch - ( long "all" - <> short 'a' - <> help "Show all pull requests (including merged/closed)" ) - -pullRequestCreateOptionsParser :: Parser PullRequestCreateOptionsCli -pullRequestCreateOptionsParser = PullRequestCreateOptionsCli - <$> strOption - ( long "title" - <> short 't' - <> metavar "TITLE" - <> help "Title of the pull request" ) - <*> strOption - ( long "message" -- Or "body" - <> short 'm' -- Or 'd' for description - <> metavar "BODY" - <> help "Body/description of the pull request" ) - <*> strOption - ( long "base" - <> short 'b' - <> metavar "TARGET_BRANCH" - <> help "Base (target) branch for the pull request" ) - --- Parser for the pullrequest subcommand and its actions -pullRequestCommandParser :: Parser PullRequestCommand -pullRequestCommandParser = subparser - ( command "list" (info (PullRequestList <$> pullRequestListOptionsParser <**> helper) - (progDesc "List pull requests. Use --all to show all PRs.")) - <> command "create" (info (PullRequestCreate <$> pullRequestCreateOptionsParser <**> helper) - (progDesc "Create a new pull request.")) - <> command "show" (info (PullRequestShow <$> pullRequestShowOptionsParser <**> helper) - (progDesc "Show a specific pull request by its number.")) - ) - --- Combined command parser using subcommands -commandParser :: Parser Command -commandParser = subparser - ( command "auth" (info (AuthCmd <$> authOptionsParser <**> helper) (progDesc "Authenticate with services")) - <> command "browse" (info (BrowseCmd <$> browseOptionsCliParser <**> helper) (progDesc "Open repository page in browser")) - <> command "issue" (info (IssueCmd <$> issueCommandParser) (progDesc "Manage issues (list, create, show)")) - <> command "pullrequest" (info (PullRequestCmd <$> pullRequestCommandParser) (progDesc "Manage pull requests (list, create, show)")) -- Added - <> command "version" (info (VersionCmd <$> versionOptionsParser <**> helper) (progDesc "Show version (same as --version flag)")) - ) - --- Top-level parser for all arguments (GlobalOptions + Command) -data CliArguments = CliArguments GlobalOptions Command deriving (Show, Eq) - -cliArgumentsParser :: Parser CliArguments -cliArgumentsParser = CliArguments <$> globalOptionsParser <*> commandParser - --- Version option for --version flag (version string provided externally) -versionOption :: String -> Parser (a -> a) -versionOption versionStr = infoOption versionStr - ( long "version" - <> short 'V' -- Different from verbose 'v' - <> help "Show version information" - <> hidden ) -- Hidden because we also have a 'version' subcommand - --- ParserInfo for the entire application -optsParserInfo :: String -> ParserInfo CliArguments -optsParserInfo versionStr = info (cliArgumentsParser <**> helper <**> versionOption versionStr) - ( fullDesc - <> progDesc ( - "CLI tool for interacting with Git services. " ++ - "Try 'gwcli --help' for command-specific help.\n\n" ++ -- Added newline for better formatting - "To generate completion scripts (redirect output to a file):\n" ++ - " gwcli --bash-completion-script gwcli\n" ++ - " gwcli --fish-completion-script gwcli\n" ++ - " gwcli --zsh-completion-script gwcli" - ) - <> header "gwcli - Git Workflow CLI" ) - --- Main function to be called from Main.hs -parseCliArgs :: String -> IO CliArguments -parseCliArgs versionStr = execParser (optsParserInfo versionStr) From 35ef5f35c77b476cda6c4b67525f57d632e16643 Mon Sep 17 00:00:00 2001 From: Daisuke Shimamoto Date: Sat, 11 Oct 2025 16:58:17 +0900 Subject: [PATCH 3/3] Update changelog for version 0.9.8.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add changelog entries documenting the refactoring work: - Module renaming (NewCommandLineParser to CommandLineParser) - Removal of old GetOpt-based parser - Code cleanup and formatting improvements - Maintainability improvements after optparse-applicative migration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- ChangeLog.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 685a82b..e25a770 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -2,6 +2,13 @@ ## Unreleased changes +## 0.9.8.0 -- 2025-10-11 + +* Refactored module naming: renamed NewCommandLineParser to CommandLineParser (#94) +* Removed old GetOpt-based command-line parser +* Code cleanup and formatting improvements in Main.hs +* Improved code maintainability after optparse-applicative migration + ## 0.9.7.0 -- 2025-01-27 * Migrated command-line parsing to optparse-applicative with shell completions (#90)