[Feature] Support instance  list command (#10)

* add instance command

* add instance command

* fix license

* fix

* fix analyzers took error

* list command

* list command

* list command

* add instance command

* Add command manual and documentations (#8)

* Add command manual and ˆdocumentation

* Rename GitHub Action and display build status and coverage badge

* Update documentation to add developer guide and polishing
diff --git a/README.md b/README.md
index aacbdf8..d8f3678 100644
--- a/README.md
+++ b/README.md
@@ -63,6 +63,8 @@
 - [`swctl`](#swctl-top-level-command)
 - [`service`](#service-second-level-command) (second level command)
   - [`list`, `ls`](#service-list---startstart-time---endend-time)
+- [`instance`](#instance-second-level-command) (second level command)
+  - [`list`, `ls`](#instance-list---service-idservice-id---service-nameservice-name---startstart-time---endend-time)
 
 ### `swctl` top-level command
 `swctl` is the top-level command, which has some options that will take effects globally.
@@ -86,6 +88,20 @@
 | `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
 | `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
 
+### `instance` second-level command
+`instance` second-level command is an entry for all operations related to instances,
+and it also has some options and third-level commands.
+
+#### `instance list [--service-id=<service id>] [--service-name=<service name>] [--start=<start time>] [--end=<end time>]`
+`instance list` lists all the instances in the time range of \[`start`, `end`\] and given --service-id or --service-name.
+
+| option | description | default |
+| :--- | :--- | :--- |
+| `--service-id` | Query service id (priority over --service-name)|  |
+| `--service-name` | Query service name |  |
+| `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
+| `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
+
 # Developer guide
 
 ## Compiling and building
@@ -118,4 +134,4 @@
 ```
 
 # License
-[Apache 2.0 License.](/LICENSE)
+[Apache 2.0 License.](/LICENSE)
\ No newline at end of file
diff --git a/commands/flags/instance.go b/commands/flags/instance.go
new file mode 100644
index 0000000..70839b1
--- /dev/null
+++ b/commands/flags/instance.go
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package flags
+
+import "github.com/urfave/cli"
+
+var InstanceServiceIdFlags = append(DurationFlags,
+	cli.StringFlag{
+		Name:  "service-id",
+		Usage: "query service `ID` (priority over \"--service-name\")",
+	},
+	cli.StringFlag{
+		Name:  "service-name",
+		Usage: "query service `Name`",
+	},
+)
diff --git a/commands/instance/instance.go b/commands/instance/instance.go
new file mode 100644
index 0000000..12dae3c
--- /dev/null
+++ b/commands/instance/instance.go
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package instance
+
+import (
+	"github.com/urfave/cli"
+)
+
+var Command = cli.Command{
+	Name:      "instance",
+	ShortName: "i",
+	Usage:     "Instance related sub-command",
+	Subcommands: cli.Commands{
+		ListCommand,
+	},
+}
diff --git a/commands/instance/list.go b/commands/instance/list.go
new file mode 100644
index 0000000..7b56c29
--- /dev/null
+++ b/commands/instance/list.go
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package instance
+
+import (
+	"github.com/apache/skywalking-cli/commands/flags"
+	"github.com/apache/skywalking-cli/commands/interceptor"
+	"github.com/apache/skywalking-cli/commands/model"
+	"github.com/apache/skywalking-cli/display"
+	"github.com/apache/skywalking-cli/graphql/client"
+	"github.com/apache/skywalking-cli/graphql/schema"
+	"github.com/apache/skywalking-cli/logger"
+	"github.com/urfave/cli"
+)
+
+var ListCommand = cli.Command{
+	Name:      "list",
+	ShortName: "ls",
+	Usage:     "List all available instance by given --service-id or --service-name parameter",
+	Flags:     flags.InstanceServiceIdFlags,
+	Before: interceptor.BeforeChain([]cli.BeforeFunc{
+		interceptor.DurationInterceptor,
+	}),
+	Action: func(ctx *cli.Context) error {
+		serviceId := ctx.String("service-id")
+		serviceName := ctx.String("service-name")
+
+		if serviceId == "" && serviceName == "" {
+			logger.Log.Fatalf("flags \"service-id, service-name\" must set one")
+		}
+
+		if serviceId == "" && serviceName != "" {
+			service, err := client.SearchService(ctx, serviceName)
+			if err != nil {
+				logger.Log.Fatalln(err)
+			}
+			serviceId = service.ID
+		}
+
+		end := ctx.String("end")
+		start := ctx.String("start")
+		step := ctx.Generic("step")
+
+		instances := client.Instances(ctx, serviceId, schema.Duration{
+			Start: start,
+			End:   end,
+			Step:  step.(*model.StepEnumValue).Selected,
+		})
+
+		return display.Display(ctx, instances)
+	},
+}
diff --git a/graphql/client/client.go b/graphql/client/client.go
index 2bbb412..d72bc06 100644
--- a/graphql/client/client.go
+++ b/graphql/client/client.go
@@ -20,18 +20,30 @@
 
 import (
 	"context"
+	"fmt"
 	"github.com/apache/skywalking-cli/graphql/schema"
 	"github.com/apache/skywalking-cli/logger"
 	"github.com/machinebox/graphql"
 	"github.com/urfave/cli"
 )
 
-func Services(cliCtx *cli.Context, duration schema.Duration) []schema.Service {
-	client := graphql.NewClient(cliCtx.GlobalString("base-url"))
+func newClient(cliCtx *cli.Context) (client *graphql.Client) {
+	client = graphql.NewClient(cliCtx.GlobalString("base-url"))
 	client.Log = func(msg string) {
 		logger.Log.Debugln(msg)
 	}
+	return
+}
 
+func executeQuery(cliCtx *cli.Context, request *graphql.Request, response interface{}) {
+	client := newClient(cliCtx)
+	ctx := context.Background()
+	if err := client.Run(ctx, request, response); err != nil {
+		logger.Log.Fatalln(err)
+	}
+}
+
+func Services(cliCtx *cli.Context, duration schema.Duration) []schema.Service {
 	var response map[string][]schema.Service
 	request := graphql.NewRequest(`
 		query ($duration: Duration!) {
@@ -42,11 +54,48 @@
 	`)
 	request.Var("duration", duration)
 
-	ctx := context.Background()
-	if err := client.Run(ctx, request, &response); err != nil {
-		logger.Log.Fatalln(err)
-		panic(err)
-	}
-
+	executeQuery(cliCtx, request, &response)
 	return response["services"]
 }
+
+func Instances(cliCtx *cli.Context, serviceId string, duration schema.Duration) []schema.ServiceInstance {
+	var response map[string][]schema.ServiceInstance
+	request := graphql.NewRequest(`
+		query ($serviceId: ID!, $duration: Duration!) {
+    		instances: getServiceInstances(duration: $duration, serviceId: $serviceId) {
+      			id
+      			name
+      			language
+				instanceUUID
+      			attributes {
+        			name
+        			value
+      			}
+			}
+		}
+	`)
+	request.Var("serviceId", serviceId)
+	request.Var("duration", duration)
+
+	executeQuery(cliCtx, request, &response)
+	return response["instances"]
+}
+
+func SearchService(cliCtx *cli.Context, serviceCode string) (service schema.Service, err error) {
+	var response map[string]schema.Service
+	request := graphql.NewRequest(`
+		query searchService($serviceCode: String!) {
+    		service: searchService(serviceCode: $serviceCode) {
+      				id name
+			}
+		}
+	`)
+	request.Var("serviceCode", serviceCode)
+
+	executeQuery(cliCtx, request, &response)
+	service = response["service"]
+	if service.ID == "" {
+		return service, fmt.Errorf("no such service [%s]", serviceCode)
+	}
+	return service, nil
+}
diff --git a/swctl/main.go b/swctl/main.go
index 0667211..e0ec990 100644
--- a/swctl/main.go
+++ b/swctl/main.go
@@ -19,6 +19,7 @@
 package main
 
 import (
+	"github.com/apache/skywalking-cli/commands/instance"
 	"github.com/apache/skywalking-cli/commands/interceptor"
 	"github.com/apache/skywalking-cli/commands/service"
 	"github.com/apache/skywalking-cli/logger"
@@ -60,12 +61,14 @@
 		altsrc.NewStringFlag(cli.StringFlag{
 			Name:     "display",
 			Required: false,
-			Usage:    "display `style` of the result, supported styles are: json, yaml",
+			Usage:    "display `style` of the result, supported styles are: json, yaml, table",
+			Value:    "json",
 		}),
 	}
 
 	app.Commands = []cli.Command{
 		service.Command,
+		instance.Command,
 	}
 
 	app.Before = interceptor.BeforeChain([]cli.BeforeFunc{