Skip to content
This repository was archived by the owner on Apr 28, 2023. It is now read-only.

Commit 0418f4b

Browse files
authored
Merge pull request #3 from redbubble/skip-flag
Allow users to skip selected apps
2 parents 06a80d2 + cb37ee1 commit 0418f4b

File tree

5 files changed

+107
-42
lines changed

5 files changed

+107
-42
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ starts the named application in Development mode, with its dependencies in Depen
4444
`--mode`, `-m`
4545
: Specify the mode. Default: `development`
4646

47+
`--skip`, `-s`
48+
: Names of any apps you don't want to start. Can be specified multiple times.
49+
4750
`--verbose`, `-v`
4851
: Print some more information about what's happening.
4952

cmd/start.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
)
1616

1717
var mode string
18+
var skip []string
1819

1920
// startCmd represents the start command
2021
var startCmd = &cobra.Command{
@@ -40,9 +41,13 @@ var startCmd = &cobra.Command{
4041
bail(err)
4142

4243
apps := make([]domain.App, 0, 1)
43-
apps, err = resolver.Add(apps, app)
44+
apps, err = resolver.Add(apps, app, skip)
4445
bail(err)
4546

47+
if len(apps) == 0 {
48+
bail(fmt.Errorf("There are no apps to start. Consider checking %s/devon.conf.yaml to figure out what's going on.", app.SourceDir))
49+
}
50+
4651
if viper.IsSet("verbose") {
4752
fmt.Println("Devon will start these apps:")
4853

@@ -84,6 +89,7 @@ func init() {
8489
rootCmd.AddCommand(startCmd)
8590

8691
startCmd.PersistentFlags().StringVarP(&mode, "mode", "m", "development", "The mode to run in, e.g. 'development' or 'dependency'. Default: development")
92+
startCmd.PersistentFlags().StringSliceVarP(&skip, "skip", "s", []string{}, "Names of any apps you don't want to start. Can be specified multiple times.")
8793
}
8894

8995
func getAppName(args []string) (string, error) {

example.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ modes:
3636
start-command: ["make", "local"]
3737
# This app takes the default list and extends it.
3838
dependencies:
39-
<<: *default_dependencies
40-
extra-app: dependency
41-
# We can override existing settings, too:
42-
my-app: development
39+
- name: extra-app
40+
mode: dependency
41+
- name: my-app
42+
mode: development

resolver/resolver.go

Lines changed: 67 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import (
77
"github.com/redbubble/devon/domain"
88
)
99

10-
func Add(apps []domain.App, app domain.App) ([]domain.App, error) {
11-
startingApps, err := add(apps, app, make([]string, 0, len(apps)))
10+
func Add(apps []domain.App, app domain.App, skip []string) ([]domain.App, error) {
11+
startingApps, err := add(apps, app, skip, make([]string, 0, len(apps)))
1212

1313
if err != nil {
1414
return nil, err
@@ -17,42 +17,36 @@ func Add(apps []domain.App, app domain.App) ([]domain.App, error) {
1717
return startingApps, nil
1818
}
1919

20-
func add(apps []domain.App, app domain.App, depChain []string) ([]domain.App, error) {
20+
func add(apps []domain.App, app domain.App, skip []string, depChain []string) ([]domain.App, error) {
2121
var startingApps []domain.App
2222

23+
// Has the user said they want to skip this app?
24+
// If so, let's return early.
25+
if checkSkip(app.Name, skip) {
26+
return apps, nil
27+
}
28+
2329
// Does the dependency chain already include this app?
2430
// If so, we've got a circular dependency, so return an error.
25-
for _, depName := range depChain {
26-
if depName == app.Name {
27-
depChainStr := strings.Join(append(depChain, app.Name), "->")
28-
err := fmt.Errorf("Circular dependency when resolving dependencies: %s", depChainStr)
29-
return []domain.App{}, err
30-
}
31+
if checkCircularDependency(app.Name, depChain) {
32+
depChainStr := strings.Join(append(depChain, app.Name), "->")
33+
err := fmt.Errorf("Circular dependency when resolving dependencies: %s", depChainStr)
34+
35+
return []domain.App{}, err
3136
}
3237

33-
// Does the list of apps already include this app?
34-
// If so, we need to compare the modes.
35-
// If the modes are the same, then this dependency is already satisfied.
36-
// There's nothing to do, so we can return now.
37-
// If the modes are different, we have conflicting dependencies.
38-
// Return an error.
39-
for j := 0; j < len(apps); j++ {
40-
if apps[j].Name == app.Name {
41-
if apps[j].Mode.Name == app.Mode.Name {
42-
// The app we want, in the mode we want, is
43-
// already in the list. Therefore, there's
44-
// nothing to do.
45-
return apps, nil
46-
} else {
47-
err := fmt.Errorf("Dependency conflict when resolving dependencies: %s in '%s' mode conflicts with %s in '%s' mode.",
48-
app.Name,
49-
app.Mode.Name,
50-
apps[j].Name,
51-
apps[j].Mode.Name)
52-
53-
return []domain.App{}, err
54-
}
55-
}
38+
if conflict, conflictingApp := checkDependencyConflict(app, apps); conflict {
39+
err := fmt.Errorf("Dependency conflict when resolving dependencies: %s in '%s' mode conflicts with %s in '%s' mode.",
40+
app.Name,
41+
app.Mode.Name,
42+
conflictingApp.Name,
43+
conflictingApp.Mode.Name)
44+
45+
return []domain.App{}, err
46+
}
47+
48+
if checkAlreadyIncluded(app, apps) {
49+
return apps, nil
5650
}
5751

5852
// All our validation checks have passed, so add the app to the list.
@@ -67,7 +61,7 @@ func add(apps []domain.App, app domain.App, depChain []string) ([]domain.App, er
6761
continue
6862
}
6963

70-
startingApps, err = add(startingApps, dep, append(depChain, app.Name))
64+
startingApps, err = add(startingApps, dep, skip, append(depChain, app.Name))
7165

7266
if err != nil {
7367
return []domain.App{}, err
@@ -76,3 +70,43 @@ func add(apps []domain.App, app domain.App, depChain []string) ([]domain.App, er
7670

7771
return startingApps, nil
7872
}
73+
74+
func checkSkip(appName string, skip []string) bool {
75+
for _, s := range skip {
76+
if appName == s {
77+
return true
78+
}
79+
}
80+
81+
return false
82+
}
83+
84+
func checkCircularDependency(appName string, depChain []string) bool {
85+
for _, depName := range depChain {
86+
if depName == appName {
87+
return true
88+
}
89+
}
90+
91+
return false
92+
}
93+
94+
func checkDependencyConflict(app domain.App, apps []domain.App) (bool, domain.App) {
95+
for _, a := range apps {
96+
if a.Name == app.Name && a.Mode.Name != app.Mode.Name {
97+
return true, a
98+
}
99+
}
100+
101+
return false, domain.App{}
102+
}
103+
104+
func checkAlreadyIncluded(app domain.App, apps []domain.App) bool {
105+
for _, a := range apps {
106+
if a.Name == app.Name && a.Mode.Name == app.Mode.Name {
107+
return true
108+
}
109+
}
110+
111+
return false
112+
}

resolver/resolver_test.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func TestAdd(t *testing.T) {
2525
},
2626
}
2727

28-
actual, err := Add(apps, app)
28+
actual, err := Add(apps, app, []string{})
2929

3030
if err != nil {
3131
t.Errorf("Error: %v\n", err)
@@ -60,7 +60,7 @@ func TestAdd(t *testing.T) {
6060
},
6161
}
6262

63-
actual, err = Add(apps, appWithDependencies)
63+
actual, err = Add(apps, appWithDependencies, []string{})
6464

6565
expectedAppNames = []string{
6666
"testfenster",
@@ -94,7 +94,7 @@ func TestAdd(t *testing.T) {
9494
},
9595
}
9696

97-
_, expectedErr := Add(apps, appWithCircularDependency)
97+
_, expectedErr := Add(apps, appWithCircularDependency, []string{})
9898

9999
if expectedErr == nil {
100100
t.Errorf("Expected a circular dependency to result in an error, but it didn't.")
@@ -119,9 +119,31 @@ func TestAdd(t *testing.T) {
119119
},
120120
}
121121

122-
_, expectedErr = Add(apps, conflictingApp)
122+
_, expectedErr = Add(apps, conflictingApp, []string{})
123123

124124
if expectedErr == nil {
125125
t.Errorf("Expected a conflicting dependency (same name, different mode) to result in an error, but it didn't.")
126126
}
127+
128+
// Declines to add apps from the skip list
129+
skippedApp := domain.App{
130+
Name: "skipme",
131+
Mode: domain.Mode{
132+
Name: "dependency",
133+
},
134+
}
135+
136+
apps = []domain.App{}
137+
138+
skip := []string{"skipme"}
139+
140+
actualApps, err := Add(apps, skippedApp, skip)
141+
142+
if err != nil {
143+
t.Error(err)
144+
}
145+
146+
if len(actualApps) != 0 {
147+
t.Errorf("Expected an app appearing in the skip list to be skipped, but it wasn't.")
148+
}
127149
}

0 commit comments

Comments
 (0)