forked from oppia/oppia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommon.py
172 lines (136 loc) · 6.27 KB
/
common.py
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
168
169
170
171
172
# Copyright 2014 The Oppia Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Common utility functions and classes used by multiple Python scripts."""
import os
import subprocess
RELEASE_BRANCH_NAME_PREFIX = 'release-'
def ensure_directory_exists(d):
"""Creates the given directory if it does not already exist."""
if not os.path.exists(d):
os.makedirs(d)
def require_cwd_to_be_oppia(allow_deploy_dir=False):
"""Ensures that the current working directory ends in 'oppia'.
If allow_deploy_dir is True, this also allows the cwd to be a directory
called 'deploy-*' which is a sibling of the oppia/ directory.
"""
is_oppia_dir = os.getcwd().endswith('oppia')
current_dirname = os.path.basename(os.path.normpath(os.getcwd()))
is_deploy_dir = (
current_dirname.startswith('deploy-') and
os.path.isdir(os.path.join(os.getcwd(), '..', 'oppia')))
if is_oppia_dir or (allow_deploy_dir and is_deploy_dir):
return
raise Exception('Please run this script from the oppia/ directory.')
def open_new_tab_in_browser_if_possible(url):
"""Opens the given URL in a new browser tab, if possible."""
browser_cmds = ['chromium-browser', 'google-chrome', 'firefox']
for cmd in browser_cmds:
if subprocess.call(['which', cmd]) == 0:
subprocess.call([cmd, url])
return
print '******************************************************************'
print 'WARNING: Unable to open browser. Please manually open the following '
print 'URL in a browser window, then press Enter to confirm.'
print ''
print ' %s' % url
print ''
print 'NOTE: To get rid of this message, open scripts/common.py and fix'
print 'the function open_new_tab_in_browser_if_possible() to work on your'
print 'system.'
raw_input()
def get_remote_alias(remote_url):
"""Finds the correct alias for the given remote repository URL."""
git_remote_output = subprocess.check_output(
['git', 'remote', '-v']).split('\n')
remote_alias = None
for line in git_remote_output:
if remote_url in line:
remote_alias = line.split()[0]
if remote_alias is None:
raise Exception(
'ERROR: There is no existing remote alias for the %s repo.'
% remote_url)
return remote_alias
def verify_local_repo_is_clean():
"""Checks that the local Git repo is clean."""
git_status_output = subprocess.check_output(
['git', 'status']).strip().split('\n')
branch_is_clean_message_1 = 'nothing to commit, working directory clean'
branch_is_clean_message_2 = 'nothing to commit, working tree clean'
if (
not branch_is_clean_message_1 in git_status_output and
not branch_is_clean_message_2 in git_status_output):
raise Exception(
'ERROR: This script should be run from a clean branch.')
def get_current_branch_name():
"""Get the current branch name."""
git_status_output = subprocess.check_output(
['git', 'status']).strip().split('\n')
branch_message_prefix = 'On branch '
git_status_first_line = git_status_output[0]
assert git_status_first_line.startswith(branch_message_prefix)
return git_status_first_line[len(branch_message_prefix):]
def is_current_branch_a_release_branch():
"""Returns whether the current branch is a release branch.
Returns:
bool. Whether the current branch is a release branch.
"""
current_branch_name = get_current_branch_name()
return current_branch_name.startswith(RELEASE_BRANCH_NAME_PREFIX)
def verify_current_branch_name(expected_branch_name):
"""Checks that the user is on the expected branch."""
if get_current_branch_name() != expected_branch_name:
raise Exception(
'ERROR: This script can only be run from the "%s" branch.' %
expected_branch_name)
def ensure_release_scripts_folder_exists_and_is_up_to_date():
"""Checks that the release-scripts folder exists and is up-to-date."""
parent_dirpath = os.path.join(os.getcwd(), os.pardir)
release_scripts_dirpath = os.path.join(parent_dirpath, 'release-scripts')
# If the release-scripts folder does not exist, set it up.
if not os.path.isdir(release_scripts_dirpath):
with CD(parent_dirpath):
# Taken from the "Check your SSH section" at
# https://help.github.com/articles/error-repository-not-found/
_, stderr = subprocess.Popen(
['ssh', '-T', 'git@github.com'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE).communicate()
if 'You\'ve successfully authenticated' not in stderr:
raise Exception(
'You need SSH access to GitHub. See the '
'"Check your SSH access" section here and follow the '
'instructions: '
'https://help.github.com/articles/'
'error-repository-not-found/#check-your-ssh-access')
subprocess.call([
'git', 'clone',
'git@github.com:oppia/release-scripts.git'])
with CD(release_scripts_dirpath):
verify_local_repo_is_clean()
verify_current_branch_name('master')
# Update the local repo.
remote_alias = get_remote_alias(
'git@github.com:oppia/release-scripts.git')
subprocess.call(['git', 'pull', remote_alias])
class CD(object):
"""Context manager for changing the current working directory."""
def __init__(self, new_path):
self.new_path = new_path
self.saved_path = None
def __enter__(self):
self.saved_path = os.getcwd()
os.chdir(self.new_path)
def __exit__(self, etype, value, traceback):
os.chdir(self.saved_path)