Add the sub-command `service` of command `dependency` (#113)

diff --git a/README.md b/README.md
index c3d6c64..c6cef7e 100644
--- a/README.md
+++ b/README.md
@@ -564,6 +564,22 @@
 
 ### `dependency`
 
+#### `service`
+
+<details>
+
+<summary>dependency service <service-id> [--start=start-time] [--end=end-time]</summary>
+
+`dependency service` shows all the dependencies of given `[service-id]` in the time range of `[start, end]`.
+
+| argument | description | default |
+| :--- | :--- | :--- |
+| `service-id` | The service id whose dependencies are to displayed. |  |
+| `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
+| `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
+
+</details>
+
 #### `endpoint`
 
 <details>
diff --git a/assets/assets.gen.go b/assets/assets.gen.go
index ee5279e..de5df31 100644
--- a/assets/assets.gen.go
+++ b/assets/assets.gen.go
@@ -20,6 +20,7 @@
 // cr/oap.yaml (942B)
 // cr/ui.yaml (935B)
 // graphqls/dependency/EndpointDependency.graphql (1.207kB)
+// graphqls/dependency/ServiceTopology.graphql (1.137kB)
 // graphqls/event/events.graphql (1.256kB)
 // graphqls/healthcheck/healthcheck.graphql (870B)
 // graphqls/logs/Logs.graphql (1.258kB)
@@ -221,6 +222,56 @@
 	return a, nil
 }
 
