Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gruntworker.py - github.com/twbs/gruntworker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: ef8f0e6b5163d769c4ec3bb326ee2912b9ce5fed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/usr/bin/env python3
# coding=utf-8

from sys import exit, argv as _argv  # pylint: disable=W0622
from subprocess import check_call, check_output, DEVNULL, CalledProcessError
from shutil import copy, rmtree
from os import remove
from os.path import join as pathjoin, exists
from datetime import datetime

SHRINKWRAP_FILENAME = 'npm-shrinkwrap.json'
SHRINKWRAP_DIRS = ['test-infra', 'grunt']
SHRINKWRAP_FILEPATHS = [pathjoin(directory, SHRINKWRAP_FILENAME) for directory in SHRINKWRAP_DIRS]


def log(*args):
    now = datetime.now().replace(microsecond=0).isoformat(' ')
    print(now, "gruntworker: ", end='')
    print(*args, flush=True)


def run_expecting_success(cmd):
    log("\trunning:", b' '.join(cmd).decode('utf8', 'replace'))
    check_call(cmd, stdin=DEVNULL)


def run_for_output(cmd):
    log("\trunning:", b' '.join(cmd).decode('utf8', 'replace'))
    return check_output(cmd, input=b'')


def reset_to_primary_and_die(primary_branch):
    log("Attempting to reset current checkout & branch to local {}...".format(primary_branch))
    try:
        run_expecting_success([b'git', b'checkout', b'-f', primary_branch.encode('utf8')])
    except CalledProcessError:
        log("Error forcibly checking out {}; Failed!".format(primary_branch))
    exit(1)


def fetch_origin(primary_branch):
    log("Fetching from origin...")
    try:
        run_expecting_success([b'git', b'fetch', b'origin', ('+' + primary_branch).encode('utf8')])
    except CalledProcessError:
        log("Error fetching from origin; Failed!")
        exit(1)


def update_primary(primary_branch, to_commitish=b'FETCH_HEAD'):
    primary_bytes = primary_branch.encode('utf8')
    log("Setting local {0} to {1}...".format(primary_branch, to_commitish.decode('utf8', 'replace')))
    try:
        run_expecting_success([b'git', b'checkout', b'-q', b'-f', to_commitish])
        run_expecting_success([b'git', b'branch', b'-f', primary_bytes, to_commitish])
        run_expecting_success([b'git', b'checkout', b'-q', b'-f', primary_bytes])
    except CalledProcessError:
        log("Error setting local {0} to {1}!".format(primary_branch, to_commitish))
        reset_to_primary_and_die(primary_branch)


def update_npm():
    found = False
    shrinkwrap_filepath = None
    for shrinkwrap_filepath in SHRINKWRAP_FILEPATHS:
        if exists(shrinkwrap_filepath):
            found = True
            break
    if not found:
        log("No shrinkwrap file found!")
        log("Failed!")
        exit(1)
    try:
        copy(shrinkwrap_filepath, SHRINKWRAP_FILENAME)
    except (OSError, IOError):
        log("Error copying shrinkwrap file into place!")
        log("Failed!")
        exit(1)

    try:
        log("Pruning unnecessary npm modules...")
        run_expecting_success([b'npm', b'prune'])
        log("Installing/updating npm modules per npm-shrinkwrap.json ...")
        run_expecting_success([b'npm', b'install'])
    except CalledProcessError:
        log("Error performing npm operations!")
        log("Purging node_modules due to errors.")
        try:
            rmtree('./node_modules', ignore_errors=True)
        except (IOError, OSError) as io_err:
            log("Error purging node_modules: {!r}".format(io_err))
        else:
            log("Successfully purged node_modules.")
        log("Failed!")
        exit(1)
    finally:
        try:
            remove(SHRINKWRAP_FILENAME)
        except Exception:  # pylint: disable=W0703
            log("Error deleting copy of shrinkwrap file!")


def get_head_commit_sha():
    commit_sha = run_for_output([b'git', b'rev-parse', b'HEAD']).strip()
    if len(commit_sha) != 40:
        log("Got malformed commit SHA for HEAD:", commit_sha.decode('utf8'))
        log("Exiting due to insanity; Failed!")
        exit(1)
    return commit_sha


def grunt_or_err():
    log("Grunting...")
    try:
        run_expecting_success([b'grunt', b'dist', b'clean:docs', b'copy:docs'])
    except CalledProcessError:
        log("Error while grunting!")
        raise


def get_modified_files():
    output = run_for_output([b'git', b'status', b'-z', b'-uno', b'--ignore-submodules=all'])
    lines = output.split(b'\x00')
    return [line[3:] for line in lines if line[:2] == b' M']


def push_or_err(primary_branch):
    log("Pushing to origin...")
    try:
        run_expecting_success([b'git', b'push', b'origin', primary_branch.encode('utf8')])
    except CalledProcessError:
        log("Error pushing to origin!")
        raise


def main(primary_branch):
    orig_commit_sha = get_head_commit_sha()
    fetch_origin(primary_branch)
    update_primary(primary_branch)
    post_fetch_commit_sha = get_head_commit_sha()
    if post_fetch_commit_sha == orig_commit_sha:
        log("Fetch didn't change HEAD commit; Done.")
        return
    update_npm()
    try:
        grunt_or_err()
        modified_files = get_modified_files()
        if not modified_files:
            log("No files modified by grunt; Done.")
            return
        run_expecting_success([b'git', b'add', b'--'] + modified_files)
        run_expecting_success([b'git', b'commit', b'-m', b"automatic `grunt dist`\n\n[ci skip]"])
        push_or_err(primary_branch)
    except Exception:  # pylint: disable=W0703
        log("Resetting primary branch & checkout back to commit {} ...".format(post_fetch_commit_sha))
        update_primary(primary_branch, to_commitish=post_fetch_commit_sha)
        log("Failed!")
    else:
        log("Successfully pushed changes; Done.")


if __name__ == '__main__':
    _argv.pop()
    if len(_argv) != 1:
        log("USAGE: gruntworker.py <primary-branch-name>")
        exit(2)
    main(_argv[0])