~nskaggs/juju-ci-tools/add-assess-terms

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())