897.2.1
by Martin Packman
Simple build and test script for merge gating go projects using git |
1 |
#!/usr/bin/python
|
2 |
"""Merge gating script for git go projects."""
|
|
3 |
||
4 |
from __future__ import print_function |
|
5 |
||
6 |
import argparse |
|
7 |
import os |
|
8 |
import subprocess |
|
9 |
import sys |
|
10 |
||
11 |
from utility import ( |
|
909.1.1
by Martin Packman
Use print_now to flush output between subprocess calls that inherit stdout |
12 |
print_now, |
897.2.1
by Martin Packman
Simple build and test script for merge gating go projects using git |
13 |
temp_dir, |
14 |
)
|
|
15 |
||
16 |
||
17 |
class SubcommandError(Exception): |
|
18 |
||
19 |
def __init__(self, command, subcommand, error): |
|
20 |
self.command = command |
|
21 |
self.subcommand = subcommand |
|
22 |
self.error = error |
|
23 |
||
24 |
def __str__(self): |
|
25 |
return "Subprocess {} {} failed with code {}".format( |
|
26 |
self.command, self.subcommand, self.error.returncode) |
|
27 |
||
28 |
||
29 |
class SubcommandRunner(object): |
|
30 |
||
31 |
def __init__(self, command, environ=None): |
|
32 |
self.command = command |
|
33 |
self.subprocess_kwargs = {} |
|
34 |
if environ is not None: |
|
35 |
self.subprocess_kwargs["env"] = environ |
|
36 |
||
37 |
def __call__(self, subcommand, *args): |
|
38 |
cmdline = [self.command, subcommand] |
|
39 |
cmdline.extend(args) |
|
40 |
try: |
|
41 |
subprocess.check_call(cmdline, **self.subprocess_kwargs) |
|
42 |
except subprocess.CalledProcessError as e: |
|
43 |
raise SubcommandError(self.command, subcommand, e) |
|
44 |
||
45 |
||
909.1.2
by Martin Packman
Clean up argument handling and behaviours |
46 |
def go_test(args, gopath): |
897.2.1
by Martin Packman
Simple build and test script for merge gating go projects using git |
47 |
"""Download, build and test a go package."""
|
48 |
goenv = dict(os.environ) |
|
49 |
goenv["GOPATH"] = gopath |
|
50 |
go = SubcommandRunner("go", goenv) |
|
51 |
git = SubcommandRunner("git") |
|
1178.1.1
by Nate Finch
add support for feature branches on gopkg.in branches |
52 |
|
1186.1.1
by Martin Packman
Apply new feature branch logic for gating script with --feature-branch arg only |
53 |
final_project = args.project |
54 |
if args.feature_branch: |
|
55 |
final_project = from_feature_dir(args.project) |
|
56 |
||
57 |
project_ellipsis = final_project + "/..." |
|
58 |
directory = os.path.join(gopath, "src", final_project) |
|
1178.1.1
by Nate Finch
add support for feature branches on gopkg.in branches |
59 |
|
1079.1.1
by Martin Packman
Add new --tsv-path argument for git_gate script |
60 |
if args.tsv_path: |
61 |
print_now("Getting and installing godeps") |
|
1540.2.1
by Nicholas Skaggs
update godeps location |
62 |
go("get", "-v", "-d", "github.com/rogpeppe/godeps/...") |
63 |
go("install", "github.com/rogpeppe/godeps/...") |
|
909.1.2
by Martin Packman
Clean up argument handling and behaviours |
64 |
if args.project_url: |
1186.1.1
by Martin Packman
Apply new feature branch logic for gating script with --feature-branch arg only |
65 |
print_now("Cloning {} from {}".format(final_project, args.project_url)) |
909.1.2
by Martin Packman
Clean up argument handling and behaviours |
66 |
git("clone", args.project_url, directory) |
1091.4.1
by James Tunnicliffe
Merged upstream |
67 |
if args.go_get_all and not (args.project_url and args.merge_url): |
909.1.2
by Martin Packman
Clean up argument handling and behaviours |
68 |
print_now("Getting {} and dependencies using go".format(args.project)) |
69 |
go("get", "-v", "-d", "-t", project_ellipsis) |
|
897.2.1
by Martin Packman
Simple build and test script for merge gating go projects using git |
70 |
os.chdir(directory) |
909.1.2
by Martin Packman
Clean up argument handling and behaviours |
71 |
if args.project_ref: |
72 |
print_now("Switching repository to {}".format(args.project_ref)) |
|
73 |
git("checkout", args.project_ref) |
|
74 |
if args.merge_url: |
|
75 |
print_now("Merging {} ref {}".format(args.merge_url, args.merge_ref)) |
|
76 |
git("fetch", args.merge_url, args.merge_ref) |
|
77 |
git("merge", "--no-ff", "-m", "Merged " + args.merge_ref, "FETCH_HEAD") |
|
1091.4.1
by James Tunnicliffe
Merged upstream |
78 |
if args.go_get_all: |
79 |
print_now("Updating {} dependencies using go".format(args.project)) |
|
80 |
go("get", "-v", "-d", "-t", project_ellipsis) |
|
909.1.2
by Martin Packman
Clean up argument handling and behaviours |
81 |
if args.dependencies: |
82 |
for dep in args.dependencies: |
|
83 |
print_now("Getting {} and dependencies using go".format(dep)) |
|
84 |
go("get", "-v", "-d", dep) |
|
1079.1.1
by Martin Packman
Add new --tsv-path argument for git_gate script |
85 |
if args.tsv_path: |
1190.1.1
by Martin Packman
Make --tsv-path relative to project rather than to /home/martin/go/src |
86 |
tsv_path = os.path.join(gopath, "src", final_project, args.tsv_path) |
1079.1.1
by Martin Packman
Add new --tsv-path argument for git_gate script |
87 |
print_now("Getting dependencies using godeps from {}".format(tsv_path)) |
88 |
godeps = SubcommandRunner(os.path.join(gopath, "bin", "godeps"), goenv) |
|
89 |
godeps("-u", tsv_path) |
|
909.1.2
by Martin Packman
Clean up argument handling and behaviours |
90 |
go("build", project_ellipsis) |
91 |
go("test", project_ellipsis) |
|
897.2.1
by Martin Packman
Simple build and test script for merge gating go projects using git |
92 |
|
93 |
||
1178.1.2
by Nate Finch
rename to from_feature_dir and add tests |
94 |
def from_feature_dir(directory): |
1178.1.1
by Nate Finch
add support for feature branches on gopkg.in branches |
95 |
"""
|
96 |
For feature branches on repos that are versioned with gopkg.in, we need to
|
|
97 |
do some special handling, since the test code expects the branch name to be
|
|
98 |
appended to the reponame with a ".". However, for a feature branch, the
|
|
99 |
branchname is different than the base gopkg.in branch. To account for
|
|
100 |
this, we use the convention of base_branch_name.featurename, and thus this
|
|
101 |
code can know that it needs to strip out the featurename when locating the
|
|
102 |
code on disk.
|
|
103 |
||
104 |
Thus, the feature branch off of gopkg.in/juju/charm.v6 would be a branch
|
|
105 |
named charm.v6.myfeature, which should end up in
|
|
106 |
$GOPATH/src/gokpg.in/juju/charm.v6
|
|
107 |
"""
|
|
1178.1.2
by Nate Finch
rename to from_feature_dir and add tests |
108 |
name = os.path.basename(directory) |
109 |
parts = name.split(".") |
|
1178.1.1
by Nate Finch
add support for feature branches on gopkg.in branches |
110 |
if len(parts) == 3: |
1178.1.2
by Nate Finch
rename to from_feature_dir and add tests |
111 |
return directory[:-len(parts[2]) - 1] |
1178.1.1
by Nate Finch
add support for feature branches on gopkg.in branches |
112 |
return directory |
113 |
||
114 |
||
897.2.1
by Martin Packman
Simple build and test script for merge gating go projects using git |
115 |
def parse_args(args=None): |
116 |
"""Parse arguments for gating script."""
|
|
117 |
parser = argparse.ArgumentParser() |
|
118 |
project_group = parser.add_argument_group() |
|
906.2.3
by John George
Drive-by lint cleanup. |
119 |
project_group.add_argument( |
1091.4.1
by James Tunnicliffe
Merged upstream |
120 |
"--keep", action="store_true", |
121 |
help="Do not remove working dir after testing.") |
|
122 |
project_group.add_argument( |
|
906.2.3
by John George
Drive-by lint cleanup. |
123 |
"--project", required=True, help="Go import path of package to test.") |
124 |
project_group.add_argument( |
|
125 |
"--project-url", help="URL to git repository of package.") |
|
126 |
project_group.add_argument( |
|
127 |
"--project-ref", help="Branch name or tag to use as basis.") |
|
1186.1.1
by Martin Packman
Apply new feature branch logic for gating script with --feature-branch arg only |
128 |
project_group.add_argument( |
129 |
"--feature-branch", action="store_true", |
|
130 |
help="Use special handling for pending feature branches.") |
|
897.2.1
by Martin Packman
Simple build and test script for merge gating go projects using git |
131 |
merge_group = parser.add_argument_group() |
906.2.3
by John George
Drive-by lint cleanup. |
132 |
merge_group.add_argument( |
133 |
"--merge-url", help="URL to git repository to merge before testing.") |
|
134 |
merge_group.add_argument( |
|
135 |
"--merge-ref", default="HEAD", |
|
897.2.1
by Martin Packman
Simple build and test script for merge gating go projects using git |
136 |
help="Branch name or tag to merge before testing.") |
137 |
dep_group = parser.add_mutually_exclusive_group() |
|
906.2.3
by John George
Drive-by lint cleanup. |
138 |
dep_group.add_argument( |
909.1.2
by Martin Packman
Clean up argument handling and behaviours |
139 |
"--dependencies", nargs="+", |
140 |
help="Any number of package import paths needed for build or testing.") |
|
141 |
dep_group.add_argument( |
|
142 |
"--go-get-all", action="store_true", |
|
897.2.1
by Martin Packman
Simple build and test script for merge gating go projects using git |
143 |
help="Go import path of package needed to for build or testing.") |
1079.1.1
by Martin Packman
Add new --tsv-path argument for git_gate script |
144 |
dep_group.add_argument( |
145 |
"--tsv-path", |
|
1190.1.1
by Martin Packman
Make --tsv-path relative to project rather than to /home/martin/go/src |
146 |
help="Path to dependencies.tsv file relative to project dir.") |
909.1.2
by Martin Packman
Clean up argument handling and behaviours |
147 |
args = parser.parse_args(args) |
148 |
if args.project_url is None and not args.go_get_all: |
|
909.1.3
by Martin Packman
Use error not exit for argparse exclusion |
149 |
parser.error("Must supply either --project-url or --go-get-all") |
1186.1.1
by Martin Packman
Apply new feature branch logic for gating script with --feature-branch arg only |
150 |
if args.feature_branch and args.go_get_all: |
151 |
parser.error("Cannot use --feature-branch and --go-get-all together") |
|
909.1.2
by Martin Packman
Clean up argument handling and behaviours |
152 |
return args |
897.2.1
by Martin Packman
Simple build and test script for merge gating go projects using git |
153 |
|
154 |
||
155 |
def main(): |
|
156 |
args = parse_args() |
|
1091.4.1
by James Tunnicliffe
Merged upstream |
157 |
with temp_dir(keep=args.keep) as d: |
897.2.1
by Martin Packman
Simple build and test script for merge gating go projects using git |
158 |
try: |
909.1.2
by Martin Packman
Clean up argument handling and behaviours |
159 |
go_test(args, d) |
897.2.1
by Martin Packman
Simple build and test script for merge gating go projects using git |
160 |
except SubcommandError as err: |
161 |
print(err, file=sys.stderr) |
|
162 |
return 1 |
|
163 |
return 0 |
|
164 |
||
165 |
||
166 |
if __name__ == '__main__': |
|
167 |
sys.exit(main()) |