Browse code

moved tools from cmd/ to tools/

Steve Kuznetsov authored on 2016/01/05 00:27:07
Showing 29 changed files
1 1
deleted file mode 100644
... ...
@@ -1,60 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"bytes"
5
-	"fmt"
6
-	"io/ioutil"
7
-	"os"
8
-	"path/filepath"
9
-
10
-	"github.com/openshift/origin/pkg/cmd/admin"
11
-	"github.com/openshift/origin/pkg/cmd/cli"
12
-	"github.com/openshift/origin/pkg/cmd/openshift"
13
-)
14
-
15
-func OutDir(path string) (string, error) {
16
-	outDir, err := filepath.Abs(path)
17
-	if err != nil {
18
-		return "", err
19
-	}
20
-
21
-	stat, err := os.Stat(outDir)
22
-	if err != nil {
23
-		return "", err
24
-	}
25
-
26
-	if !stat.IsDir() {
27
-		return "", fmt.Errorf("output directory %s is not a directory\n", outDir)
28
-	}
29
-	outDir = outDir + "/"
30
-	return outDir, nil
31
-}
32
-
33
-func main() {
34
-	// use os.Args instead of "flags" because "flags" will mess up the man pages!
35
-	path := "contrib/completions/bash/"
36
-	if len(os.Args) == 2 {
37
-		path = os.Args[1]
38
-	} else if len(os.Args) > 2 {
39
-		fmt.Fprintf(os.Stderr, "usage: %s [output directory]\n", os.Args[0])
40
-		os.Exit(1)
41
-	}
42
-
43
-	outDir, err := OutDir(path)
44
-	if err != nil {
45
-		fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err)
46
-		os.Exit(1)
47
-	}
48
-	outFile_openshift := outDir + "openshift"
49
-	openshift := openshift.NewCommandOpenShift("openshift")
50
-	openshift.GenBashCompletionFile(outFile_openshift)
51
-
52
-	outFile_osc := outDir + "oc"
53
-	out := os.Stdout
54
-	oc := cli.NewCommandCLI("oc", "openshift cli", &bytes.Buffer{}, out, ioutil.Discard)
55
-	oc.GenBashCompletionFile(outFile_osc)
56
-
57
-	outFile_osadm := outDir + "oadm"
58
-	oadm := admin.NewCommandAdmin("oadm", "openshift admin", ioutil.Discard)
59
-	oadm.GenBashCompletionFile(outFile_osadm)
60
-}
61 1
deleted file mode 100644
... ...
@@ -1,71 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"fmt"
5
-	"io"
6
-	"os"
7
-	"runtime"
8
-	"strings"
9
-
10
-	"k8s.io/kubernetes/pkg/api"
11
-	pkg_runtime "k8s.io/kubernetes/pkg/runtime"
12
-	"k8s.io/kubernetes/pkg/util/sets"
13
-
14
-	"github.com/golang/glog"
15
-	flag "github.com/spf13/pflag"
16
-
17
-	_ "github.com/openshift/origin/pkg/api"
18
-	_ "github.com/openshift/origin/pkg/api/v1"
19
-	_ "github.com/openshift/origin/pkg/api/v1beta3"
20
-)
21
-
22
-var (
23
-	functionDest = flag.StringP("funcDest", "f", "-", "Output for conversion functions; '-' means stdout")
24
-	version      = flag.StringP("version", "v", "v1beta3", "Version for conversion.")
25
-)
26
-
27
-func main() {
28
-	runtime.GOMAXPROCS(runtime.NumCPU())
29
-	flag.Parse()
30
-
31
-	var funcOut io.Writer
32
-	if *functionDest == "-" {
33
-		funcOut = os.Stdout
34
-	} else {
35
-		file, err := os.Create(*functionDest)
36
-		if err != nil {
37
-			glog.Fatalf("Couldn't open %v: %v", *functionDest, err)
38
-		}
39
-		defer file.Close()
40
-		funcOut = file
41
-	}
42
-
43
-	generator := pkg_runtime.NewConversionGenerator(api.Scheme.Raw(), "github.com/openshift/origin/pkg/api")
44
-	apiShort := generator.AddImport("k8s.io/kubernetes/pkg/api")
45
-	generator.AddImport("k8s.io/kubernetes/pkg/api/resource")
46
-	generator.AssumePrivateConversions()
47
-	// TODO(wojtek-t): Change the overwrites to a flag.
48
-	generator.OverwritePackage(*version, "")
49
-	for _, knownType := range api.Scheme.KnownTypes(*version) {
50
-		if !strings.Contains(knownType.PkgPath(), "openshift/origin") {
51
-			continue
52
-		}
53
-		if err := generator.GenerateConversionsForType(*version, knownType); err != nil {
54
-			glog.Errorf("error while generating conversion functions for %v: %v", knownType, err)
55
-		}
56
-	}
57
-
58
-	generator.RepackImports(sets.NewString("k8s.io/kubernetes/pkg/runtime"))
59
-	// the repack changes the name of the import
60
-	apiShort = generator.AddImport("k8s.io/kubernetes/pkg/api")
61
-
62
-	if err := generator.WriteImports(funcOut); err != nil {
63
-		glog.Fatalf("error while writing imports: %v", err)
64
-	}
65
-	if err := generator.WriteConversionFunctions(funcOut); err != nil {
66
-		glog.Fatalf("Error while writing conversion functions: %v", err)
67
-	}
68
-	if err := generator.RegisterConversionFunctions(funcOut, fmt.Sprintf("%s.Scheme", apiShort)); err != nil {
69
-		glog.Fatalf("Error while writing conversion functions: %v", err)
70
-	}
71
-}
72 1
deleted file mode 100644
... ...
@@ -1,94 +0,0 @@
1
-/*
2
-Copyright 2015 The Kubernetes Authors All rights reserved.
3
-
4
-Licensed under the Apache License, Version 2.0 (the "License");
5
-you may not use this file except in compliance with the License.
6
-You may obtain a copy of the License at
7
-
8
-    http://www.apache.org/licenses/LICENSE-2.0
9
-
10
-Unless required by applicable law or agreed to in writing, software
11
-distributed under the License is distributed on an "AS IS" BASIS,
12
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
-See the License for the specific language governing permissions and
14
-limitations under the License.
15
-*/
16
-
17
-package main
18
-
19
-import (
20
-	"fmt"
21
-	"io"
22
-	"os"
23
-	"runtime"
24
-	"strings"
25
-
26
-	"k8s.io/kubernetes/pkg/api"
27
-	pkg_runtime "k8s.io/kubernetes/pkg/runtime"
28
-	"k8s.io/kubernetes/pkg/util/sets"
29
-
30
-	"github.com/golang/glog"
31
-	flag "github.com/spf13/pflag"
32
-
33
-	_ "github.com/openshift/origin/pkg/api"
34
-	_ "github.com/openshift/origin/pkg/api/v1"
35
-	_ "github.com/openshift/origin/pkg/api/v1beta3"
36
-)
37
-
38
-var (
39
-	functionDest = flag.StringP("func-dest", "f", "-", "Output for deep copy functions; '-' means stdout")
40
-	version      = flag.StringP("version", "v", "v1beta3", "Version for deep copies.")
41
-	overwrites   = flag.StringP("overwrites", "o", "", "Comma-separated overwrites for package names")
42
-)
43
-
44
-func main() {
45
-	runtime.GOMAXPROCS(runtime.NumCPU())
46
-	flag.Parse()
47
-
48
-	var funcOut io.Writer
49
-	if *functionDest == "-" {
50
-		funcOut = os.Stdout
51
-	} else {
52
-		file, err := os.Create(*functionDest)
53
-		if err != nil {
54
-			glog.Fatalf("Couldn't open %v: %v", *functionDest, err)
55
-		}
56
-		defer file.Close()
57
-		funcOut = file
58
-	}
59
-
60
-	knownVersion := *version
61
-	if knownVersion == "api" {
62
-		knownVersion = api.Scheme.Raw().InternalVersion
63
-	}
64
-	generator := pkg_runtime.NewDeepCopyGenerator(api.Scheme.Raw(), "github.com/openshift/origin/pkg/api", sets.NewString("github.com/openshift/origin"))
65
-	apiShort := generator.AddImport("k8s.io/kubernetes/pkg/api")
66
-	generator.ReplaceType("k8s.io/kubernetes/pkg/util/sets", "empty", struct{}{})
67
-
68
-	for _, overwrite := range strings.Split(*overwrites, ",") {
69
-		vals := strings.Split(overwrite, "=")
70
-		generator.OverwritePackage(vals[0], vals[1])
71
-	}
72
-	for _, knownType := range api.Scheme.KnownTypes(knownVersion) {
73
-		if !strings.Contains(knownType.PkgPath(), "openshift/origin") {
74
-			continue
75
-		}
76
-		if err := generator.AddType(knownType); err != nil {
77
-			glog.Errorf("error while generating deep copy functions for %v: %v", knownType, err)
78
-		}
79
-	}
80
-
81
-	generator.RepackImports()
82
-	// the repack changes the name of the import
83
-	apiShort = generator.AddImport("k8s.io/kubernetes/pkg/api")
84
-
85
-	if err := generator.WriteImports(funcOut); err != nil {
86
-		glog.Fatalf("error while writing imports: %v", err)
87
-	}
88
-	if err := generator.WriteDeepCopyFunctions(funcOut); err != nil {
89
-		glog.Fatalf("error while writing deep copy functions: %v", err)
90
-	}
91
-	if err := generator.RegisterDeepCopyFunctions(funcOut, fmt.Sprintf("%s.Scheme", apiShort)); err != nil {
92
-		glog.Fatalf("error while registering deep copy functions: %v", err)
93
-	}
94
-}
95 1
deleted file mode 100644
... ...
@@ -1,56 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"bytes"
5
-	"fmt"
6
-	"io/ioutil"
7
-	"os"
8
-	"path/filepath"
9
-
10
-	"github.com/openshift/origin/pkg/cmd/admin"
11
-	"github.com/openshift/origin/pkg/cmd/cli"
12
-	"github.com/openshift/origin/pkg/cmd/util/gendocs"
13
-)
14
-
15
-func OutDir(path string) (string, error) {
16
-	outDir, err := filepath.Abs(path)
17
-	if err != nil {
18
-		return "", err
19
-	}
20
-
21
-	stat, err := os.Stat(outDir)
22
-	if err != nil {
23
-		return "", err
24
-	}
25
-
26
-	if !stat.IsDir() {
27
-		return "", fmt.Errorf("output directory %s is not a directory\n", outDir)
28
-	}
29
-	outDir = outDir + "/"
30
-	return outDir, nil
31
-}
32
-
33
-func main() {
34
-	path := "docs/generated/"
35
-	if len(os.Args) == 2 {
36
-		path = os.Args[1]
37
-	} else if len(os.Args) > 2 {
38
-		fmt.Fprintf(os.Stderr, "usage: %s [output directory]\n", os.Args[0])
39
-		os.Exit(1)
40
-	}
41
-
42
-	outDir, err := OutDir(path)
43
-	if err != nil {
44
-		fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err)
45
-		os.Exit(1)
46
-	}
47
-
48
-	outFile := outDir + "oc_by_example_content.adoc"
49
-	out := os.Stdout
50
-	cmd := cli.NewCommandCLI("oc", "oc", &bytes.Buffer{}, out, ioutil.Discard)
51
-	gendocs.GenDocs(cmd, outFile)
52
-
53
-	outFile = outDir + "oadm_by_example_content.adoc"
54
-	cmd = admin.NewCommandAdmin("oadm", "oadm", ioutil.Discard)
55
-	gendocs.GenDocs(cmd, outFile)
56
-}
57 1
deleted file mode 100644
... ...
@@ -1,46 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"flag"
5
-	"fmt"
6
-	"os"
7
-	"strings"
8
-
9
-	"github.com/openshift/origin/cmd/rebasehelpers/util"
10
-)
11
-
12
-func main() {
13
-	var start, end string
14
-	flag.StringVar(&start, "start", "master", "The start of the revision range for analysis")
15
-	flag.StringVar(&end, "end", "HEAD", "The end of the revision range for analysis")
16
-	flag.Parse()
17
-
18
-	commits, err := util.CommitsBetween(start, end)
19
-	if err != nil {
20
-		os.Stderr.WriteString(fmt.Sprintf("ERROR: couldn't find commits from %s..%s: %v\n", start, end, err))
21
-		os.Exit(1)
22
-	}
23
-
24
-	// TODO: Filter out bump commits for now until we decide how to deal with
25
-	// them correctly.
26
-	nonbumpCommits := []util.Commit{}
27
-	for _, commit := range commits {
28
-		if commit.DeclaresUpstreamChange() &&
29
-			!strings.HasPrefix(commit.Summary, "bump(") {
30
-			nonbumpCommits = append(nonbumpCommits, commit)
31
-		}
32
-	}
33
-
34
-	errs := []string{}
35
-	for _, validate := range AllValidators {
36
-		err := validate(nonbumpCommits)
37
-		if err != nil {
38
-			errs = append(errs, err.Error())
39
-		}
40
-	}
41
-
42
-	if len(errs) > 0 {
43
-		os.Stderr.WriteString(strings.Join(errs, "\n\n"))
44
-		os.Exit(2)
45
-	}
46
-}
47 1
deleted file mode 100644
... ...
@@ -1,185 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"bytes"
5
-	"fmt"
6
-	"regexp"
7
-	"strings"
8
-	"text/template"
9
-
10
-	"github.com/openshift/origin/cmd/rebasehelpers/util"
11
-)
12
-
13
-var CommitSummaryErrorTemplate = `
14
-The following UPSTREAM commits have invalid summaries:
15
-
16
-{{ range .Commits }}  [{{ .Sha }}] {{ .Summary }}
17
-{{ end }}
18
-UPSTREAM commit summaries should look like:
19
-
20
-  UPSTREAM: [non-kube-repo/name: ]<PR number|carry|drop>: description
21
-
22
-UPSTREAM commits which revert previous UPSTREAM commits should look like:
23
-
24
-  UPSTREAM: revert: <sha>: <normal upstream format>
25
-
26
-UPSTREAM commits are validated against the following regular expression:
27
-
28
-  {{ .Pattern }}
29
-
30
-Examples of valid summaries:
31
-
32
-  UPSTREAM: 12345: A kube fix
33
-  UPSTREAM: coreos/etcd: 12345: An etcd fix
34
-  UPSTREAM: <carry>: A carried kube change
35
-  UPSTREAM: <drop>: A dropped kube change
36
-  UPSTREAM: revert: abcd123: coreos/etcd: 12345: An etcd fix
37
-  UPSTREAM: k8s.io/heapster: 12345: A heapster fix
38
-
39
-`
40
-
41
-var AllValidators = []func([]util.Commit) error{
42
-	ValidateUpstreamCommitSummaries,
43
-	ValidateUpstreamCommitsWithoutGodepsChanges,
44
-	ValidateUpstreamCommitModifiesSingleGodepsRepo,
45
-	ValidateUpstreamCommitModifiesOnlyGodeps,
46
-	ValidateUpstreamCommitModifiesOnlyDeclaredGodepRepo,
47
-}
48
-
49
-// ValidateUpstreamCommitsWithoutGodepsChanges returns an error if any
50
-// upstream commits have no Godeps changes.
51
-func ValidateUpstreamCommitsWithoutGodepsChanges(commits []util.Commit) error {
52
-	problemCommits := []util.Commit{}
53
-	for _, commit := range commits {
54
-		if commit.HasGodepsChanges() && !commit.DeclaresUpstreamChange() {
55
-			problemCommits = append(problemCommits, commit)
56
-		}
57
-	}
58
-	if len(problemCommits) > 0 {
59
-		label := "The following commits contain Godeps changes but aren't declared as UPSTREAM"
60
-		msg := renderGodepFilesError(label, problemCommits, RenderOnlyGodepsFiles)
61
-		return fmt.Errorf(msg)
62
-	}
63
-	return nil
64
-}
65
-
66
-// ValidateUpstreamCommitModifiesSingleGodepsRepo returns an error if any
67
-// upstream commits have changes that span more than one Godeps repo.
68
-func ValidateUpstreamCommitModifiesSingleGodepsRepo(commits []util.Commit) error {
69
-	problemCommits := []util.Commit{}
70
-	for _, commit := range commits {
71
-		godepsChanges, err := commit.GodepsReposChanged()
72
-		if err != nil {
73
-			return err
74
-		}
75
-		if len(godepsChanges) > 1 {
76
-			problemCommits = append(problemCommits, commit)
77
-		}
78
-	}
79
-	if len(problemCommits) > 0 {
80
-		label := "The following UPSTREAM commits modify more than one repo in their changelist"
81
-		msg := renderGodepFilesError(label, problemCommits, RenderOnlyGodepsFiles)
82
-		return fmt.Errorf(msg)
83
-	}
84
-	return nil
85
-}
86
-
87
-// ValidateUpstreamCommitSummaries ensures that any commits which declare to
88
-// be upstream match the regular expressions for UPSTREAM summaries.
89
-func ValidateUpstreamCommitSummaries(commits []util.Commit) error {
90
-	problemCommits := []util.Commit{}
91
-	for _, commit := range commits {
92
-		if commit.DeclaresUpstreamChange() && !commit.MatchesUpstreamSummaryPattern() {
93
-			problemCommits = append(problemCommits, commit)
94
-		}
95
-	}
96
-	if len(problemCommits) > 0 {
97
-		tmpl, _ := template.New("problems").Parse(CommitSummaryErrorTemplate)
98
-		data := struct {
99
-			Pattern *regexp.Regexp
100
-			Commits []util.Commit
101
-		}{
102
-			Pattern: util.UpstreamSummaryPattern,
103
-			Commits: problemCommits,
104
-		}
105
-		buffer := &bytes.Buffer{}
106
-		tmpl.Execute(buffer, data)
107
-		return fmt.Errorf(buffer.String())
108
-	}
109
-	return nil
110
-}
111
-
112
-// ValidateUpstreamCommitModifiesOnlyGodeps ensures that any Godeps commits
113
-// modify ONLY Godeps files.
114
-func ValidateUpstreamCommitModifiesOnlyGodeps(commits []util.Commit) error {
115
-	problemCommits := []util.Commit{}
116
-	for _, commit := range commits {
117
-		if commit.HasGodepsChanges() && commit.HasNonGodepsChanges() {
118
-			problemCommits = append(problemCommits, commit)
119
-		}
120
-	}
121
-	if len(problemCommits) > 0 {
122
-		label := "The following UPSTREAM commits modify files outside Godeps"
123
-		msg := renderGodepFilesError(label, problemCommits, RenderAllFiles)
124
-		return fmt.Errorf(msg)
125
-	}
126
-	return nil
127
-}
128
-
129
-// ValidateUpstreamCommitModifiesOnlyDeclaredGodepRepo ensures that an
130
-// upstream commit only modifies the Godep repo the summary declares.
131
-func ValidateUpstreamCommitModifiesOnlyDeclaredGodepRepo(commits []util.Commit) error {
132
-	problemCommits := []util.Commit{}
133
-	for _, commit := range commits {
134
-		if commit.DeclaresUpstreamChange() {
135
-			declaredRepo, err := commit.DeclaredUpstreamRepo()
136
-			if err != nil {
137
-				return err
138
-			}
139
-			reposChanged, err := commit.GodepsReposChanged()
140
-			if err != nil {
141
-				return err
142
-			}
143
-			for _, changedRepo := range reposChanged {
144
-				if !strings.Contains(changedRepo, declaredRepo) {
145
-					problemCommits = append(problemCommits, commit)
146
-				}
147
-			}
148
-		}
149
-	}
150
-	if len(problemCommits) > 0 {
151
-		label := "The following UPSTREAM commits modify Godeps repos other than the repo the commit declares"
152
-		msg := renderGodepFilesError(label, problemCommits, RenderAllFiles)
153
-		return fmt.Errorf(msg)
154
-	}
155
-	return nil
156
-}
157
-
158
-type CommitFilesRenderOption int
159
-
160
-const (
161
-	RenderNoFiles CommitFilesRenderOption = iota
162
-	RenderOnlyGodepsFiles
163
-	RenderOnlyNonGodepsFiles
164
-	RenderAllFiles
165
-)
166
-
167
-// renderGodepFilesError formats commits and their file lists into readable
168
-// output prefixed with label.
169
-func renderGodepFilesError(label string, commits []util.Commit, opt CommitFilesRenderOption) string {
170
-	msg := fmt.Sprintf("%s:\n\n", label)
171
-	for _, commit := range commits {
172
-		msg += fmt.Sprintf("[%s] %s\n", commit.Sha, commit.Summary)
173
-		if opt == RenderNoFiles {
174
-			continue
175
-		}
176
-		for _, file := range commit.Files {
177
-			if opt == RenderAllFiles ||
178
-				(opt == RenderOnlyGodepsFiles && file.HasGodepsChanges()) ||
179
-				(opt == RenderOnlyNonGodepsFiles && !file.HasGodepsChanges()) {
180
-				msg += fmt.Sprintf("  - %s\n", file)
181
-			}
182
-		}
183
-	}
184
-	return msg
185
-}
186 1
deleted file mode 100644
... ...
@@ -1,379 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"testing"
5
-
6
-	"github.com/openshift/origin/cmd/rebasehelpers/util"
7
-)
8
-
9
-func TestValidateUpstreamCommitsWithoutGodepsChanges(t *testing.T) {
10
-	tests := []struct {
11
-		name          string
12
-		commits       []util.Commit
13
-		errorExpected bool
14
-	}{
15
-		{
16
-			name: "test 1",
17
-			commits: []util.Commit{
18
-				{
19
-					Sha:     "aaa0000",
20
-					Summary: "commit 1",
21
-					Files:   []util.File{"file1", "pkg/file2"},
22
-				},
23
-				{
24
-					Sha:     "aaa0001",
25
-					Summary: "commit 2",
26
-					Files:   []util.File{"Godeps/file1", "pkg/file2"},
27
-				},
28
-			},
29
-			errorExpected: true,
30
-		},
31
-		{
32
-			name: "test 2",
33
-			commits: []util.Commit{
34
-				{
35
-					Sha:     "aaa0000",
36
-					Summary: "commit 1",
37
-					Files:   []util.File{"file1", "pkg/file2"},
38
-				},
39
-				{
40
-					Sha:     "aaa0001",
41
-					Summary: "UPSTREAM: commit 2",
42
-					Files:   []util.File{"Godeps/file1", "pkg/file2"},
43
-				},
44
-			},
45
-			errorExpected: false,
46
-		},
47
-	}
48
-	for _, test := range tests {
49
-		t.Logf("evaluating test %q", test.name)
50
-		err := ValidateUpstreamCommitsWithoutGodepsChanges(test.commits)
51
-		if err != nil {
52
-			if test.errorExpected {
53
-				t.Logf("got expected error:\n%s", err)
54
-				continue
55
-			} else {
56
-				t.Fatalf("unexpected error:\n%s", err)
57
-			}
58
-		} else {
59
-			if test.errorExpected {
60
-				t.Fatalf("expected an error, got none")
61
-			}
62
-		}
63
-	}
64
-}
65
-
66
-func TestValidateUpstreamCommitModifiesSingleGodepsRepo(t *testing.T) {
67
-	tests := []struct {
68
-		name          string
69
-		commits       []util.Commit
70
-		errorExpected bool
71
-	}{
72
-		{
73
-			name: "test 1",
74
-			commits: []util.Commit{
75
-				{
76
-					Sha:     "aaa0000",
77
-					Summary: "commit 1",
78
-					Files:   []util.File{"file1", "pkg/file2"},
79
-				},
80
-				{
81
-					Sha:     "aaa0001",
82
-					Summary: "commit 2",
83
-					Files: []util.File{
84
-						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
85
-						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
86
-					},
87
-				},
88
-			},
89
-			errorExpected: false,
90
-		},
91
-		{
92
-			name: "test 2",
93
-			commits: []util.Commit{
94
-				{
95
-					Sha:     "aaa0000",
96
-					Summary: "commit 1",
97
-					Files:   []util.File{"file1", "pkg/file2"},
98
-				},
99
-				{
100
-					Sha:     "aaa0001",
101
-					Summary: "UPSTREAM: commit 2",
102
-					Files: []util.File{
103
-						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
104
-						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
105
-						"Godeps/_workspace/src/github.com/coreos/etcd/file",
106
-					},
107
-				},
108
-				{
109
-					Sha:     "aaa0002",
110
-					Summary: "UPSTREAM: commit 3",
111
-					Files: []util.File{
112
-						"Godeps/_workspace/src/k8s.io/heapster/file1",
113
-						"Godeps/_workspace/src/github.com/coreos/etcd/file1",
114
-					},
115
-				},
116
-			},
117
-			errorExpected: true,
118
-		},
119
-	}
120
-	for _, test := range tests {
121
-		t.Logf("evaluating test %q", test.name)
122
-		err := ValidateUpstreamCommitModifiesSingleGodepsRepo(test.commits)
123
-		if err != nil {
124
-			if test.errorExpected {
125
-				t.Logf("got expected error:\n%s", err)
126
-				continue
127
-			} else {
128
-				t.Fatalf("unexpected error:\n%s", err)
129
-			}
130
-		} else {
131
-			if test.errorExpected {
132
-				t.Fatalf("expected an error, got none")
133
-			}
134
-		}
135
-	}
136
-}
137
-
138
-func TestValidateUpstreamCommitModifiesOnlyGodeps(t *testing.T) {
139
-	tests := []struct {
140
-		name          string
141
-		commits       []util.Commit
142
-		errorExpected bool
143
-	}{
144
-		{
145
-			name: "test 1",
146
-			commits: []util.Commit{
147
-				{
148
-					Sha:     "aaa0000",
149
-					Summary: "commit 1",
150
-					Files:   []util.File{"file1", "pkg/file2"},
151
-				},
152
-				{
153
-					Sha:     "aaa0001",
154
-					Summary: "UPSTREAM: commit 2",
155
-					Files: []util.File{
156
-						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
157
-						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
158
-						"pkg/some_file",
159
-					},
160
-				},
161
-			},
162
-			errorExpected: true,
163
-		},
164
-		{
165
-			name: "test 2",
166
-			commits: []util.Commit{
167
-				{
168
-					Sha:     "aaa0000",
169
-					Summary: "commit 1",
170
-					Files:   []util.File{"file1", "pkg/file2"},
171
-				},
172
-				{
173
-					Sha:     "aaa0001",
174
-					Summary: "UPSTREAM: commit 2",
175
-					Files: []util.File{
176
-						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
177
-						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
178
-					},
179
-				},
180
-			},
181
-			errorExpected: false,
182
-		},
183
-	}
184
-	for _, test := range tests {
185
-		t.Logf("evaluating test %q", test.name)
186
-		err := ValidateUpstreamCommitModifiesOnlyGodeps(test.commits)
187
-		if err != nil {
188
-			if test.errorExpected {
189
-				t.Logf("got expected error:\n%s", err)
190
-				continue
191
-			} else {
192
-				t.Fatalf("unexpected error:\n%s", err)
193
-			}
194
-		} else {
195
-			if test.errorExpected {
196
-				t.Fatalf("expected an error, got none")
197
-			}
198
-		}
199
-	}
200
-}
201
-
202
-func TestValidateUpstreamCommitSummaries(t *testing.T) {
203
-	tests := []struct {
204
-		summary string
205
-		valid   bool
206
-	}{
207
-		{valid: true, summary: "UPSTREAM: 12345: a change"},
208
-		{valid: true, summary: "UPSTREAM: k8s.io/heapster: 12345: a change"},
209
-		{valid: true, summary: "UPSTREAM: <carry>: a change"},
210
-		{valid: true, summary: "UPSTREAM: <drop>: a change"},
211
-		{valid: true, summary: "UPSTREAM: coreos/etcd: <carry>: a change"},
212
-		{valid: true, summary: "UPSTREAM: coreos/etcd: <drop>: a change"},
213
-		{valid: true, summary: "UPSTREAM: revert: abcd123: 12345: a change"},
214
-		{valid: true, summary: "UPSTREAM: revert: abcd123: k8s.io/heapster: 12345: a change"},
215
-		{valid: true, summary: "UPSTREAM: revert: abcd123: <carry>: a change"},
216
-		{valid: true, summary: "UPSTREAM: revert: abcd123: <drop>: a change"},
217
-		{valid: true, summary: "UPSTREAM: revert: abcd123: coreos/etcd: <carry>: a change"},
218
-		{valid: true, summary: "UPSTREAM: revert: abcd123: coreos/etcd: <drop>: a change"},
219
-		{valid: false, summary: "UPSTREAM: whoopsie daisy"},
220
-	}
221
-	for _, test := range tests {
222
-		commit := util.Commit{Summary: test.summary, Sha: "abcd000"}
223
-		err := ValidateUpstreamCommitSummaries([]util.Commit{commit})
224
-		if err != nil {
225
-			if test.valid {
226
-				t.Fatalf("unexpected error:\n%s", err)
227
-			} else {
228
-				t.Logf("got expected error:\n%s", err)
229
-			}
230
-		} else {
231
-			if !test.valid {
232
-				t.Fatalf("expected an error, got none; summary: %s", test.summary)
233
-			}
234
-		}
235
-	}
236
-}
237
-
238
-func TestValidateUpstreamCommitModifiesOnlyDeclaredGodepRepo(t *testing.T) {
239
-	tests := []struct {
240
-		name          string
241
-		commits       []util.Commit
242
-		errorExpected bool
243
-	}{
244
-		{
245
-			name: "test 1",
246
-			commits: []util.Commit{
247
-				{
248
-					Sha:     "aaa0000",
249
-					Summary: "commit 1",
250
-					Files:   []util.File{"file1", "pkg/file2"},
251
-				},
252
-				{
253
-					Sha:     "aaa0001",
254
-					Summary: "UPSTREAM: coreos/etcd: 12345: a change",
255
-					Files: []util.File{
256
-						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
257
-						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
258
-						"Godeps/_workspace/src/github.com/coreos/etcd/file1",
259
-					},
260
-				},
261
-			},
262
-			errorExpected: true,
263
-		},
264
-		{
265
-			name: "test 2",
266
-			commits: []util.Commit{
267
-				{
268
-					Sha:     "aaa0001",
269
-					Summary: "UPSTREAM: coreos/etcd: 12345: a change",
270
-					Files: []util.File{
271
-						"Godeps/_workspace/src/github.com/coreos/etcd/file1",
272
-						"Godeps/_workspace/src/github.com/coreos/etcd/file2",
273
-					},
274
-				},
275
-			},
276
-			errorExpected: false,
277
-		},
278
-		{
279
-			name: "test three segments",
280
-			commits: []util.Commit{
281
-				{
282
-					Sha:     "aaa0001",
283
-					Summary: "UPSTREAM: coreos/etcd: 12345: a change",
284
-					Files: []util.File{
285
-						"Godeps/_workspace/src/github.com/coreos/etcd/a/file1",
286
-						"Godeps/_workspace/src/github.com/coreos/etcd/b/file2",
287
-					},
288
-				},
289
-			},
290
-			errorExpected: false,
291
-		},
292
-		{
293
-			name: "test 3",
294
-			commits: []util.Commit{
295
-				{
296
-					Sha:     "aaa0001",
297
-					Summary: "UPSTREAM: 12345: a change",
298
-					Files: []util.File{
299
-						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
300
-						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
301
-					},
302
-				},
303
-			},
304
-			errorExpected: false,
305
-		},
306
-		{
307
-			name: "test 4",
308
-			commits: []util.Commit{
309
-				{
310
-					Sha:     "aaa0001",
311
-					Summary: "UPSTREAM: 12345: a change",
312
-					Files: []util.File{
313
-						"Godeps/_workspace/src/github.com/coreos/etcd/file1",
314
-						"Godeps/_workspace/src/github.com/coreos/etcd/file2",
315
-					},
316
-				},
317
-			},
318
-			errorExpected: true,
319
-		},
320
-		{
321
-			name: "test 5",
322
-			commits: []util.Commit{
323
-				{
324
-					Sha:     "aaa0001",
325
-					Summary: "UPSTREAM: revert: abcd000: 12345: a change",
326
-					Files: []util.File{
327
-						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
328
-						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
329
-					},
330
-				},
331
-			},
332
-			errorExpected: false,
333
-		},
334
-		{
335
-			name: "test 6",
336
-			commits: []util.Commit{
337
-				{
338
-					Sha:     "aaa0001",
339
-					Summary: "UPSTREAM: revert: abcd000: coreos/etcd: 12345: a change",
340
-					Files: []util.File{
341
-						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
342
-						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
343
-					},
344
-				},
345
-			},
346
-			errorExpected: true,
347
-		},
348
-		{
349
-			name: "test 7",
350
-			commits: []util.Commit{
351
-				{
352
-					Sha:     "aaa0001",
353
-					Summary: "UPSTREAM: revert: abcd000: coreos/etcd: 12345: a change",
354
-					Files: []util.File{
355
-						"Godeps/_workspace/src/github.com/coreos/etcd/file1",
356
-						"Godeps/_workspace/src/github.com/coreos/etcd/file2",
357
-					},
358
-				},
359
-			},
360
-			errorExpected: false,
361
-		},
362
-	}
363
-	for _, test := range tests {
364
-		t.Logf("evaluating test %q", test.name)
365
-		err := ValidateUpstreamCommitModifiesOnlyDeclaredGodepRepo(test.commits)
366
-		if err != nil {
367
-			if test.errorExpected {
368
-				t.Logf("got expected error:\n%s", err)
369
-				continue
370
-			} else {
371
-				t.Fatalf("unexpected error:\n%s", err)
372
-			}
373
-		} else {
374
-			if test.errorExpected {
375
-				t.Fatalf("expected an error, got none")
376
-			}
377
-		}
378
-	}
379
-}
380 1
deleted file mode 100644
... ...
@@ -1,200 +0,0 @@
1
-package util
2
-
3
-import (
4
-	"bytes"
5
-	"fmt"
6
-	"os"
7
-	"os/exec"
8
-	"regexp"
9
-	"strings"
10
-)
11
-
12
-var UpstreamSummaryPattern = regexp.MustCompile(`UPSTREAM: (revert: [a-f0-9]{7,}: )?(([\w\.-]+\/[\w-]+)?: )?(\d+:|<carry>:|<drop>:)`)
13
-
14
-// supportedHosts maps source hosts to the number of path segments that
15
-// represent the account/repo for that host. This is necessary because we
16
-// can't tell just by looking at an import path whether the repo is identified
17
-// by the first 2 or 3 path segments.
18
-//
19
-// If dependencies are introduced from new hosts, they'll need to be added
20
-// here.
21
-var SupportedHosts = map[string]int{
22
-	"bitbucket.org":     3,
23
-	"code.google.com":   3,
24
-	"github.com":        3,
25
-	"golang.org":        3,
26
-	"google.golang.org": 2,
27
-	"gopkg.in":          2,
28
-	"k8s.io":            2,
29
-	"speter.net":        2,
30
-}
31
-
32
-type Commit struct {
33
-	Sha     string
34
-	Summary string
35
-	Files   []File
36
-}
37
-
38
-func (c Commit) DeclaresUpstreamChange() bool {
39
-	return strings.HasPrefix(strings.ToLower(c.Summary), "upstream")
40
-}
41
-
42
-func (c Commit) MatchesUpstreamSummaryPattern() bool {
43
-	return UpstreamSummaryPattern.MatchString(c.Summary)
44
-}
45
-
46
-func (c Commit) DeclaredUpstreamRepo() (string, error) {
47
-	if !c.DeclaresUpstreamChange() {
48
-		return "", fmt.Errorf("commit declares no upstream changes")
49
-	}
50
-	if !c.MatchesUpstreamSummaryPattern() {
51
-		return "", fmt.Errorf("commit doesn't match the upstream commit summary pattern")
52
-	}
53
-	groups := UpstreamSummaryPattern.FindStringSubmatch(c.Summary)
54
-	repo := groups[3]
55
-	if len(repo) == 0 {
56
-		repo = "k8s.io/kubernetes"
57
-	}
58
-	return repo, nil
59
-}
60
-
61
-func (c Commit) HasGodepsChanges() bool {
62
-	for _, file := range c.Files {
63
-		if file.HasGodepsChanges() {
64
-			return true
65
-		}
66
-	}
67
-	return false
68
-}
69
-
70
-func (c Commit) HasNonGodepsChanges() bool {
71
-	for _, file := range c.Files {
72
-		if !file.HasGodepsChanges() {
73
-			return true
74
-		}
75
-	}
76
-	return false
77
-}
78
-
79
-func (c Commit) GodepsReposChanged() ([]string, error) {
80
-	repos := map[string]struct{}{}
81
-	for _, file := range c.Files {
82
-		if !file.HasGodepsChanges() {
83
-			continue
84
-		}
85
-		repo, err := file.GodepsRepoChanged()
86
-		if err != nil {
87
-			return nil, fmt.Errorf("problem with file %q in commit %s: %s", file, c.Sha, err)
88
-		}
89
-		repos[repo] = struct{}{}
90
-	}
91
-	changed := []string{}
92
-	for repo := range repos {
93
-		changed = append(changed, repo)
94
-	}
95
-	return changed, nil
96
-}
97
-
98
-type File string
99
-
100
-func (f File) HasGodepsChanges() bool {
101
-	return strings.HasPrefix(string(f), "Godeps")
102
-}
103
-
104
-func (f File) GodepsRepoChanged() (string, error) {
105
-	if !f.HasGodepsChanges() {
106
-		return "", fmt.Errorf("file doesn't appear to be a Godeps change")
107
-	}
108
-	// Find the _workspace path segment index.
109
-	workspaceIdx := -1
110
-	parts := strings.Split(string(f), string(os.PathSeparator))
111
-	for i, part := range parts {
112
-		if part == "_workspace" {
113
-			workspaceIdx = i
114
-			break
115
-		}
116
-	}
117
-	// Godeps path struture assumption: Godeps/_workspace/src/...
118
-	if workspaceIdx == -1 || len(parts) < (workspaceIdx+3) {
119
-		return "", fmt.Errorf("file doesn't appear to be a Godeps workspace path")
120
-	}
121
-	// Deal with repos which could be identified by either 2 or 3 path segments.
122
-	host := parts[workspaceIdx+2]
123
-	segments := -1
124
-	for supportedHost, count := range SupportedHosts {
125
-		if host == supportedHost {
126
-			segments = count
127
-			break
128
-		}
129
-	}
130
-	if segments == -1 {
131
-		return "", fmt.Errorf("file modifies an unsupported repo host %q", host)
132
-	}
133
-	switch segments {
134
-	case 2:
135
-		return fmt.Sprintf("%s/%s", host, parts[workspaceIdx+3]), nil
136
-	case 3:
137
-		return fmt.Sprintf("%s/%s/%s", host, parts[workspaceIdx+3], parts[workspaceIdx+4]), nil
138
-	}
139
-	return "", fmt.Errorf("file modifies an unsupported repo host %q", host)
140
-}
141
-
142
-func CommitsBetween(a, b string) ([]Commit, error) {
143
-	commits := []Commit{}
144
-	stdout, _, err := run("git", "log", "--oneline", fmt.Sprintf("%s..%s", a, b))
145
-	if err != nil {
146
-		return nil, fmt.Errorf("error executing git log: %s", err)
147
-	}
148
-	for _, log := range strings.Split(stdout, "\n") {
149
-		if len(log) == 0 {
150
-			continue
151
-		}
152
-		commit, err := NewCommitFromOnelineLog(log)
153
-		if err != nil {
154
-			return nil, err
155
-		}
156
-		commits = append(commits, commit)
157
-	}
158
-	return commits, nil
159
-}
160
-
161
-func NewCommitFromOnelineLog(log string) (Commit, error) {
162
-	var commit Commit
163
-	parts := strings.Split(log, " ")
164
-	if len(parts) < 2 {
165
-		return commit, fmt.Errorf("invalid log entry: %s", log)
166
-	}
167
-	commit.Sha = parts[0]
168
-	commit.Summary = strings.Join(parts[1:], " ")
169
-	files, err := filesInCommit(commit.Sha)
170
-	if err != nil {
171
-		return commit, err
172
-	}
173
-	commit.Files = files
174
-	return commit, nil
175
-}
176
-
177
-func filesInCommit(sha string) ([]File, error) {
178
-	files := []File{}
179
-	stdout, _, err := run("git", "diff-tree", "--no-commit-id", "--name-only", "-r", sha)
180
-	if err != nil {
181
-		return nil, err
182
-	}
183
-	for _, filename := range strings.Split(stdout, "\n") {
184
-		if len(filename) == 0 {
185
-			continue
186
-		}
187
-		files = append(files, File(filename))
188
-	}
189
-	return files, nil
190
-}
191
-
192
-func run(args ...string) (string, string, error) {
193
-	cmd := exec.Command(args[0], args[1:]...)
194
-	var stdout bytes.Buffer
195
-	var stderr bytes.Buffer
196
-	cmd.Stdout = &stdout
197
-	cmd.Stderr = &stderr
198
-	err := cmd.Run()
199
-	return stdout.String(), stderr.String(), err
200
-}
... ...
@@ -32,7 +32,7 @@ if [[ ! -d "${UPSTREAM_REPO_LOCATION}" ]]; then
32 32
 fi
