diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7330e08..25883fb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,6 +7,6 @@ Please note we have a code of conduct, please follow it in all your interactions ## Pull Request Process 1. Ensure any install or build dependencies are removed before the end of the layer when doing a build. -2. Update the README.md with detafils of changes to the interface, this includes new environment variables, exposed ports, useful file locations and container parameters. +2. Update the README.md with details of changes to the interface, this includes new environment variables, exposed ports, useful file locations and container parameters. 3. Increase the version numbers in any examples files and the README.md to the new version that this Pull Request would represent. The versioning scheme we use is [SemVer](https://semver.org). 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you do not have permission to do that, you may request the second reviewer to merge it for you. diff --git a/README.md b/README.md index 0329d68..85ab8d8 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ $ go get github.com/dnnrly/httpref/cmd/httpref # Usage +## Filter by Title + ``` $ httpref 1 1xx Informational response @@ -41,7 +43,7 @@ $ httpref 1 101 Switching 102 Processing 103 Early hints - + $ httpref 200 200 - OK @@ -60,6 +62,21 @@ The successful result of a PUT or a DELETE is often not a 200 OK but a 204 No Co https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200 ``` +## Full-text Search + +The `--search` option accepts a term to full-text search. This option is available for header, method, and status references. + +``` +$ httpref --search clear +Clear-Site-Data + Clears browsing data (e.g. cookies, storage, cache) associated with the requesting + website. +205 + Reset Content +431 + Request Header Fields Too Large + + ## Important `make` targets * `deps` - downloads all of the deps you need to build, test, and release diff --git a/cmd/root.go b/cmd/root.go index 377308c..4a6ee1d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -11,28 +11,29 @@ import ( ) var ( - titles = false - width = 100 + titles = false + width = 100 + searchTerm = "" ) -// rootCmd represents the base command when ctitlesed without any subcommands +// rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "httpref [filter]", Args: cobra.MaximumNArgs(1), Short: "Command line access to HTTP references", Long: paragraphical.Format(width, `This displays useful information related to HTTP. -It will prefer exact matches where there are mutliple entries matching the filter (e.g. Accept and Accept-Language). If you want to match everything with the same prefix then you can use * as a wildcard suffix, for example: +It will prefer exact matches where there are multiple entries matching the filter (e.g. Accept and Accept-Language). If you want to match everything with the same prefix then you can use * as a wildcard suffix, for example: httpref 'Accept*' Most of the content comes from the Mozilla developer documentation (https://developer.mozilla.org/en-US/docs/Web/HTTP) and is copyright Mozilla and individual contributors. See https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses for details. Ports can only be looked up using the 'ports' sub command. You can also look up ports inside a range. Information on ports comes from https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers under the Creative Commons Attribution-ShareAlike License.`), - RunE: root, + Run: root, } // Execute adds titles child commands to the root command and sets flags appropriately. -// This is ctitlesed by main.main(). It only needs to happen once to the rootCmd. +// This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { if err := rootCmd.Execute(); err != nil { fmt.Println(err) @@ -43,6 +44,7 @@ func Execute() { func init() { rootCmd.PersistentFlags().BoolVarP(&titles, "titles", "t", titles, "List titles of the summaries available") rootCmd.PersistentFlags().IntVarP(&width, "width", "w", width, "Width to fit the output to") + rootCmd.PersistentFlags().StringVarP(&searchTerm, "search", "", searchTerm, "Full-text search term") rootCmd.AddCommand(subCmd("methods", "method", httpref.Methods)) rootCmd.AddCommand(subCmd("statuses", "status", httpref.Statuses)) @@ -64,26 +66,35 @@ func subCmd(name, alias string, ref httpref.References) *cobra.Command { } } -func root(cmd *cobra.Command, args []string) error { - results := append(httpref.Statuses.Titles(), httpref.Headers.Titles()...) - results = append(results, httpref.Methods.Titles()...) - results = append(results, httpref.WellKnownPorts.Titles()...) - results = append(results, httpref.RegisteredPorts.Titles()...) +func root(cmd *cobra.Command, args []string) { + if titles { + results := append(httpref.Statuses.Titles(), httpref.Headers.Titles()...) + results = append(results, httpref.Methods.Titles()...) + results = append(results, httpref.WellKnownPorts.Titles()...) + results = append(results, httpref.RegisteredPorts.Titles()...) - if !titles { - if len(args) == 0 { - fmt.Fprintf(os.Stderr, "Must specify something to filter by\n") - os.Exit(1) - } else { - results = append(httpref.Statuses, httpref.Headers...) - results = append(results, httpref.Methods...) - results = results.ByName(args[0]) - } + printResults(results) + + return } - printResults(results) + if searchTerm == "" && len(args) == 0 { + fmt.Fprintf(os.Stderr, "Must specify something to filter by\n") + os.Exit(1) + } + + results := append(httpref.Headers, httpref.Methods...) + results = append(results, httpref.Statuses...) + + if searchTerm != "" { + results = results.Search(searchTerm) + printResults(results) - return nil + return + } + + results = results.ByName(args[0]) + printResults(results) } func printResults(results httpref.References) { @@ -100,22 +111,29 @@ func printResults(results httpref.References) { } } -func referenceCmd(ref httpref.References) func(cmd *cobra.Command, args []string) { +func referenceCmd(results httpref.References) func(cmd *cobra.Command, args []string) { return func(cmd *cobra.Command, args []string) { - results := ref + if searchTerm != "" { + printResults(results.Search(searchTerm)) + return + } if len(args) == 0 { - results = results.Titles() - } else { - results = results.ByName(args[0]) + printResults(results.Titles()) + return } - printResults(results) + printResults(results.ByName(args[0])) } } func portsReference() func(cmd *cobra.Command, args []string) { return func(cmd *cobra.Command, args []string) { + if searchTerm != "" { + fmt.Fprintf(os.Stderr, "error: full-text search not supported\n") + os.Exit(1) + } + ref := append(httpref.WellKnownPorts, httpref.RegisteredPorts...) var results httpref.References @@ -123,13 +141,12 @@ func portsReference() func(cmd *cobra.Command, args []string) { results = ref.Titles() } else { results = ref.ByName(args[0]) - + if len(results) == 0 { results = ref.InRange(args[0]) } } - printResults(results) } } diff --git a/httpref.go b/httpref.go index fd87c11..b61bef0 100644 --- a/httpref.go +++ b/httpref.go @@ -87,3 +87,17 @@ func (r References) Titles() References { return results } + +func (r References) Search(term string) References { + results := References{} + + for _, v := range r { + if strings.Contains(strings.ToLower(v.Name), term) || + strings.Contains(strings.ToLower(v.Summary), term) || + strings.Contains(strings.ToLower(v.Description), term) { + results = append(results, v) + } + } + + return results +} diff --git a/httpref_test.go b/httpref_test.go index be97611..dca1d7e 100644 --- a/httpref_test.go +++ b/httpref_test.go @@ -111,3 +111,8 @@ func TestPortsConsistencyValidation(t *testing.T) { } } } + +func TestReferences_Search(t *testing.T) { + n := Statuses.Search("auth") + assert.Equal(t, 8, len(n)) +} diff --git a/test/basic.bats b/test/basic.bats index 11a4897..5bc3dd6 100644 --- a/test/basic.bats +++ b/test/basic.bats @@ -59,6 +59,31 @@ BIN=./httpref [ "$(echo $output | grep -c '/docs/Web/HTTP/Headers/Accept$')" -eq 1 ] } +@test "Full-text search option works on root" { + run ${BIN} --search clear + [ $status -eq 0 ] +} + +@test "Full-text search option works on headers" { + run ${BIN} headers --search cache + [ $status -eq 0 ] +} + +@test "Full-text search option works on methods" { + run ${BIN} methods --search cache + [ $status -eq 0 ] +} + +@test "Full-text search option works on statuses" { + run ${BIN} statuses --search cache + [ $status -eq 0 ] +} + +@test "Full-text search option does NOT work on ports" { + run ${BIN} ports --search cache + [ $status -eq 1 ] +} + @test "Can change the width of the output" { run ${BIN} -w 70 100 [ $status -eq 0 ]