From d02fed478581a510abcb75bf8df53b7d7a22d35b Mon Sep 17 00:00:00 2001 From: Julian Skupnjak Date: Fri, 29 Jun 2018 21:33:29 +0200 Subject: [PATCH] implement list option --- .gitignore | 2 + README.md | 30 +++- cmd/resc/cmd/list.go | 45 ++++++ cmd/resc/cmd/man.go | 5 + cmd/resc/cmd/print.go | 5 + cmd/resc/cmd/root.go | 4 +- cmd/resc/cmd/run.go | 5 + scriptmanager/list.go | 56 ++++++++ scriptmanager/list_test.go | 273 +++++++++++++++++++++++++++++++++++++ 9 files changed, 418 insertions(+), 7 deletions(-) create mode 100644 cmd/resc/cmd/list.go create mode 100644 scriptmanager/list.go create mode 100644 scriptmanager/list_test.go diff --git a/.gitignore b/.gitignore index 48b8bf9..ad38ff2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ vendor/ +resc-darwin-amd64 +resc-linux-amd64 diff --git a/README.md b/README.md index f6b7410..40a00c7 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ### OS X ``` -$ wget -O /usr/local/bin/resc https://github.com/JulzDiverse/resc/releases/download/v0.1.0/resc-darwin-amd64 && chmod +x /usr/local/bin/resc +$ wget -O /usr/local/bin/resc https://github.com/JulzDiverse/resc/releases/download/v0.2.0/resc-darwin-amd64 && chmod +x /usr/local/bin/resc ``` OR @@ -25,7 +25,7 @@ $ brew install resc ### Linux ``` -$ wget -O /usr/bin/resc https://github.com/JulzDiverse/resc/releases/download/v0.1.0/resc-linux-amd64 && chmod +x /usr/bin/resc +$ wget -O /usr/bin/resc https://github.com/JulzDiverse/resc/releases/download/v0.2.0/resc-linux-amd64 && chmod +x /usr/bin/resc ``` ## Hello, World! @@ -40,16 +40,18 @@ This runs the `hello-world` script located in the `JulzDiverse/remote-scripts` r ## `resc` scripts -`resc` scripts requires one or more top level directories inside a GitHub repository that contain a `run.sh` script and a `README.md` file. In case of the `hello-world` script the directory looks like this: +`resc` scripts requires one or more top level directories inside a GitHub repository that contain a `run.sh` script, a `.resc` file and a `README.md` file. In case of the `hello-world` script the directory looks like this: ``` .remote-scripts └── hello-world -   ├── run.sh +   ├── .resc + ├── run.sh    └── README.md ``` - The `directory name` (here `hello-world`) indicates the script +- The `.resc` is an empty file that indicates that the directoy is a `resc` script - The `run.sh` is the bash script that is run by `resc` - The `README.md` is a Markdown file that provides information for a script (eg description, usage). The `README.md` is processed by the `resc` CLI and should only contain the following markdown syntax: - H1 (#) @@ -78,14 +80,30 @@ You can also provide parameters to a script using `--args|-a` option. Try it: $ resc run hello-world -r JulzDiverse/remote-scripts -a your-name ``` -### 🧐 Set base `resc` script repository (`set`) +### 🧐 Set default `resc` script repository (`set`) -You can set a base `resc` script repository, s.t you are not required to specify the repository of a script everytime you execute the `resc run`. +You can set a default `resc` script repository, s.t you are not required to specify the repository of a script everytime you execute the `resc run`. ``` $ resc set / ``` +### ✅ List all available scripts in a resc repository (`list`) + +If you want to know what `resc` scripts a repository provides, you can list all of them using `list`. + +If you have set a default repository you can run just: + +``` +$ resc list +``` + +If you want to list scripts of a specific repository, run: + +``` +$ resc list / +``` + ### 📖 Get some script info (`man`) If you want to know what a script does before you run it, you can check the provided README by calling `man`: diff --git a/cmd/resc/cmd/list.go b/cmd/resc/cmd/list.go new file mode 100644 index 0000000..042bbc7 --- /dev/null +++ b/cmd/resc/cmd/list.go @@ -0,0 +1,45 @@ +package cmd + +import ( + "fmt" + "strings" + + "github.com/JulzDiverse/resc/scriptmanager" + "github.com/spf13/cobra" +) + +var listCmd = &cobra.Command{ + Use: "list", + Short: "list remote script of a resc repository", + Run: list, +} + +func list(cmd *cobra.Command, args []string) { + var user, repo string + if len(args) == 0 { + user, repo = configFromFile() + } else { + sl := strings.Split(args[0], "/") + user = sl[0] + repo = sl[1] + } + + scriptManager := scriptmanager.New( + "https://api.github.com", + user, + repo, + ) + + list, err := scriptManager.List() + exitWithError(err) + + listScripts(fmt.Sprintf("%s/%s", user, repo), list) +} + +func listScripts(repo string, scripts []string) { + fmt.Println("ReSc Repository:", repo) + fmt.Println("\nAvailable Scripts:") + for _, script := range scripts { + fmt.Println(" -", script) + } +} diff --git a/cmd/resc/cmd/man.go b/cmd/resc/cmd/man.go index 0757efe..4c0965f 100644 --- a/cmd/resc/cmd/man.go +++ b/cmd/resc/cmd/man.go @@ -2,6 +2,7 @@ package cmd import ( "bufio" + "errors" "fmt" "strings" @@ -17,6 +18,10 @@ var manCmd = &cobra.Command{ } func man(cmd *cobra.Command, args []string) { + if len(args) == 0 { + exitWithError(errors.New("No script specified")) + } + userRepo, err := cmd.Flags().GetString("repo") exitWithError(err) diff --git a/cmd/resc/cmd/print.go b/cmd/resc/cmd/print.go index 7880f28..1d49695 100644 --- a/cmd/resc/cmd/print.go +++ b/cmd/resc/cmd/print.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "strings" @@ -15,6 +16,10 @@ var printCmd = &cobra.Command{ } func print(cmd *cobra.Command, args []string) { + if len(args) == 0 { + exitWithError(errors.New("No script specified")) + } + userRepo, err := cmd.Flags().GetString("repo") exitWithError(err) diff --git a/cmd/resc/cmd/root.go b/cmd/resc/cmd/root.go index c7970ac..777bd93 100644 --- a/cmd/resc/cmd/root.go +++ b/cmd/resc/cmd/root.go @@ -15,17 +15,19 @@ var rootCmd = &cobra.Command{ Use: "resc", Short: "execute remote scripts", Long: `This tool is executing scripts located on github`, - Version: "0.1.0", + Version: "0.2.0", } func init() { initRun() initPrint() initMan() + rootCmd.AddCommand(runCmd) rootCmd.AddCommand(setCmd) rootCmd.AddCommand(printCmd) rootCmd.AddCommand(manCmd) + rootCmd.AddCommand(listCmd) } func Execute() { diff --git a/cmd/resc/cmd/run.go b/cmd/resc/cmd/run.go index 6de7272..6851914 100644 --- a/cmd/resc/cmd/run.go +++ b/cmd/resc/cmd/run.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "strings" "github.com/JulzDiverse/resc/runner" @@ -20,6 +21,10 @@ var runCmd = &cobra.Command{ } func run(cmd *cobra.Command, args []string) { + if len(args) == 0 { + exitWithError(errors.New("No script specified")) + } + userRepo, err := cmd.Flags().GetString("repo") exitWithError(err) diff --git a/scriptmanager/list.go b/scriptmanager/list.go new file mode 100644 index 0000000..a1b5602 --- /dev/null +++ b/scriptmanager/list.go @@ -0,0 +1,56 @@ +package scriptmanager + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/pkg/errors" +) + +type Content struct { + Name string `json:"name"` + ContentType string `json:"type"` +} + +func (s *ScriptManager) List() ([]string, error) { + list, err := getter(fmt.Sprintf("%s/repos/%s/%s/contents", s.url, s.user, s.repo)) + if err != nil { + return nil, err + } + + var contents []Content + err = json.Unmarshal(list, &contents) + if err != nil { + return nil, err + } + + validScripts := []string{} + for _, content := range contents { + if content.ContentType == "dir" { + if ok, err := exists(fmt.Sprintf("%s/repos/%s/%s/contents/%s/.resc", s.url, s.user, s.repo, content.Name)); ok { + validScripts = append(validScripts, content.Name) + } else { + if err != nil { + return nil, err + } + } + } + } + return validScripts, nil +} + +func exists(url string) (bool, error) { + resp, err := http.Get(url) + if err != nil { + return false, errors.Wrap(err, "failed to perform http GET") + } + + if resp.StatusCode == http.StatusOK { + return true, nil + } else if resp.StatusCode == http.StatusNotFound { + return false, nil + } else { + return false, errors.New(fmt.Sprintf("an error ocurred while checking repository: %s", resp.Status)) + } +} diff --git a/scriptmanager/list_test.go b/scriptmanager/list_test.go new file mode 100644 index 0000000..344e81e --- /dev/null +++ b/scriptmanager/list_test.go @@ -0,0 +1,273 @@ +package scriptmanager_test + +import ( + "net/http" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/ghttp" + + . "github.com/JulzDiverse/resc/scriptmanager" +) + +var _ = Describe("List", func() { + + var ( + scriptManager *ScriptManager + fakeServer *ghttp.Server + url, user, repo string + ) + + BeforeEach(func() { + fakeServer = ghttp.NewServer() + url = fakeServer.URL() + user = "zeus" + repo = "pandora" + }) + + JustBeforeEach(func() { + scriptManager = New(url, user, repo) + }) + + Context("listing available scripts in a repository", func() { + Context("When all directories are script directories", func() { + + BeforeEach(func() { + fakeServer.AppendHandlers( + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents", + ), + ghttp.RespondWith( + http.StatusOK, + `[{ + "name": "script-one", + "type": "dir" + }, + { + "name": "script-two", + "type": "dir" + }, + { + "name": "script-three", + "type": "dir" + }]`, + ), + ), + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents/script-one/.resc", + ), + ghttp.RespondWith( + http.StatusOK, + "{}", + ), + ), + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents/script-two/.resc", + ), + ghttp.RespondWith( + http.StatusOK, + "{}", + ), + ), + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents/script-three/.resc", + ), + ghttp.RespondWith( + http.StatusOK, + "{}", + ), + ), + ) + + }) + + It("should list all available repositories", func() { + scriptList, err := scriptManager.List() + Expect(err).ToNot(HaveOccurred()) + Expect(scriptList).To(HaveLen(3)) + Expect(scriptList).To(Equal([]string{ + "script-one", + "script-two", + "script-three", + })) + }) + }) + + Context("When some directories are no script directories", func() { + + BeforeEach(func() { + fakeServer.AppendHandlers( + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents", + ), + ghttp.RespondWith( + http.StatusOK, + `[{ + "name": "script-one", + "type": "dir" + }, + { + "name": "no-script", + "type": "dir" + }, + { + "name": "script-three", + "type": "dir" + }]`, + ), + ), + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents/script-one/.resc", + ), + ghttp.RespondWith( + http.StatusOK, + "{}", + ), + ), + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents/no-script/.resc", + ), + ghttp.RespondWith( + http.StatusNotFound, + "{}", + ), + ), + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents/script-three/.resc", + ), + ghttp.RespondWith( + http.StatusOK, + "{}", + ), + ), + ) + }) + + It("should list all available repositories", func() { + scriptList, err := scriptManager.List() + Expect(err).ToNot(HaveOccurred()) + Expect(scriptList).To(HaveLen(2)) + Expect(scriptList).To(Equal([]string{ + "script-one", + "script-three", + })) + }) + }) + + Context("When repository contains files", func() { + BeforeEach(func() { + fakeServer.AppendHandlers( + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents", + ), + ghttp.RespondWith( + http.StatusOK, + `[{ + "name": "script-one", + "type": "dir" + }, + { + "name": "no-script", + "type": "file" + }, + { + "name": "script-three", + "type": "dir" + }]`, + ), + ), + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents/script-one/.resc", + ), + ghttp.RespondWith( + http.StatusOK, + "{}", + ), + ), + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents/script-three/.resc", + ), + ghttp.RespondWith( + http.StatusOK, + "{}", + ), + ), + ) + + }) + + It("should list all available repositories", func() { + scriptList, err := scriptManager.List() + Expect(err).ToNot(HaveOccurred()) + Expect(scriptList).To(HaveLen(2)) + Expect(scriptList).To(Equal([]string{ + "script-one", + "script-three", + })) + }) + }) + + Context("When repository contains no valid script directories", func() { + BeforeEach(func() { + fakeServer.AppendHandlers( + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents", + ), + ghttp.RespondWith( + http.StatusOK, + `[{ + "name": "no-script-dir", + "type": "dir" + }, + { + "name": "no-script", + "type": "file" + }]`, + ), + ), + ghttp.CombineHandlers( + ghttp.VerifyRequest( + "GET", + "/repos/zeus/pandora/contents/no-script-dir/.resc", + ), + ghttp.RespondWith( + http.StatusNotFound, + "{}", + ), + ), + ) + }) + + It("should list all available repositories", func() { + scriptList, err := scriptManager.List() + Expect(err).ToNot(HaveOccurred()) + Expect(scriptList).To(HaveLen(0)) + Expect(scriptList).To(Equal([]string{})) + }) + }) + }) +})