Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d0b103a
Merge branch 'main' of github.com:gofr-dev/gofr into release/v1.42.3
Umang01-hash Jul 9, 2025
b560a96
udpdate release version to v1.42.3
Umang01-hash Jul 9, 2025
4bcc782
Merge pull request #2047 from gofr-dev/release/v1.42.3
Umang01-hash Jul 9, 2025
3137ed4
update release version to v1.42.4
Umang01-hash Jul 25, 2025
27c3f79
Merge branch 'development' of github.com:gofr-dev/gofr into release/v…
coolwednesday Jul 25, 2025
e663a51
Release/v1.42.4 (#2092)
Umang01-hash Jul 25, 2025
e964e1f
Merge remote-tracking branch 'origin/main' into release/v1.42.5
Umang01-hash Aug 1, 2025
bad33fc
update release version to v1.42.5
Umang01-hash Aug 1, 2025
fa6c7c1
Release/v1.42.5 (#2115)
Umang01-hash Aug 1, 2025
ad79586
Merge branch 'main' into release/v1.43.0
Umang01-hash Aug 5, 2025
ffba79f
update release version to v1.43.0
Umang01-hash Aug 5, 2025
d68809c
Release/v1.43.0 (#2137)
aryanmehrotra Aug 5, 2025
580f94e
Merge branch 'main' into release/v1.44.0
Umang01-hash Aug 21, 2025
ca58ff3
update release version to v1.44.0
Umang01-hash Aug 21, 2025
76a5e93
Release/v1.44.0
aryanmehrotra Aug 21, 2025
1686f68
Merge branch 'main' of https://github.com/gofr-dev/gofr into docs-upd…
aryaman-vohra Aug 27, 2025
f8ded88
Add comprehensive CLI documentation and examples
aryaman-vohra Aug 27, 2025
3166bc4
Merge branch 'development' into docs-update-newCMD
aryaman-vohra Aug 29, 2025
06bd68f
Merge branch 'development' into docs-update-newCMD
aryaman-vohra Aug 29, 2025
119e76d
Merge branch 'development' into docs-update-newCMD
Umang01-hash Sep 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
427 changes: 427 additions & 0 deletions docs/cli/cli.md

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions docs/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ export const navigation = [
title: 'Hello Server',
href: '/docs/quick-start/introduction' ,
desc: "Getting started with how to write a server using GoFR with basic examples and explanations. Boost your productivity with efficient coding practices and learn to build scalable applications quickly."},

{
title: 'CLI Applications',
href: '/docs/cli/cli',
desc: "Learn to build powerful command-line interface (CLI) applications using GoFr's app.NewCMD(), offering a robust framework for command-line tools."
},

{
title: 'Configuration',
href: '/docs/quick-start/configuration',
Expand Down
119 changes: 119 additions & 0 deletions examples/cli-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# GoFr CLI Examples

This directory contains examples demonstrating how to build Command-Line Interface (CLI) applications using the GoFr framework.

⚠️ **Version Note**: These examples are designed for the current stable GoFr version where automatic argument parsing (`ctx.Args()` / `ctx.Flags()`) is not yet available. Arguments and flags are therefore parsed manually using `os.Args` and helper functions.

---

## Example 1: Multiple Subcommands with Manual Argument Parsing

**File**: `example1-mutli-sub-command/main.go`

This example demonstrates a robust GoFr CLI application supporting multiple subcommands (`hello` and `goodbye`). It showcases how to manually parse both flag-based and positional arguments using `os.Args` and a custom helper function.

### Purpose
- Define multiple subcommands: `hello` and `goodbye`.
- Handle `--name` flag and positional arguments (e.g., `hello John`, `goodbye Jane`).
- Provide default values if no argument is supplied for either subcommand.
- Output results using `ctx.Out.Println`.

### How to Run

First, ensure you have the `example1-mutli-sub-command/main.go` file created in this directory (content provided below).

Navigate to your GoFr project root and execute the following commands:

1. **Run `hello` subcommand with default value (no arguments):**
```bash
go run examples/cli-example/example1-mutli-sub-command/main.go hello
# Output: Hello, World!
```

2. **Run `hello` subcommand with a positional argument:**
```bash
go run examples/cli-example/example1-mutli-sub-command/main.go hello John
# Output: Hello, John!
```

3. **Run `hello` subcommand with a flag argument:**
```bash
go run examples/cli-example/example1-mutli-sub-command/main.go hello --name Jane
# Output: Hello, Jane!
```

4. **Run `goodbye` subcommand with default value (no arguments):**
```bash
go run examples/cli-example/example1-mutli-sub-command/main.go goodbye
# Output: Goodbye, Friend!
```

5. **Run `goodbye` subcommand with a positional argument:**
```bash
go run examples/cli-example/example1-mutli-sub-command/main.go goodbye Mark
# Output: Goodbye, Mark!
```

6. **Run `goodbye` subcommand with a flag argument:**
```bash
go run examples/cli-example/example1-mutli-sub-command/main.go goodbye --name Susan
# Output: Goodbye, Susan!
```

### Key Concepts Demonstrated
- **`app.NewCMD()`**: Initializes a new GoFr CLI application.
- **`app.SubCommand("name", handler)`**: Registers multiple subcommands with their respective handler functions.
- **Manual Argument Parsing**: `os.Args` is used directly with a helper function (`getFlagValue`) to extract flag values (e.g., `--name`) and positional arguments within each subcommand's handler.
- **`ctx.Out.Println()`**: Prints output directly to the standard CLI output stream.
- **Subcommand Handler Signature:**
```go
func(ctx *gofr.Context) (any, error)
```
This is the required signature for all subcommand handlers, returning an optional result and an error.

---

## Example 2: Single Subcommand with Manual Argument Parsing

**File**: `example2-single-sub-command/main.go`

This example demonstrates a basic GoFr CLI application with a single subcommand (`hello`), focusing on manual argument parsing.

### Purpose
- Define a single subcommand: `hello`.
- Handle `--name` flag and positional arguments (e.g., `hello John`).
- Provide default values if no argument is supplied.
- Output results using `ctx.Out.Println`.

### How to Run

Navigate to your GoFr project root and execute:

1. **Run with default value (no arguments):**
```bash
go run examples/cli-example/example2-single-sub-command/main.go hello
# Output: Hello, World!
```

2. **Run with a positional argument:**
```bash
go run examples/cli-example/example2-single-sub-command/main.go hello John
# Output: Hello, John!
```

3. **Run with a flag argument:**
```bash
go run examples/cli-example/example2-single-sub-command/main.go hello --name Jane
# Output: Hello, Jane!
```

### Key Concepts Demonstrated
- **`app.NewCMD()`**: Initializes a new GoFr CLI application.
- **`app.SubCommand("name", handler)`**: Registers a subcommand with its handler function.
- **Manual Argument Parsing**: Use `os.Args` with a helper function (`getFlagValue`) to extract flag values (e.g., `--name`).
- **`ctx.Out.Println()`**: Prints output directly to the standard CLI output stream.
- **Subcommand Handler Signature:**
```go
func(ctx *gofr.Context) (any, error)
```
This is required for all subcommand handlers, returning an optional result and an error.
58 changes: 58 additions & 0 deletions examples/cli-example/example1-mutli-sub-command/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package main

import (
"fmt"
"os"
"strings"

"gofr.dev/pkg/gofr"
)

// helper function to parse flags manually
func getFlagValue(args []string, flag string, defaultValue string) string {
for i := 0; i < len(args); i++ {
if args[i] == flag && i+1 < len(args) {
return args[i+1]
}
}
return defaultValue
}

func main() {
app := gofr.NewCMD()

// -----------------------
// Subcommand: hello
// -----------------------
app.SubCommand("hello", func(ctx *gofr.Context) (any, error) {
args := os.Args[2:] // arguments after "hello"
name := getFlagValue(args, "--name", "")
if name == "" && len(args) > 0 && !strings.HasPrefix(args[0], "--") {
name = args[0] // fallback to positional arg
}
if name == "" {
name = "World"
}
ctx.Out.Println(fmt.Sprintf("Hello, %s!", name))
return nil, nil
})

// -----------------------
// Subcommand: goodbye
// -----------------------
app.SubCommand("goodbye", func(ctx *gofr.Context) (any, error) {
args := os.Args[2:] // arguments after "goodbye"
name := getFlagValue(args, "--name", "")
if name == "" && len(args) > 0 && !strings.HasPrefix(args[0], "--") {
name = args[0]
}
if name == "" {
name = "Friend"
}
ctx.Out.Println(fmt.Sprintf("Goodbye, %s!", name))
return nil, nil
})

// Run the CLI app
app.Run()
}
46 changes: 46 additions & 0 deletions examples/cli-example/example2-single-sub-command/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package main

import (
"fmt"
"os"
"strings"

"gofr.dev/pkg/gofr"
)

// Helper function to manually parse flags
func getFlagValue(args []string, flag string, defaultValue string) string {
for i := 0; i < len(args); i++ {
if args[i] == flag && i+1 < len(args) {
return args[i+1]
}
}
return defaultValue
}

func main() {
app := gofr.NewCMD()

// -----------------------
// Subcommand: hello
// -----------------------
app.SubCommand("hello", func(ctx *gofr.Context) (any, error) {
args := os.Args[2:] // arguments after "hello"
name := getFlagValue(args, "--name", "")

// fallback to positional argument if --name not provided
if name == "" && len(args) > 0 && !strings.HasPrefix(args[0], "--") {
name = args[0]
}

if name == "" {
name = "World"
}

ctx.Out.Println(fmt.Sprintf("Hello, %s!", name))
return nil, nil
})

// Run the CLI application
app.Run()
}
11 changes: 11 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel all the changes in the go.work.sum are not related to scope of this PR so please revert them back.

github.com/testcontainers/testcontainers-go v0.28.0 h1:1HLm9qm+J5VikzFDYhOd+Zw12NtOl+8drH2E8nTY1r8=
github.com/testcontainers/testcontainers-go v0.28.0/go.mod h1:COlDpUXbwW3owtpMkEB1zo9gwb1CoKVKlyrVPejF4AU=
github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw=
Expand Down Expand Up @@ -1256,6 +1257,8 @@ golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ss
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
Expand Down Expand Up @@ -1291,6 +1294,8 @@ golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
Expand Down Expand Up @@ -1324,6 +1329,8 @@ golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand All @@ -1349,6 +1356,7 @@ golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down Expand Up @@ -1389,6 +1397,7 @@ golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMe
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ=
golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4=
golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488/go.mod h1:fGb/2+tgXXjhjHsTNdVEEMZNWA0quBnfrO+AfoDSAKw=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down Expand Up @@ -1449,6 +1458,8 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
Expand Down
2 changes: 1 addition & 1 deletion pkg/gofr/version/version.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package version

const Framework = "dev"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is not needed please revert it.

const Framework = "v1.44.0"
Loading