+var _graphqlsDependencyServicetopologyGraphql = []byte(`# Licensed to 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. Apache Software Foundation (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.
+
+query ($serviceId: ID!, $duration: Duration!) {
+    result: getServiceTopology(duration: $duration, serviceId: $serviceId) {
+        nodes {
+            id
+            name
+            type
+            isReal
+        }
+        calls {
+            id
+            source
+            detectPoints
+            target
+        }
+    }
+}
+`)
+
+func graphqlsDependencyServicetopologyGraphqlBytes() ([]byte, error) {
+	return _graphqlsDependencyServicetopologyGraphql, nil
+}
+
+func graphqlsDependencyServicetopologyGraphql() (*asset, error) {
+	bytes, err := graphqlsDependencyServicetopologyGraphqlBytes()
+	if err != nil {
+		return nil, err
+	}
+
+	info := bindataFileInfo{name: "graphqls/dependency/ServiceTopology.graphql", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
+	a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb9, 0xb4, 0x57, 0x4c, 0xe6, 0x57, 0x1c, 0x34, 0xbd, 0xed, 0x73, 0x68, 0x63, 0x5, 0xab, 0x62, 0x44, 0x9, 0xc3, 0x12, 0x9, 0x85, 0x4b, 0xad, 0xb5, 0xb0, 0xa, 0xdb, 0xa8, 0x48, 0x22, 0x54}}
+	return a, nil
+}
+
 var _graphqlsEventEventsGraphql = []byte(`# Licensed to Apache Software Foundation (ASF) under one or more contributor
 # license agreements. See the NOTICE file distributed with
 # this work for additional information regarding copyright
@@ -1377,6 +1428,7 @@
 	"cr/oap.yaml": crOapYaml,
 	"cr/ui.yaml":  crUiYaml,
 	"graphqls/dependency/EndpointDependency.graphql": graphqlsDependencyEndpointdependencyGraphql,
+	"graphqls/dependency/ServiceTopology.graphql":    graphqlsDependencyServicetopologyGraphql,
 	"graphqls/event/events.graphql":                  graphqlsEventEventsGraphql,
 	"graphqls/healthcheck/healthcheck.graphql":       graphqlsHealthcheckHealthcheckGraphql,
 	"graphqls/logs/Logs.graphql":                     graphqlsLogsLogsGraphql,
@@ -1452,6 +1504,7 @@
 	"graphqls": &bintree{nil, map[string]*bintree{
 		"dependency": &bintree{nil, map[string]*bintree{
 			"EndpointDependency.graphql": &bintree{graphqlsDependencyEndpointdependencyGraphql, map[string]*bintree{}},
+			"ServiceTopology.graphql":    &bintree{graphqlsDependencyServicetopologyGraphql, map[string]*bintree{}},
 		}},
 		"event": &bintree{nil, map[string]*bintree{
 			"events.graphql": &bintree{graphqlsEventEventsGraphql, map[string]*bintree{}},
diff --git a/assets/graphqls/dependency/ServiceTopology.graphql b/assets/graphqls/dependency/ServiceTopology.graphql
new file mode 100644
index 0000000..bc08f0e
--- /dev/null
+++ b/assets/graphqls/dependency/ServiceTopology.graphql
@@ -0,0 +1,33 @@
+# Licensed to 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. Apache Software Foundation (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.
+
+query ($serviceId: ID!, $duration: Duration!) {
+    result: getServiceTopology(duration: $duration, serviceId: $serviceId) {
+        nodes {
+            id
+            name
+            type
+            isReal
+        }
+        calls {
+            id
+            source
+            detectPoints
+            target
+        }
+    }
+}
diff --git a/internal/commands/dependency/dependency.go b/internal/commands/dependency/dependency.go
index c060165..b719293 100644
--- a/internal/commands/dependency/dependency.go
+++ b/internal/commands/dependency/dependency.go
@@ -27,5 +27,6 @@
 	Usage:     "Dependency related subcommand",
 	Subcommands: cli.Commands{
 		EndpointCommand,
+		ServiceCommand,
 	},
 }
diff --git a/internal/commands/dependency/service.go b/internal/commands/dependency/service.go
new file mode 100644
index 0000000..4a0abb3
--- /dev/null
+++ b/internal/commands/dependency/service.go
@@ -0,0 +1,74 @@
+// Licensed to 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. Apache Software Foundation (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 dependency
+
+import (
+	"fmt"
+
+	"github.com/urfave/cli"
+
+	"github.com/apache/skywalking-cli/internal/commands/interceptor"
+	"github.com/apache/skywalking-cli/internal/flags"
+	"github.com/apache/skywalking-cli/internal/logger"
+	"github.com/apache/skywalking-cli/internal/model"
+
+	"github.com/apache/skywalking-cli/pkg/display"
+	"github.com/apache/skywalking-cli/pkg/display/displayable"
+
+	"github.com/apache/skywalking-cli/pkg/graphql/dependency"
+
+	api "skywalking.apache.org/repo/goapi/query"
+)
+
+var ServiceCommand = cli.Command{
+	Name:      "service",
+	ShortName: "svc",
+	Usage:     "Query the dependencies of given service",
+	ArgsUsage: "<serviceId>",
+	Flags: flags.Flags(
+		flags.DurationFlags,
+	),
+	Before: interceptor.BeforeChain([]cli.BeforeFunc{
+		interceptor.TimezoneInterceptor,
+		interceptor.DurationInterceptor,
+	}),
+
+	Action: func(ctx *cli.Context) error {
+		if ctx.NArg() == 0 {
+			return fmt.Errorf("command service requires serviceId as argument")
+		}
+
+		end := ctx.String("end")
+		start := ctx.String("start")
+		step := ctx.Generic("step")
+
+		duration := api.Duration{
+			Start: start,
+			End:   end,
+			Step:  step.(*model.StepEnumValue).Selected,
+		}
+
+		dependency, err := dependency.ServiceTopology(ctx, ctx.Args().First(), duration)
+
+		if err != nil {
+			logger.Log.Fatalln(err)
+		}
+
+		return display.Display(ctx, &displayable.Displayable{Data: dependency})
+	},
+}
diff --git a/pkg/graphql/dependency/dependency.go b/pkg/graphql/dependency/dependency.go
index b84c8d4..8b28ea6 100644
--- a/pkg/graphql/dependency/dependency.go
+++ b/pkg/graphql/dependency/dependency.go
@@ -38,3 +38,15 @@
 
 	return response["result"], err
 }
+
+func ServiceTopology(ctx *cli.Context, serviceID string, duration api.Duration) (api.Topology, error) {
+	var response map[string]api.Topology
+
+	request := graphql.NewRequest(assets.Read("graphqls/dependency/ServiceTopology.graphql"))
+	request.Var("serviceId", serviceID)
+	request.Var("duration", duration)
+
+	err := client.ExecuteQuery(ctx, request, &response)
+
+	return response["result"], err
+}
diff --git a/scripts/test_commands.sh b/scripts/test_commands.sh
index e72d3d1..59f41f0 100755
--- a/scripts/test_commands.sh
+++ b/scripts/test_commands.sh
@@ -66,3 +66,8 @@
 
 # Test `dashboard global`
 ${swctl} --display=json db g >/dev/null 2>&1
+
+# Test `dependency`
+${swctl} --display=json dependency service "test" > /dev/null 2>&1
+
+${swctl} --display=json dependency endpoint "test" > /dev/null 2>&1
\ No newline at end of file