33 33
 
34 34
 if [[ -z "${NO_REBASE-}" ]]; then
35
-  lastrev="$(go run ${OS_ROOT}/hack/version.go ${OS_ROOT}/Godeps/Godeps.json ${repo}/${package})"
35
+  lastrev="$(go run ${OS_ROOT}/tools/godepversion/godepversion.go ${OS_ROOT}/Godeps/Godeps.json ${repo}/${package})"
36 36
 fi
37 37
 
38 38
 pushd "${UPSTREAM_REPO_LOCATION}" > /dev/null
... ...
@@ -518,8 +518,8 @@ os::build::os_version_vars() {
518 518
 # os::build::kube_version_vars returns the version of Kubernetes we have
519 519
 # vendored.
520 520
 os::build::kube_version_vars() {
521
-  KUBE_GIT_VERSION=$(go run "${OS_ROOT}/hack/version.go" "${OS_ROOT}/Godeps/Godeps.json" "k8s.io/kubernetes/pkg/api" "comment")
522
-  KUBE_GIT_COMMIT=$(go run "${OS_ROOT}/hack/version.go" "${OS_ROOT}/Godeps/Godeps.json" "k8s.io/kubernetes/pkg/api")
521
+  KUBE_GIT_VERSION=$(go run "${OS_ROOT}/tools/godepversion/godepversion.go" "${OS_ROOT}/Godeps/Godeps.json" "k8s.io/kubernetes/pkg/api" "comment")
522
+  KUBE_GIT_COMMIT=$(go run "${OS_ROOT}/tools/godepversion/godepversion.go" "${OS_ROOT}/Godeps/Godeps.json" "k8s.io/kubernetes/pkg/api")
523 523
 }
524 524
 
525 525
 # Saves the environment flags to $1
... ...
@@ -10,7 +10,7 @@ OS_ROOT=$(dirname "${BASH_SOURCE}")/..
10 10
 source "${OS_ROOT}/hack/util.sh"
11 11
 os::log::install_errexit
12 12
 
13
-etcd_version=$(go run ${OS_ROOT}/hack/version.go ${OS_ROOT}/Godeps/Godeps.json github.com/coreos/etcd/etcdserver)
13
+etcd_version=$(go run ${OS_ROOT}/tools/godepversion/godepversion.go ${OS_ROOT}/Godeps/Godeps.json github.com/coreos/etcd/etcdserver)
14 14
 
15 15
 mkdir -p "${OS_ROOT}/_tools"
16 16
 cd "${OS_ROOT}/_tools"
... ...
@@ -25,7 +25,7 @@ if [[ ! -d "${relativedir}" ]]; then
25 25
 fi
26 26
 
27 27
 if [[ -z "${NO_REBASE-}" ]]; then
28
-  lastrev="$(go run ${OS_ROOT}/hack/version.go ${OS_ROOT}/Godeps/Godeps.json ${repo}/${package})"
28
+  lastrev="$(go run ${OS_ROOT}/tools/godepversion/godepversion.go ${OS_ROOT}/Godeps/Godeps.json ${repo}/${package})"
29 29
 fi
30 30
 
31 31
 branch="$(git rev-parse --abbrev-ref HEAD)"
... ...
@@ -15,7 +15,7 @@ if [[ "${platform}" != "linux/amd64" ]]; then
15 15
   exit 1
16 16
 fi
17 17
 
18
-"${OS_ROOT}/hack/build-go.sh" cmd/genbashcomp
18
+"${OS_ROOT}/hack/build-go.sh" tools/genbashcomp
19 19
 
20 20
 # Find binary
21 21
 genbashcomp="$(os::build::find-binary genbashcomp)"
... ...
@@ -25,7 +25,7 @@ if [[ ! "$genbashcomp" ]]; then
25 25
     echo "It looks as if you don't have a compiled genbashcomp binary"
26 26
     echo
27 27
     echo "If you are running from a clone of the git repo, please run"
28
-    echo "'./hack/build-go.sh cmd/genbashcomp'."
28
+    echo "'./hack/build-go.sh tools/genbashcomp'."
29 29
   } >&2
