-
Notifications
You must be signed in to change notification settings - Fork 1
/
autoupdate.py
executable file
·120 lines (98 loc) · 5.28 KB
/
autoupdate.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
#!/usr/bin/env python
import logging
import os
from psh_logging import outputError
from psh_utility import runCommand, SOURCE_OP_TOOLS_VERSION
def main():
"""
:return:
"""
updaters = {
'composer.json': {'command': 'composer update', 'lock': 'composer.lock'},
'Pipfile': {'command': 'pipenv update', 'lock': 'Pipfile.lock'},
'poetry.lock': {'command': 'poetry update --lock', 'lock': 'poetry.lock'},
'Gemfile': {'command': 'bundle update --all', 'lock': 'Gemfile.lock'},
'go.mod': {'command': 'go get -u ./... && go mod tidy', 'lock': 'go.sum go.mod'},
'package-lock.json': {'command': 'npm update', 'lock': 'package-lock.json'},
'yarn.lock': {'command': 'hash yarn >/dev/null 2>&1 && yarn upgrade || corepack yarn upgrade',
'lock': 'yarn.lock package.json'}
}
appFile = '.platform.app.yaml'
# @todo should this be a configurable message?
gitCommitMsg = 'Auto dependency updates via source operation'
def find_dependency_files(projectPath):
updateFiles = []
for (dirpath, dirnames, filenames) in os.walk(projectPath):
# do we have any updater files in this directory?
# @todo is there a way to combine this with the platform.app.yaml check?
toUpdate = list(set(filenames) & set(updaters.keys()))
if appFile in filenames and 0 < len(toUpdate):
# dirpath is the full path to the file, and we only want the relative path. if the two are equal, we
# dont even need it
if dirpath == projectPath:
dirpath = ''
else:
# otherwise we just want the relative bit
# full path location: /mnt/source/app
# path to composer.json: /mnt/source/app/drupal
# We only want to record `drupal`
# note, to add a cross-os-compatible ending directory slash, you path.join the path with empty. :shrug:
dirpath = dirpath.replace(os.path.join(projectPath, ''), '')
updateFiles += list(map(lambda file: os.path.join(dirpath, file), toUpdate))
return updateFiles
logging.info("Beginning update process using version v{} of Source Ops Toolkit...".format(SOURCE_OP_TOOLS_VERSION))
# get the path to our app. yes, it's different. in a source op container, we're in a different location
appPath = os.getenv('PLATFORM_SOURCE_DIR', os.getcwd())
# grab the list of dependency management files in the app project
appfiles = find_dependency_files(appPath)
if 1 > len(appfiles):
return outputError('Gathering dependency definition file(s)',
"I was unable to locate any dependency definition files")
doCommit = False
for fileFull in appfiles:
# split the file into the actual file & relative path
dependencyFilePath, dependencyFile = os.path.split(fileFull)
# When running `pipenv update` the update is being run inside a virtualenv. The default is to run with user set
# to `true` which results in the error
# `Can not perform a '--user' install. User site-packages are not visible in this virtualenv`
# We'll need to set the config for user to false before running the update
# @see
if 'Pipfile' == dependencyFile:
rCommand = 'export PIP_USER=0;' + updaters[dependencyFile]['command']
else:
rCommand = updaters[dependencyFile]['command']
logging.info("Found a {} file...".format(dependencyFile))
logging.info("Running {}".format(rCommand))
# run the update process
procUpdate = runCommand(rCommand, os.path.join(appPath, dependencyFilePath))
if not procUpdate['result']:
return outputError(rCommand, procUpdate['message'])
# now let's see if we have updates
logging.info("Seeing if there are any updates to commit.")
procStatus = runCommand('git status --porcelain=1', appPath)
if not procStatus['message']:
# no updates so nothing to add, not a failure, but we are done
logging.info("No updates available, nothing to commit. Exiting...")
return True
possibleUpdates = updaters[dependencyFile]['lock'].split()
for updatedFile in possibleUpdates:
if updatedFile in procStatus['message']:
lockFileLocation = procAdd = None
lockFileLocation = os.path.join(dependencyFilePath, updatedFile)
logging.info("Updates are available, adding {}...".format(lockFileLocation))
procAdd = runCommand('git add {}'.format(lockFileLocation), appPath)
if not procAdd['result']:
return outputError('git add', procAdd['message'])
else:
gitCommitMsg += '\nAdded updated {}'.format(lockFileLocation)
doCommit = True
if doCommit:
cmd = 'git commit -m "{}"'.format(gitCommitMsg)
procCommit = runCommand(cmd, appPath)
if not procCommit['result']:
return outputError('git commit', procCommit['message'])
else:
logging.info("Changes successfully committed.")
return True
if __name__ == '__main__':
main()