1package commands
2
3import (
4	"fmt"
5	"os"
6	"strconv"
7	"time"
8
9	"github.com/concourse/concourse/atc"
10	"github.com/concourse/concourse/fly/commands/internal/flaghelpers"
11	"github.com/concourse/concourse/fly/rc"
12	"github.com/concourse/concourse/fly/ui"
13	"github.com/fatih/color"
14)
15
16type CheckResourceCommand struct {
17	Resource flaghelpers.ResourceFlag `short:"r" long:"resource" required:"true" value-name:"PIPELINE/RESOURCE" description:"Name of a resource to check version for"`
18	Version  *atc.Version             `short:"f" long:"from"                     value-name:"VERSION"           description:"Version of the resource to check from, e.g. ref:abcd or path:thing-1.2.3.tgz"`
19	Async    bool                     `short:"a" long:"async"                    value-name:"ASYNC"             description:"Return the check without waiting for its result"`
20	Shallow  bool                     `long:"shallow"                          value-name:"SHALLOW"         description:"Check the resource itself only"`
21}
22
23func (command *CheckResourceCommand) Execute(args []string) error {
24	target, err := rc.LoadTarget(Fly.Target, Fly.Verbose)
25	if err != nil {
26		return err
27	}
28
29	err = target.Validate()
30	if err != nil {
31		return err
32	}
33
34	var version atc.Version
35	if command.Version != nil {
36		version = *command.Version
37	}
38
39	if !command.Shallow {
40		err = command.checkParent(target)
41		if err != nil {
42			return err
43		}
44	}
45
46	check, found, err := target.Team().CheckResource(command.Resource.PipelineName, command.Resource.ResourceName, version)
47	if err != nil {
48		return err
49	}
50
51	if !found {
52		return fmt.Errorf("pipeline '%s' or resource '%s' not found\n", command.Resource.PipelineName, command.Resource.ResourceName)
53	}
54
55	var checkID = strconv.Itoa(check.ID)
56
57	if !command.Async {
58		for check.Status == "started" {
59			time.Sleep(time.Second)
60
61			check, found, err = target.Client().Check(checkID)
62			if err != nil {
63				return err
64			}
65
66			if !found {
67				return fmt.Errorf("check '%s' not found\n", checkID)
68			}
69		}
70	}
71
72	table := ui.Table{
73		Headers: ui.TableRow{
74			{Contents: "id", Color: color.New(color.Bold)},
75			{Contents: "name", Color: color.New(color.Bold)},
76			{Contents: "status", Color: color.New(color.Bold)},
77			{Contents: "check_error", Color: color.New(color.Bold)},
78		},
79	}
80
81	table.Data = append(table.Data, []ui.TableCell{
82		{Contents: checkID},
83		{Contents: command.Resource.ResourceName},
84		{Contents: check.Status},
85		{Contents: check.CheckError},
86	})
87
88	if err = table.Render(os.Stdout, Fly.PrintTableHeaders); err != nil {
89		return err
90	}
91
92	if check.Status == "errored" {
93		os.Exit(1)
94	}
95
96	return nil
97}
98
99func (command *CheckResourceCommand) checkParent(target rc.Target) error {
100	resource, found, err := target.Team().Resource(command.Resource.PipelineName, command.Resource.ResourceName)
101	if err != nil {
102		return err
103	}
104
105	if !found {
106		return fmt.Errorf("resource '%s' not found\n", command.Resource.ResourceName)
107	}
108
109	resourceTypes, found, err := target.Team().VersionedResourceTypes(command.Resource.PipelineName)
110	if err != nil {
111		return err
112	}
113
114	if !found {
115		return fmt.Errorf("pipeline '%s' not found\n", command.Resource.PipelineName)
116	}
117
118	parentType, found := command.findParent(resource, resourceTypes)
119	if !found {
120		return nil
121	}
122
123	cmd := &CheckResourceTypeCommand{
124		ResourceType: flaghelpers.ResourceFlag{
125			ResourceName: parentType.Name,
126			PipelineName: command.Resource.PipelineName,
127		},
128	}
129
130	return cmd.Execute(nil)
131}
132
133func (command *CheckResourceCommand) findParent(resource atc.Resource, resourceTypes atc.VersionedResourceTypes) (atc.VersionedResourceType, bool) {
134	for _, t := range resourceTypes {
135		if t.Name != resource.Name && t.Name == resource.Type {
136			return t, true
137		}
138	}
139	return atc.VersionedResourceType{}, false
140}
141