30 30
   exit 1
31 31
 fi
... ...
@@ -24,7 +24,7 @@ package ${version}
24 24
 // AUTO-GENERATED FUNCTIONS START HERE
25 25
 EOF
26 26
 
27
-	go run cmd/genconversion/conversion.go -v ${version} -f - >>  $TMPFILE
27
+	go run tools/genconversion/conversion.go -v ${version} -f - >>  $TMPFILE
28 28
 
29 29
 	cat >> $TMPFILE <<EOF
30 30
 // AUTO-GENERATED FUNCTIONS END HERE
... ...
@@ -35,7 +35,7 @@ package ${version}
35 35
 // AUTO-GENERATED FUNCTIONS START HERE
36 36
 EOF
37 37
 
38
-	go run cmd/gendeepcopy/deep_copy.go -v ${version} -f - -o "${version}=" >>  $TMPFILE
38
+	go run tools/gendeepcopy/deep_copy.go -v ${version} -f - -o "${version}=" >>  $TMPFILE
39 39
 
40 40
 	cat >> $TMPFILE <<EOF
41 41
 // AUTO-GENERATED FUNCTIONS END HERE
... ...
@@ -9,7 +9,7 @@ set -o pipefail
9 9
 OS_ROOT=$(dirname "${BASH_SOURCE}")/..
10 10
 source "${OS_ROOT}/hack/common.sh"
11 11
 
12
-"${OS_ROOT}/hack/build-go.sh" cmd/gendocs
12
+"${OS_ROOT}/hack/build-go.sh" tools/gendocs
13 13
 
14 14
 # Find binary
15 15
 gendocs="$(os::build::find-binary gendocs)"
... ...
@@ -19,7 +19,7 @@ if [[ -z "$gendocs" ]]; then
19 19
     echo "It looks as if you don't have a compiled gendocs binary"
20 20
     echo
21 21
     echo "If you are running from a clone of the git repo, please run"
22
-    echo "'./hack/build-go.sh cmd/gendocs'."
22
+    echo "'./hack/build-go.sh tools/gendocs'."
23 23
   } >&2
24 24
   exit 1
25 25
 fi
... ...
@@ -11,7 +11,7 @@ cd "${OS_ROOT}"
11 11
 
12 12
 echo "===== Verifying Generated Conversions ====="
13 13
 echo "Building genconversion binary..."
14
-if ! buildout=`"${OS_ROOT}/hack/build-go.sh" cmd/genconversion 2>&1`
14
+if ! buildout=`"${OS_ROOT}/hack/build-go.sh" tools/genconversion 2>&1`
15 15
 then
16 16
   echo "FAILURE: Building genconversion binary failed:"
17 17
   echo "$buildout"
... ...
@@ -27,7 +27,7 @@ if [[ ! -x "$genconversion" ]]; then
27 27
   {
28 28
     echo "FAILURE: It looks as if you don't have a compiled conversion binary."
29 29
     echo "If you are running from a clone of the git repo, please run:"
30
-    echo "'./hack/build-go.sh cmd/genconversion'."
30
+    echo "'./hack/build-go.sh tools/genconversion'."
31 31
   } >&2
32 32
   exit 1
33 33
 fi
... ...
@@ -11,7 +11,7 @@ cd "${OS_ROOT}"
11 11
 
12 12
 echo "===== Verifying Generated Conversions ====="
13 13
 echo "Building gendeepcopy binary..."
14
-if ! buildout=`"${OS_ROOT}/hack/build-go.sh" cmd/gendeepcopy 2>&1`
14
+if ! buildout=`"${OS_ROOT}/hack/build-go.sh" tools/gendeepcopy 2>&1`
15 15
 then
16 16
   echo "FAILURE: Building gendeepcopy binary failed:"
17 17
   echo "$buildout"
... ...
@@ -27,7 +27,7 @@ if [[ ! -x "$gendeepcopy" ]]; then
27 27
   {
28 28
     echo "FAILURE: It looks as if you don't have a compiled conversion binary."
29 29
     echo "If you are running from a clone of the git repo, please run:"
30
-    echo "'./hack/build-go.sh cmd/gendeepcopy'."
30
+    echo "'./hack/build-go.sh tools/gendeepcopy'."
31 31
   } >&2
32 32
   exit 1
33 33
 fi
... ...
@@ -7,7 +7,7 @@ set -o pipefail
7 7
 OS_ROOT=$(dirname "${BASH_SOURCE}")/..
8 8
 source "${OS_ROOT}/hack/common.sh"
9 9
 
10
-"${OS_ROOT}/hack/build-go.sh" cmd/rebasehelpers/commitchecker
10
+"${OS_ROOT}/hack/build-go.sh" tools/rebasehelpers/commitchecker
11 11
 
12 12
 # Find binary
13 13
 commitchecker="$(os::build::find-binary commitchecker)"
14 14
deleted file mode 100644
... ...
@@ -1,67 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"encoding/json"
5
-	"fmt"
6
-	"io/ioutil"
7
-	"os"
8
-)
9
-
10
-type Godep struct {
11
-	Deps []Dep
12
-}
13
-
14
-type Dep struct {
15
-	ImportPath string
16
-	Comment    string
17
-	Rev        string
18
-}
19
-
20
-func main() {
21
-	comment := false
22
-	args := os.Args[1:]
23
-	if len(args) == 3 {
24
-		if args[2] == "comment" {
25
-			comment = true
26
-		} else {
27
-			fmt.Fprintf(os.Stderr, "The third argument must be 'comment' or not specified.\n")
28
-			os.Exit(1)
29
-		}
30
-		args = args[:2]
31
-	}
32
-	if len(args) != 2 {
33
-		fmt.Fprintf(os.Stderr, "Expects two arguments, a path to the Godep.json file and a package to get the commit for (and optionally, 'comment' as the third option)\n")
34
-		os.Exit(1)
35
-	}
36
-
37
-	path := args[0]
38
-	pkg := args[1]
39
-
40
-	data, err := ioutil.ReadFile(path)
41
-	if err != nil {
42
-		fmt.Fprintf(os.Stderr, "Unable to read %s: %v\n", path, err)
43
-		os.Exit(1)
44
-	}
45
-	godeps := &Godep{}
46
-	if err := json.Unmarshal(data, godeps); err != nil {
47
-		fmt.Fprintf(os.Stderr, "Unable to read %s: %v\n", path, err)
48
-		os.Exit(1)
49
-	}
50
-
51
-	for _, dep := range godeps.Deps {
52
-		if dep.ImportPath != pkg {
53
-			continue
54
-		}
55
-		if len(dep.Rev) > 7 {
56
-			dep.Rev = dep.Rev[0:7]
57
-		}
58
-		if comment && len(dep.Comment) > 0 {
59
-			dep.Rev = dep.Comment
60
-		}
61
-		fmt.Fprintf(os.Stdout, dep.Rev)
62
-		return
63
-	}
64
-
65
-	fmt.Fprintf(os.Stderr, "Could not find %s in %s\n", pkg, path)
66
-	os.Exit(1)
67
-}
68 1
new file mode 100644
... ...
@@ -0,0 +1,60 @@
0
+package main
1
+
2
+import (
3
+	"bytes"
4
+	"fmt"
5
+	"io/ioutil"
6
+	"os"
7
+	"path/filepath"
8
+
9
+	"github.com/openshift/origin/pkg/cmd/admin"
10
+	"github.com/openshift/origin/pkg/cmd/cli"
11
+	"github.com/openshift/origin/pkg/cmd/openshift"
12
+)
13
+
14
+func OutDir(path string) (string, error) {
15
+	outDir, err := filepath.Abs(path)
16
+	if err != nil {
17
+		return "", err
18
+	}
19
+
20
+	stat, err := os.Stat(outDir)
21
+	if err != nil {
22
+		return "", err
23
+	}
24
+
25
+	if !stat.IsDir() {
26
+		return "", fmt.Errorf("output directory %s is not a directory\n", outDir)
27
+	}
28
+	outDir = outDir + "/"
29
+	return outDir, nil
30
+}
31
+
32
+func main() {
33
+	// use os.Args instead of "flags" because "flags" will mess up the man pages!
34
+	path := "contrib/completions/bash/"
35
+	if len(os.Args) == 2 {
36
+		path = os.Args[1]
37
+	} else if len(os.Args) > 2 {
38
+		fmt.Fprintf(os.Stderr, "usage: %s [output directory]\n", os.Args[0])
39
+		os.Exit(1)
40
+	}
41
+
42
+	outDir, err := OutDir(path)
43
+	if err != nil {
44
+		fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err)
45
+		os.Exit(1)
46
+	}
47
+	outFile_openshift := outDir + "openshift"
48
+	openshift := openshift.NewCommandOpenShift("openshift")
49
+	openshift.GenBashCompletionFile(outFile_openshift)
50
+
51
+	outFile_osc := outDir + "oc"
52
+	out := os.Stdout
53
+	oc := cli.NewCommandCLI("oc", "openshift cli", &bytes.Buffer{}, out, ioutil.Discard)
54
+	oc.GenBashCompletionFile(outFile_osc)
55
+
56
+	outFile_osadm := outDir + "oadm"
57
+	oadm := admin.NewCommandAdmin("oadm", "openshift admin", ioutil.Discard)
58
+	oadm.GenBashCompletionFile(outFile_osadm)
59
+}
0 60
new file mode 100644
... ...
@@ -0,0 +1,71 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"io"
5
+	"os"
6
+	"runtime"
7
+	"strings"
8
+
9
+	"k8s.io/kubernetes/pkg/api"
10
+	pkg_runtime "k8s.io/kubernetes/pkg/runtime"
11
+	"k8s.io/kubernetes/pkg/util/sets"
12
+
13
+	"github.com/golang/glog"
14
+	flag "github.com/spf13/pflag"
15
+
16
+	_ "github.com/openshift/origin/pkg/api"
17
+	_ "github.com/openshift/origin/pkg/api/v1"
18
+	_ "github.com/openshift/origin/pkg/api/v1beta3"
19
+)
20
+
21
+var (
22
+	functionDest = flag.StringP("funcDest", "f", "-", "Output for conversion functions; '-' means stdout")
23
+	version      = flag.StringP("version", "v", "v1beta3", "Version for conversion.")
24
+)
25
+
26
+func main() {
27
+	runtime.GOMAXPROCS(runtime.NumCPU())
28
+	flag.Parse()
29
+
30
+	var funcOut io.Writer
31
+	if *functionDest == "-" {
32
+		funcOut = os.Stdout
33
+	} else {
34
+		file, err := os.Create(*functionDest)
35
+		if err != nil {
36
+			glog.Fatalf("Couldn't open %v: %v", *functionDest, err)
37
+		}
38
+		defer file.Close()
39
+		funcOut = file
40
+	}
41
+
42
+	generator := pkg_runtime.NewConversionGenerator(api.Scheme.Raw(), "github.com/openshift/origin/pkg/api")
43
+	apiShort := generator.AddImport("k8s.io/kubernetes/pkg/api")
44
+	generator.AddImport("k8s.io/kubernetes/pkg/api/resource")
45
+	generator.AssumePrivateConversions()
46
+	// TODO(wojtek-t): Change the overwrites to a flag.
47
+	generator.OverwritePackage(*version, "")
48
+	for _, knownType := range api.Scheme.KnownTypes(*version) {
49
+		if !strings.Contains(knownType.PkgPath(), "openshift/origin") {
50
+			continue
51
+		}
52
+		if err := generator.GenerateConversionsForType(*version, knownType); err != nil {
53
+			glog.Errorf("error while generating conversion functions for %v: %v", knownType, err)
54
+		}
55
+	}
56
+
57
+	generator.RepackImports(sets.NewString("k8s.io/kubernetes/pkg/runtime"))
58
+	// the repack changes the name of the import
59
+	apiShort = generator.AddImport("k8s.io/kubernetes/pkg/api")
60
+
61
+	if err := generator.WriteImports(funcOut); err != nil {
62
+		glog.Fatalf("error while writing imports: %v", err)
63
+	}
64
+	if err := generator.WriteConversionFunctions(funcOut); err != nil {
65
+		glog.Fatalf("Error while writing conversion functions: %v", err)
66
+	}
67
+	if err := generator.RegisterConversionFunctions(funcOut, fmt.Sprintf("%s.Scheme", apiShort)); err != nil {
68
+		glog.Fatalf("Error while writing conversion functions: %v", err)
69
+	}
70
+}
0 71
new file mode 100644
... ...
@@ -0,0 +1,94 @@
0
+/*
1
+Copyright 2015 The Kubernetes Authors All rights reserved.
2
+
3
+Licensed under the Apache License, Version 2.0 (the "License");
4
+you may not use this file except in compliance with the License.
5
+You may obtain a copy of the License at
6
+
7
+    http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+Unless required by applicable law or agreed to in writing, software
10
+distributed under the License is distributed on an "AS IS" BASIS,
11
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+See the License for the specific language governing permissions and
13
+limitations under the License.
14
+*/
15
+
16
+package main
17
+
18
+import (
19
+	"fmt"
20
+	"io"
21
+	"os"
22
+	"runtime"
23
+	"strings"
24
+
25
+	"k8s.io/kubernetes/pkg/api"
26
+	pkg_runtime "k8s.io/kubernetes/pkg/runtime"
27
+	"k8s.io/kubernetes/pkg/util/sets"
28
+
29
+	"github.com/golang/glog"
30
+	flag "github.com/spf13/pflag"
31
+
32
+	_ "github.com/openshift/origin/pkg/api"
33
+	_ "github.com/openshift/origin/pkg/api/v1"
34
+	_ "github.com/openshift/origin/pkg/api/v1beta3"
35
+)
36
+
37
+var (
38
+	functionDest = flag.StringP("func-dest", "f", "-", "Output for deep copy functions; '-' means stdout")
39
+	version      = flag.StringP("version", "v", "v1beta3", "Version for deep copies.")
40
+	overwrites   = flag.StringP("overwrites", "o", "", "Comma-separated overwrites for package names")
41
+)
42
+
43
+func main() {
44
+	runtime.GOMAXPROCS(runtime.NumCPU())
45
+	flag.Parse()
46
+
47
+	var funcOut io.Writer
48
+	if *functionDest == "-" {
49
+		funcOut = os.Stdout
50
+	} else {
51
+		file, err := os.Create(*functionDest)
52
+		if err != nil {
53
+			glog.Fatalf("Couldn't open %v: %v", *functionDest, err)
54
+		}
55
+		defer file.Close()
56
+		funcOut = file
57
+	}
58
+
59
+	knownVersion := *version
60
+	if knownVersion == "api" {
61
+		knownVersion = api.Scheme.Raw().InternalVersion
62
+	}
63
+	generator := pkg_runtime.NewDeepCopyGenerator(api.Scheme.Raw(), "github.com/openshift/origin/pkg/api", sets.NewString("github.com/openshift/origin"))
64
+	apiShort := generator.AddImport("k8s.io/kubernetes/pkg/api")
65
+	generator.ReplaceType("k8s.io/kubernetes/pkg/util/sets", "empty", struct{}{})
66
+
67
+	for _, overwrite := range strings.Split(*overwrites, ",") {
68
+		vals := strings.Split(overwrite, "=")
69
+		generator.OverwritePackage(vals[0], vals[1])
70
+	}
71
+	for _, knownType := range api.Scheme.KnownTypes(knownVersion) {
72
+		if !strings.Contains(knownType.PkgPath(), "openshift/origin") {
73
+			continue
74
+		}
75
+		if err := generator.AddType(knownType); err != nil {
76
+			glog.Errorf("error while generating deep copy functions for %v: %v", knownType, err)
77
+		}
78
+	}
79
+
80
+	generator.RepackImports()
81
+	// the repack changes the name of the import
82
+	apiShort = generator.AddImport("k8s.io/kubernetes/pkg/api")
83
+
84
+	if err := generator.WriteImports(funcOut); err != nil {
85
+		glog.Fatalf("error while writing imports: %v", err)
86
+	}
87
+	if err := generator.WriteDeepCopyFunctions(funcOut); err != nil {
88
+		glog.Fatalf("error while writing deep copy functions: %v", err)
89
+	}
90
+	if err := generator.RegisterDeepCopyFunctions(funcOut, fmt.Sprintf("%s.Scheme", apiShort)); err != nil {
91
+		glog.Fatalf("error while registering deep copy functions: %v", err)
92
+	}
93
+}
0 94
new file mode 100644
... ...
@@ -0,0 +1,56 @@
0
+package main
1
+
2
+import (
3
+	"bytes"
4
+	"fmt"
5
+	"io/ioutil"
6
+	"os"
7
+	"path/filepath"
8
+
9
+	"github.com/openshift/origin/pkg/cmd/admin"
10
+	"github.com/openshift/origin/pkg/cmd/cli"
11
+	"github.com/openshift/origin/pkg/cmd/util/gendocs"
12
+)
13
+
14
+func OutDir(path string) (string, error) {
15
+	outDir, err := filepath.Abs(path)
16
+	if err != nil {
17
+		return "", err
18
+	}
19
+
20
+	stat, err := os.Stat(outDir)
21
+	if err != nil {
22
+		return "", err
23
+	}
24
+
25
+	if !stat.IsDir() {
26
+		return "", fmt.Errorf("output directory %s is not a directory\n", outDir)
27
+	}
28
+	outDir = outDir + "/"
29
+	return outDir, nil
30
+}
31
+
32
+func main() {
33
+	path := "docs/generated/"
34
+	if len(os.Args) == 2 {
35
+		path = os.Args[1]
36
+	} else if len(os.Args) > 2 {
37
+		fmt.Fprintf(os.Stderr, "usage: %s [output directory]\n", os.Args[0])
38
+		os.Exit(1)
39
+	}
40
+
41
+	outDir, err := OutDir(path)
42
+	if err != nil {
43
+		fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err)
44
+		os.Exit(1)
45
+	}
46
+
47
+	outFile := outDir + "oc_by_example_content.adoc"
48
+	out := os.Stdout
49
+	cmd := cli.NewCommandCLI("oc", "oc", &bytes.Buffer{}, out, ioutil.Discard)
50
+	gendocs.GenDocs(cmd, outFile)
51
+
52
+	outFile = outDir + "oadm_by_example_content.adoc"
53
+	cmd = admin.NewCommandAdmin("oadm", "oadm", ioutil.Discard)
54
+	gendocs.GenDocs(cmd, outFile)
55
+}
0 56
new file mode 100644
... ...
@@ -0,0 +1,67 @@
0
+package main
1
+
2
+import (
3
+	"encoding/json"
4
+	"fmt"
5
+	"io/ioutil"
6
+	"os"
7
+)
8
+
9
+type Godep struct {
10
+	Deps []Dep
11
+}
12
+
13
+type Dep struct {
14
+	ImportPath string
15
+	Comment    string
16
+	Rev        string
17
+}
18
+
19
+func main() {
20
+	comment := false
21
+	args := os.Args[1:]
22
+	if len(args) == 3 {
23
+		if args[2] == "comment" {
24
+			comment = true
25
+		} else {
26
+			fmt.Fprintf(os.Stderr, "The third argument must be 'comment' or not specified.\n")
27
+			os.Exit(1)
28
+		}
29
+		args = args[:2]
30
+	}
31
+	if len(args) != 2 {
32
+		fmt.Fprintf(os.Stderr, "Expects two arguments, a path to the Godep.json file and a package to get the commit for (and optionally, 'comment' as the third option)\n")
33
+		os.Exit(1)
34
+	}
35
+
36
+	path := args[0]
37
+	pkg := args[1]
38
+
39
+	data, err := ioutil.ReadFile(path)
40
+	if err != nil {
41
+		fmt.Fprintf(os.Stderr, "Unable to read %s: %v\n", path, err)
42
+		os.Exit(1)
43
+	}
44
+	godeps := &Godep{}
45
+	if err := json.Unmarshal(data, godeps); err != nil {
46
+		fmt.Fprintf(os.Stderr, "Unable to read %s: %v\n", path, err)
47
+		os.Exit(1)
48
+	}
49
+
50
+	for _, dep := range godeps.Deps {
51
+		if dep.ImportPath != pkg {
52
+			continue
53
+		}
54
+		if len(dep.Rev) > 7 {
55
+			dep.Rev = dep.Rev[0:7]
56
+		}
57
+		if comment && len(dep.Comment) > 0 {
58
+			dep.Rev = dep.Comment
59
+		}
60
+		fmt.Fprintf(os.Stdout, dep.Rev)
61
+		return
62
+	}
63
+
64
+	fmt.Fprintf(os.Stderr, "Could not find %s in %s\n", pkg, path)
65
+	os.Exit(1)
66
+}
0 67
new file mode 100644
... ...
@@ -0,0 +1,46 @@
0
+package main
1
+
2
+import (
3
+	"flag"
4
+	"fmt"
5
+	"os"
6
+	"strings"
7
+
8
+	"github.com/openshift/origin/tools/rebasehelpers/util"
9
+)
10
+
11
+func main() {
12
+	var start, end string
13
+	flag.StringVar(&start, "start", "master", "The start of the revision range for analysis")
14
+	flag.StringVar(&end, "end", "HEAD", "The end of the revision range for analysis")
15
+	flag.Parse()
16
+
17
+	commits, err := util.CommitsBetween(start, end)
18
+	if err != nil {
19
+		os.Stderr.WriteString(fmt.Sprintf("ERROR: couldn't find commits from %s..%s: %v\n", start, end, err))
20
+		os.Exit(1)
21
+	}
22
+
23
+	// TODO: Filter out bump commits for now until we decide how to deal with
24
+	// them correctly.
25
+	nonbumpCommits := []util.Commit{}
26
+	for _, commit := range commits {
27
+		if commit.DeclaresUpstreamChange() &&
28
+			!strings.HasPrefix(commit.Summary, "bump(") {
29
+			nonbumpCommits = append(nonbumpCommits, commit)
30
+		}
31
+	}
32
+
33
+	errs := []string{}
34
+	for _, validate := range AllValidators {
35
+		err := validate(nonbumpCommits)
36
+		if err != nil {
37
+			errs = append(errs, err.Error())
38
+		}
39
+	}
40
+
41
+	if len(errs) > 0 {
42
+		os.Stderr.WriteString(strings.Join(errs, "\n\n"))
43
+		os.Exit(2)
44
+	}
45
+}
0 46
new file mode 100644
... ...
@@ -0,0 +1,185 @@
0
+package main
1
+
2
+import (
3
+	"bytes"
4
+	"fmt"
5
+	"regexp"
6
+	"strings"
7
+	"text/template"
8
+
9
+	"github.com/openshift/origin/tools/rebasehelpers/util"
10
+)
11
+
12
+var CommitSummaryErrorTemplate = `
13
+The following UPSTREAM commits have invalid summaries:
14
+
15
+{{ range .Commits }}  [{{ .Sha }}] {{ .Summary }}
16
+{{ end }}
17
+UPSTREAM commit summaries should look like:
18
+
19
+  UPSTREAM: [non-kube-repo/name: ]<PR number|carry|drop>: description
20
+
21
+UPSTREAM commits which revert previous UPSTREAM commits should look like:
22
+
23
+  UPSTREAM: revert: <sha>: <normal upstream format>
24
+
25
+UPSTREAM commits are validated against the following regular expression:
26
+
27
+  {{ .Pattern }}
28
+
29
+Examples of valid summaries:
30
+
31
+  UPSTREAM: 12345: A kube fix
32
+  UPSTREAM: coreos/etcd: 12345: An etcd fix
33
+  UPSTREAM: <carry>: A carried kube change
34
+  UPSTREAM: <drop>: A dropped kube change
35
+  UPSTREAM: revert: abcd123: coreos/etcd: 12345: An etcd fix
36
+  UPSTREAM: k8s.io/heapster: 12345: A heapster fix
37
+
38
+`
39
+
40
+var AllValidators = []func([]util.Commit) error{
41
+	ValidateUpstreamCommitSummaries,
42
+	ValidateUpstreamCommitsWithoutGodepsChanges,
43
+	ValidateUpstreamCommitModifiesSingleGodepsRepo,
44
+	ValidateUpstreamCommitModifiesOnlyGodeps,
45
+	ValidateUpstreamCommitModifiesOnlyDeclaredGodepRepo,
46
+}
47
+
48
+// ValidateUpstreamCommitsWithoutGodepsChanges returns an error if any
49
+// upstream commits have no Godeps changes.
50
+func ValidateUpstreamCommitsWithoutGodepsChanges(commits []util.Commit) error {
51
+	problemCommits := []util.Commit{}
52
+	for _, commit := range commits {
53
+		if commit.HasGodepsChanges() && !commit.DeclaresUpstreamChange() {
54
+			problemCommits = append(problemCommits, commit)
55
+		}
56
+	}
57
+	if len(problemCommits) > 0 {
58
+		label := "The following commits contain Godeps changes but aren't declared as UPSTREAM"
59
+		msg := renderGodepFilesError(label, problemCommits, RenderOnlyGodepsFiles)
60
+		return fmt.Errorf(msg)
61
+	}
62
+	return nil
63
+}
64
+
65
+// ValidateUpstreamCommitModifiesSingleGodepsRepo returns an error if any
66
+// upstream commits have changes that span more than one Godeps repo.
67
+func ValidateUpstreamCommitModifiesSingleGodepsRepo(commits []util.Commit) error {
68
+	problemCommits := []util.Commit{}
69
+	for _, commit := range commits {
70
+		godepsChanges, err := commit.GodepsReposChanged()
71
+		if err != nil {
72
+			return err
73
+		}
74
+		if len(godepsChanges) > 1 {
75
+			problemCommits = append(problemCommits, commit)
76
+		}
77
+	}
78
+	if len(problemCommits) > 0 {
79
+		label := "The following UPSTREAM commits modify more than one repo in their changelist"
80
+		msg := renderGodepFilesError(label, problemCommits, RenderOnlyGodepsFiles)
81
+		return fmt.Errorf(msg)
82
+	}
83
+	return nil
84
+}
85
+
86
+// ValidateUpstreamCommitSummaries ensures that any commits which declare to
87
+// be upstream match the regular expressions for UPSTREAM summaries.
88
+func ValidateUpstreamCommitSummaries(commits []util.Commit) error {
89
+	problemCommits := []util.Commit{}
90
+	for _, commit := range commits {
91
+		if commit.DeclaresUpstreamChange() && !commit.MatchesUpstreamSummaryPattern() {
92
+			problemCommits = append(problemCommits, commit)
93
+		}
94
+	}
95
+	if len(problemCommits) > 0 {
96
+		tmpl, _ := template.New("problems").Parse(CommitSummaryErrorTemplate)
97
+		data := struct {
98
+			Pattern *regexp.Regexp
99
+			Commits []util.Commit
100
+		}{
101
+			Pattern: util.UpstreamSummaryPattern,
102
+			Commits: problemCommits,
103
+		}
104
+		buffer := &bytes.Buffer{}
105
+		tmpl.Execute(buffer, data)
106
+		return fmt.Errorf(buffer.String())
107
+	}
108
+	return nil
109
+}
110
+
111
+// ValidateUpstreamCommitModifiesOnlyGodeps ensures that any Godeps commits
112
+// modify ONLY Godeps files.
113
+func ValidateUpstreamCommitModifiesOnlyGodeps(commits []util.Commit) error {
114
+	problemCommits := []util.Commit{}
115
+	for _, commit := range commits {
116
+		if commit.HasGodepsChanges() && commit.HasNonGodepsChanges() {
117
+			problemCommits = append(problemCommits, commit)
118
+		}
119
+	}
120
+	if len(problemCommits) > 0 {
121
+		label := "The following UPSTREAM commits modify files outside Godeps"
122
+		msg := renderGodepFilesError(label, problemCommits, RenderAllFiles)
123
+		return fmt.Errorf(msg)
124
+	}
125
+	return nil
126
+}
127
+
128
+// ValidateUpstreamCommitModifiesOnlyDeclaredGodepRepo ensures that an
129
+// upstream commit only modifies the Godep repo the summary declares.
130
+func ValidateUpstreamCommitModifiesOnlyDeclaredGodepRepo(commits []util.Commit) error {
131
+	problemCommits := []util.Commit{}
132
+	for _, commit := range commits {
133
+		if commit.DeclaresUpstreamChange() {
134
+			declaredRepo, err := commit.DeclaredUpstreamRepo()
135
+			if err != nil {
136
+				return err
137
+			}
138
+			reposChanged, err := commit.GodepsReposChanged()
139
+			if err != nil {
140
+				return err
141
+			}
142
+			for _, changedRepo := range reposChanged {
143
+				if !strings.Contains(changedRepo, declaredRepo) {
144
+					problemCommits = append(problemCommits, commit)
145
+				}
146
+			}
147
+		}
148
+	}
149
+	if len(problemCommits) > 0 {
150
+		label := "The following UPSTREAM commits modify Godeps repos other than the repo the commit declares"
151
+		msg := renderGodepFilesError(label, problemCommits, RenderAllFiles)
152
+		return fmt.Errorf(msg)
153
+	}
154
+	return nil
155
+}
156
+
157
+type CommitFilesRenderOption int
158
+
159
+const (
160
+	RenderNoFiles CommitFilesRenderOption = iota
161
+	RenderOnlyGodepsFiles
162
+	RenderOnlyNonGodepsFiles
163
+	RenderAllFiles
164
+)
165
+
166
+// renderGodepFilesError formats commits and their file lists into readable
167
+// output prefixed with label.
168
+func renderGodepFilesError(label string, commits []util.Commit, opt CommitFilesRenderOption) string {
169
+	msg := fmt.Sprintf("%s:\n\n", label)
170
+	for _, commit := range commits {
171
+		msg += fmt.Sprintf("[%s] %s\n", commit.Sha, commit.Summary)
172
+		if opt == RenderNoFiles {
173
+			continue
174
+		}
175
+		for _, file := range commit.Files {
176
+			if opt == RenderAllFiles ||
177
+				(opt == RenderOnlyGodepsFiles && file.HasGodepsChanges()) ||
178
+				(opt == RenderOnlyNonGodepsFiles && !file.HasGodepsChanges()) {
179
+				msg += fmt.Sprintf("  - %s\n", file)
180
+			}
181
+		}
182
+	}
183
+	return msg
184
+}
0 185
new file mode 100644
... ...
@@ -0,0 +1,379 @@
0
+package main
1
+
2
+import (
3
+	"testing"
4
+
5
+	"github.com/openshift/origin/tools/rebasehelpers/util"
6
+)
7
+
8
+func TestValidateUpstreamCommitsWithoutGodepsChanges(t *testing.T) {
9
+	tests := []struct {
10
+		name          string
11
+		commits       []util.Commit
12
+		errorExpected bool
13
+	}{
14
+		{
15
+			name: "test 1",
16
+			commits: []util.Commit{
17
+				{
18
+					Sha:     "aaa0000",
19
+					Summary: "commit 1",
20
+					Files:   []util.File{"file1", "pkg/file2"},
21
+				},
22
+				{
23
+					Sha:     "aaa0001",
24
+					Summary: "commit 2",
25
+					Files:   []util.File{"Godeps/file1", "pkg/file2"},
26
+				},
27
+			},
28
+			errorExpected: true,
29
+		},
30
+		{
31
+			name: "test 2",
32
+			commits: []util.Commit{
33
+				{
34
+					Sha:     "aaa0000",
35
+					Summary: "commit 1",
36
+					Files:   []util.File{"file1", "pkg/file2"},
37
+				},
38
+				{
39
+					Sha:     "aaa0001",
40
+					Summary: "UPSTREAM: commit 2",
41
+					Files:   []util.File{"Godeps/file1", "pkg/file2"},
42
+				},
43
+			},
44
+			errorExpected: false,
45
+		},
46
+	}
47
+	for _, test := range tests {
48
+		t.Logf("evaluating test %q", test.name)
49
+		err := ValidateUpstreamCommitsWithoutGodepsChanges(test.commits)
50
+		if err != nil {
51
+			if test.errorExpected {
52
+				t.Logf("got expected error:\n%s", err)
53
+				continue
54
+			} else {
55
+				t.Fatalf("unexpected error:\n%s", err)
56
+			}
57
+		} else {
58
+			if test.errorExpected {
59
+				t.Fatalf("expected an error, got none")
60
+			}
61
+		}
62
+	}
63
+}
64
+
65
+func TestValidateUpstreamCommitModifiesSingleGodepsRepo(t *testing.T) {
66
+	tests := []struct {
67
+		name          string
68
+		commits       []util.Commit
69
+		errorExpected bool
70
+	}{
71
+		{
72
+			name: "test 1",
73
+			commits: []util.Commit{
74
+				{
75
+					Sha:     "aaa0000",
76
+					Summary: "commit 1",
77
+					Files:   []util.File{"file1", "pkg/file2"},
78
+				},
79
+				{
80
+					Sha:     "aaa0001",
81
+					Summary: "commit 2",
82
+					Files: []util.File{
83
+						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
84
+						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
85
+					},
86
+				},
87
+			},
88
+			errorExpected: false,
89
+		},
90
+		{
91
+			name: "test 2",
92
+			commits: []util.Commit{
93
+				{
94
+					Sha:     "aaa0000",
95
+					Summary: "commit 1",
96
+					Files:   []util.File{"file1", "pkg/file2"},
97
+				},
98
+				{
99
+					Sha:     "aaa0001",
100
+					Summary: "UPSTREAM: commit 2",
101
+					Files: []util.File{
102
+						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
103
+						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
104
+						"Godeps/_workspace/src/github.com/coreos/etcd/file",
105
+					},
106
+				},
107
+				{
108
+					Sha:     "aaa0002",
109
+					Summary: "UPSTREAM: commit 3",
110
+					Files: []util.File{
111
+						"Godeps/_workspace/src/k8s.io/heapster/file1",
112
+						"Godeps/_workspace/src/github.com/coreos/etcd/file1",
113
+					},
114
+				},
115
+			},
116
+			errorExpected: true,
117
+		},
118
+	}
119
+	for _, test := range tests {
120
+		t.Logf("evaluating test %q", test.name)
121
+		err := ValidateUpstreamCommitModifiesSingleGodepsRepo(test.commits)
122
+		if err != nil {
123
+			if test.errorExpected {
124
+				t.Logf("got expected error:\n%s", err)
125
+				continue
126
+			} else {
127
+				t.Fatalf("unexpected error:\n%s", err)
128
+			}
129
+		} else {
130
+			if test.errorExpected {
131
+				t.Fatalf("expected an error, got none")
132
+			}
133
+		}
134
+	}
135
+}
136
+
137
+func TestValidateUpstreamCommitModifiesOnlyGodeps(t *testing.T) {
138
+	tests := []struct {
139
+		name          string
140
+		commits       []util.Commit
141
+		errorExpected bool
142
+	}{
143
+		{
144
+			name: "test 1",
145
+			commits: []util.Commit{
146
+				{
147
+					Sha:     "aaa0000",
148
+					Summary: "commit 1",
149
+					Files:   []util.File{"file1", "pkg/file2"},
150
+				},
151
+				{
152
+					Sha:     "aaa0001",
153
+					Summary: "UPSTREAM: commit 2",
154
+					Files: []util.File{
155
+						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
156
+						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
157
+						"pkg/some_file",
158
+					},
159
+				},
160
+			},
161
+			errorExpected: true,
162
+		},
163
+		{
164
+			name: "test 2",
165
+			commits: []util.Commit{
166
+				{
167
+					Sha:     "aaa0000",
168
+					Summary: "commit 1",
169
+					Files:   []util.File{"file1", "pkg/file2"},
170
+				},
171
+				{
172
+					Sha:     "aaa0001",
173
+					Summary: "UPSTREAM: commit 2",
174
+					Files: []util.File{
175
+						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
176
+						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
177
+					},
178
+				},
179
+			},
180
+			errorExpected: false,
181
+		},
182
+	}
183
+	for _, test := range tests {
184
+		t.Logf("evaluating test %q", test.name)
185
+		err := ValidateUpstreamCommitModifiesOnlyGodeps(test.commits)
186
+		if err != nil {
187
+			if test.errorExpected {
188
+				t.Logf("got expected error:\n%s", err)
189
+				continue
190
+			} else {
191
+				t.Fatalf("unexpected error:\n%s", err)
192
+			}
193
+		} else {
194
+			if test.errorExpected {
195
+				t.Fatalf("expected an error, got none")
196
+			}
197
+		}
198
+	}
199
+}
200
+
201
+func TestValidateUpstreamCommitSummaries(t *testing.T) {
202
+	tests := []struct {
203
+		summary string
204
+		valid   bool
205
+	}{
206
+		{valid: true, summary: "UPSTREAM: 12345: a change"},
207
+		{valid: true, summary: "UPSTREAM: k8s.io/heapster: 12345: a change"},
208
+		{valid: true, summary: "UPSTREAM: <carry>: a change"},
209
+		{valid: true, summary: "UPSTREAM: <drop>: a change"},
210
+		{valid: true, summary: "UPSTREAM: coreos/etcd: <carry>: a change"},
211
+		{valid: true, summary: "UPSTREAM: coreos/etcd: <drop>: a change"},
212
+		{valid: true, summary: "UPSTREAM: revert: abcd123: 12345: a change"},
213
+		{valid: true, summary: "UPSTREAM: revert: abcd123: k8s.io/heapster: 12345: a change"},
214
+		{valid: true, summary: "UPSTREAM: revert: abcd123: <carry>: a change"},
215
+		{valid: true, summary: "UPSTREAM: revert: abcd123: <drop>: a change"},
216
+		{valid: true, summary: "UPSTREAM: revert: abcd123: coreos/etcd: <carry>: a change"},
217
+		{valid: true, summary: "UPSTREAM: revert: abcd123: coreos/etcd: <drop>: a change"},
218
+		{valid: false, summary: "UPSTREAM: whoopsie daisy"},
219
+	}
220
+	for _, test := range tests {
221
+		commit := util.Commit{Summary: test.summary, Sha: "abcd000"}
222
+		err := ValidateUpstreamCommitSummaries([]util.Commit{commit})
223
+		if err != nil {
224
+			if test.valid {
225
+				t.Fatalf("unexpected error:\n%s", err)
226
+			} else {
227
+				t.Logf("got expected error:\n%s", err)
228
+			}
229
+		} else {
230
+			if !test.valid {
231
+				t.Fatalf("expected an error, got none; summary: %s", test.summary)
232
+			}
233
+		}
234
+	}
235
+}
236
+
237
+func TestValidateUpstreamCommitModifiesOnlyDeclaredGodepRepo(t *testing.T) {
238
+	tests := []struct {
239
+		name          string
240
+		commits       []util.Commit
241
+		errorExpected bool
242
+	}{
243
+		{
244
+			name: "test 1",
245
+			commits: []util.Commit{
246
+				{
247
+					Sha:     "aaa0000",
248
+					Summary: "commit 1",
249
+					Files:   []util.File{"file1", "pkg/file2"},
250
+				},
251
+				{
252
+					Sha:     "aaa0001",
253
+					Summary: "UPSTREAM: coreos/etcd: 12345: a change",
254
+					Files: []util.File{
255
+						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
256
+						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
257
+						"Godeps/_workspace/src/github.com/coreos/etcd/file1",
258
+					},
259
+				},
260
+			},
261
+			errorExpected: true,
262
+		},
263
+		{
264
+			name: "test 2",
265
+			commits: []util.Commit{
266
+				{
267
+					Sha:     "aaa0001",
268
+					Summary: "UPSTREAM: coreos/etcd: 12345: a change",
269
+					Files: []util.File{
270
+						"Godeps/_workspace/src/github.com/coreos/etcd/file1",
271
+						"Godeps/_workspace/src/github.com/coreos/etcd/file2",
272
+					},
273
+				},
274
+			},
275
+			errorExpected: false,
276
+		},
277
+		{
278
+			name: "test three segments",
279
+			commits: []util.Commit{
280
+				{
281
+					Sha:     "aaa0001",
282
+					Summary: "UPSTREAM: coreos/etcd: 12345: a change",
283
+					Files: []util.File{
284
+						"Godeps/_workspace/src/github.com/coreos/etcd/a/file1",
285
+						"Godeps/_workspace/src/github.com/coreos/etcd/b/file2",
286
+					},
287
+				},
288
+			},
289
+			errorExpected: false,
290
+		},
291
+		{
292
+			name: "test 3",
293
+			commits: []util.Commit{
294
+				{
295
+					Sha:     "aaa0001",
296
+					Summary: "UPSTREAM: 12345: a change",
297
+					Files: []util.File{
298
+						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
299
+						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
300
+					},
301
+				},
302
+			},
303
+			errorExpected: false,
304
+		},
305
+		{
306
+			name: "test 4",
307
+			commits: []util.Commit{
308
+				{
309
+					Sha:     "aaa0001",
310
+					Summary: "UPSTREAM: 12345: a change",
311
+					Files: []util.File{
312
+						"Godeps/_workspace/src/github.com/coreos/etcd/file1",
313
+						"Godeps/_workspace/src/github.com/coreos/etcd/file2",
314
+					},
315
+				},
316
+			},
317
+			errorExpected: true,
318
+		},
319
+		{
320
+			name: "test 5",
321
+			commits: []util.Commit{
322
+				{
323
+					Sha:     "aaa0001",
324
+					Summary: "UPSTREAM: revert: abcd000: 12345: a change",
325
+					Files: []util.File{
326
+						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
327
+						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
328
+					},
329
+				},
330
+			},
331
+			errorExpected: false,
332
+		},
333
+		{
334
+			name: "test 6",
335
+			commits: []util.Commit{
336
+				{
337
+					Sha:     "aaa0001",
338
+					Summary: "UPSTREAM: revert: abcd000: coreos/etcd: 12345: a change",
339
+					Files: []util.File{
340
+						"Godeps/_workspace/src/k8s.io/kubernetes/file1",
341
+						"Godeps/_workspace/src/k8s.io/kubernetes/file2",
342
+					},
343
+				},
344
+			},
345
+			errorExpected: true,
346
+		},
347
+		{
348
+			name: "test 7",
349
+			commits: []util.Commit{
350
+				{
351
+					Sha:     "aaa0001",
352
+					Summary: "UPSTREAM: revert: abcd000: coreos/etcd: 12345: a change",
353
+					Files: []util.File{
354
+						"Godeps/_workspace/src/github.com/coreos/etcd/file1",
355
+						"Godeps/_workspace/src/github.com/coreos/etcd/file2",
356
+					},
357
+				},
358
+			},
359
+			errorExpected: false,
360
+		},
361
+	}
362
+	for _, test := range tests {
363
+		t.Logf("evaluating test %q", test.name)
364
+		err := ValidateUpstreamCommitModifiesOnlyDeclaredGodepRepo(test.commits)
365
+		if err != nil {
366
+			if test.errorExpected {
367
+				t.Logf("got expected error:\n%s", err)
368
+				continue
369
+			} else {
370
+				t.Fatalf("unexpected error:\n%s", err)
371
+			}
372
+		} else {
373
+			if test.errorExpected {
374
+				t.Fatalf("expected an error, got none")
375
+			}
376
+		}
377
+	}
378
+}
0 379
new file mode 100644
... ...
@@ -0,0 +1,200 @@
0
+package util
1
+
2
+import (
3
+	"bytes"
4
+	"fmt"
5
+	"os"
6
+	"os/exec"
7
+	"regexp"
8
+	"strings"
9
+)
10
+
11
+var UpstreamSummaryPattern = regexp.MustCompile(`UPSTREAM: (revert: [a-f0-9]{7,}: )?(([\w\.-]+\/[\w-]+)?: )?(\d+:|<carry>:|<drop>:)`)
12
+
13
+// supportedHosts maps source hosts to the number of path segments that
14
+// represent the account/repo for that host. This is necessary because we
15
+// can't tell just by looking at an import path whether the repo is identified
16
+// by the first 2 or 3 path segments.
17
+//
18
+// If dependencies are introduced from new hosts, they'll need to be added
19
+// here.
20
+var SupportedHosts = map[string]int{
21
+	"bitbucket.org":     3,
22
+	"code.google.com":   3,
23
+	"github.com":        3,
24
+	"golang.org":        3,
25
+	"google.golang.org": 2,
26
+	"gopkg.in":          2,
27
+	"k8s.io":            2,
28
+	"speter.net":        2,
29
+}
30
+
31
+type Commit struct {
32
+	Sha     string
33
+	Summary string
34
+	Files   []File
35
+}
36
+
37
+func (c Commit) DeclaresUpstreamChange() bool {
38
+	return strings.HasPrefix(strings.ToLower(c.Summary), "upstream")
39
+}
40
+
41
+func (c Commit) MatchesUpstreamSummaryPattern() bool {
42
+	return UpstreamSummaryPattern.MatchString(c.Summary)
43
+}
44
+
45
+func (c Commit) DeclaredUpstreamRepo() (string, error) {
46
+	if !c.DeclaresUpstreamChange() {
47
+		return "", fmt.Errorf("commit declares no upstream changes")
48
+	}
49
+	if !c.MatchesUpstreamSummaryPattern() {
50
+		return "", fmt.Errorf("commit doesn't match the upstream commit summary pattern")
51
+	}
52
+	groups := UpstreamSummaryPattern.FindStringSubmatch(c.Summary)
53
+	repo := groups[3]
54
+	if len(repo) == 0 {
55
+		repo = "k8s.io/kubernetes"
56
+	}
57
+	return repo, nil
58
+}
59
+
60
+func (c Commit) HasGodepsChanges() bool {
61
+	for _, file := range c.Files {
62
+		if file.HasGodepsChanges() {
63
+			return true
64
+		}
65
+	}
66
+	return false
67
+}
68
+
69
+func (c Commit) HasNonGodepsChanges() bool {
70
+	for _, file := range c.Files {
71
+		if !file.HasGodepsChanges() {
72
+			return true
73
+		}
74
+	}
75
+	return false
76
+}
77
+
78
+func (c Commit) GodepsReposChanged() ([]string, error) {
79
+	repos := map[string]struct{}{}
80
+	for _, file := range c.Files {
81
+		if !file.HasGodepsChanges() {
82
+			continue
83
+		}
84
+		repo, err := file.GodepsRepoChanged()
85
+		if err != nil {
86
+			return nil, fmt.Errorf("problem with file %q in commit %s: %s", file, c.Sha, err)
87
+		}
88
+		repos[repo] = struct{}{}
89
+	}
90
+	changed := []string{}
91
+	for repo := range repos {
92
+		changed = append(changed, repo)
93
+	}
94
+	return changed, nil
95
+}
96
+
97
+type File string
98
+
99
+func (f File) HasGodepsChanges() bool {
100
+	return strings.HasPrefix(string(f), "Godeps")
101
+}
102
+
103
+func (f File) GodepsRepoChanged() (string, error) {
104
+	if !f.HasGodepsChanges() {
105
+		return "", fmt.Errorf("file doesn't appear to be a Godeps change")
106
+	}
107
+	// Find the _workspace path segment index.
108
+	workspaceIdx := -1
109
+	parts := strings.Split(string(f), string(os.PathSeparator))
110
+	for i, part := range parts {
111
+		if part == "_workspace" {
112
+			workspaceIdx = i
113
+			break
114
+		}
115
+	}
116
+	// Godeps path struture assumption: Godeps/_workspace/src/...
117
+	if workspaceIdx == -1 || len(parts) < (workspaceIdx+3) {
118
+		return "", fmt.Errorf("file doesn't appear to be a Godeps workspace path")
119
+	}
120
+	// Deal with repos which could be identified by either 2 or 3 path segments.
121
+	host := parts[workspaceIdx+2]
122
+	segments := -1
123
+	for supportedHost, count := range SupportedHosts {
124
+		if host == supportedHost {
125
+			segments = count
126
+			break
127
+		}
128
+	}
129
+	if segments == -1 {
130
+		return "", fmt.Errorf("file modifies an unsupported repo host %q", host)
131
+	}
132
+	switch segments {
133
+	case 2:
134
+		return fmt.Sprintf("%s/%s", host, parts[workspaceIdx+3]), nil
135
+	case 3:
136
+		return fmt.Sprintf("%s/%s/%s", host, parts[workspaceIdx+3], parts[workspaceIdx+4]), nil
137
+	}
138
+	return "", fmt.Errorf("file modifies an unsupported repo host %q", host)
139
+}
140
+
141
+func CommitsBetween(a, b string) ([]Commit, error) {
142
+	commits := []Commit{}
143
+	stdout, _, err := run("git", "log", "--oneline", fmt.Sprintf("%s..%s", a, b))
144
+	if err != nil {
145
+		return nil, fmt.Errorf("error executing git log: %s", err)
146
+	}
147
+	for _, log := range strings.Split(stdout, "\n") {
148
+		if len(log) == 0 {
149
+			continue
150
+		}
151
+		commit, err := NewCommitFromOnelineLog(log)
152
+		if err != nil {
153
+			return nil, err
154
+		}
155
+		commits = append(commits, commit)
156
+	}
157
+	return commits, nil
158
+}
159
+
160
+func NewCommitFromOnelineLog(log string) (Commit, error) {
161
+	var commit Commit
162
+	parts := strings.Split(log, " ")
163
+	if len(parts) < 2 {
164
+		return commit, fmt.Errorf("invalid log entry: %s", log)
165
+	}
166
+	commit.Sha = parts[0]
167
+	commit.Summary = strings.Join(parts[1:], " ")
168
+	files, err := filesInCommit(commit.Sha)
169
+	if err != nil {
170
+		return commit, err
171
+	}
172
+	commit.Files = files
173
+	return commit, nil
174
+}
175
+
176
+func filesInCommit(sha string) ([]File, error) {
177
+	files := []File{}
178
+	stdout, _, err := run("git", "diff-tree", "--no-commit-id", "--name-only", "-r", sha)
179
+	if err != nil {
180
+		return nil, err
181
+	}
182
+	for _, filename := range strings.Split(stdout, "\n") {
183
+		if len(filename) == 0 {
184
+			continue
185
+		}
186
+		files = append(files, File(filename))
187
+	}
188
+	return files, nil
189
+}
190
+
191
+func run(args ...string) (string, string, error) {
192
+	cmd := exec.Command(args[0], args[1:]...)
193
+	var stdout bytes.Buffer
194
+	var stderr bytes.Buffer
195
+	cmd.Stdout = &stdout
196
+	cmd.Stderr = &stderr
197
+	err := cmd.Run()
198
+	return stdout.String(), stderr.String(), err
199
+}