Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Automates deploying nightly builds to the dropbox shared folder and to each of Wrye Bash's nexus pages. Dropbox: - Uses dropbox's cli oauth to allow access to the shared folder; - The oauth process above can be overridden by providing your own access token; - Will deploy to the root of the shared folder - if previous builds are present it will delete them before uploading the new ones; - Test/Branch builds are supported by deploying to a subfolder via the '--branch' flag. Nexus: - Requires Google Chrome installed and an active nexus session in either Chrome, Firefox or Safari; - The appropriate chromedriver for the Chrome version is automatically downloaded; - The required nexus auth cookies ('member_id', 'pass_hash', and 'sid') are automatically retrieved for one of the above browsers; - Both chromedriver version and auth cookies can be overridden; - Selenium will run Chrome headless while deploying to prevent accidental user input; - If previous builds are present in the Updates section that match the current regex they will be deleted and replaced by the newer files. A log is kept of all verbose output (sensitive information is not logged). The path to this log can be changed via '--logfile'. The authentication credentials are stored in plain text to ease multiple deployments - this can be disabled via '--no-config'. For testing purposes, a dry run can be executed via '--dry-run'. The folder containing distributables to deploy can be changed via '--dist-folder'. It is recommended to always use 'deploy.py' to deploy - disabling deployment to either target can be via '--no-dropbox' or '--no-nexus'.
- Loading branch information
Showing
6 changed files
with
675 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#!/usr/bin/env python2 | ||
# -*- coding: utf-8 -*- | ||
|
||
# GPL License and Copyright Notice ============================================ | ||
# This file is part of Wrye Bash. | ||
# | ||
# Wrye Bash is free software; you can redistribute it and/or | ||
# modify it under the terms of the GNU General Public License | ||
# as published by the Free Software Foundation; either version 2 | ||
# of the License, or (at your option) any later version. | ||
# | ||
# Wrye Bash is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with Wrye Bash; if not, write to the Free Software Foundation, | ||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
# | ||
# Wrye Bash copyright (C) 2005-2009 Wrye, 2010-2019 Wrye Bash Team | ||
# https://github.com/wrye-bash | ||
# | ||
# ============================================================================= | ||
|
||
""" | ||
Deploy nightly builds. | ||
To deploy to dropbox you need a Dropbox account and access to the wrye bash | ||
shared folder in your dropbox. Optionally, you can override the regular oauth | ||
process with your own API access token via '--access-token'. Deploying test | ||
builds to a subfolder is also supported with '--branch'. | ||
To deploy to nexus you need to have Google Chrome/Chromium installed and be | ||
logged in to nexus in a browser [Supported: Chrome, Firefox, Safari]. The | ||
appropriate selenium driver and the needed auth cookies are automatically | ||
retrieved. If there are issues with this process, you can override the | ||
chromedriver version with '--driver-version' and the auth cookie values with | ||
'--member-id', '--pass-hash' and '--sid'. | ||
Unless '--no-config' is supplied, all values are saved to a | ||
configuration file at './deploy_config.json'. Values are | ||
stored as a dictionary with the format (keys in lowercase): | ||
'%ARGUMENT%': '%VALUE%' | ||
""" | ||
|
||
import argparse | ||
|
||
import deploy_dropbox | ||
import deploy_nexus | ||
import utils | ||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser( | ||
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter | ||
) | ||
utils.setup_deploy_parser(parser) | ||
parser.add_argument( | ||
"--no-dropbox", | ||
action="store_false", | ||
dest="dropbox", | ||
help="Do not deploy to dropbox.", | ||
) | ||
parser.add_argument( | ||
"--no-nexus", | ||
action="store_false", | ||
dest="nexus", | ||
help="Do not deploy to nexusmods.", | ||
) | ||
dropbox_parser = parser.add_argument_group("dropbox arguments") | ||
deploy_dropbox.setup_parser(dropbox_parser) | ||
nexus_parser = parser.add_argument_group("nexus arguments") | ||
deploy_nexus.setup_parser(nexus_parser) | ||
args = parser.parse_args() | ||
open(args.logfile, "w").close() | ||
if args.dropbox: | ||
deploy_dropbox.main(args) | ||
if args.nexus: | ||
deploy_nexus.main(args) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
#!/usr/bin/env python2 | ||
# -*- coding: utf-8 -*- | ||
|
||
# GPL License and Copyright Notice ============================================ | ||
# This file is part of Wrye Bash. | ||
# | ||
# Wrye Bash is free software; you can redistribute it and/or | ||
# modify it under the terms of the GNU General Public License | ||
# as published by the Free Software Foundation; either version 2 | ||
# of the License, or (at your option) any later version. | ||
# | ||
# Wrye Bash is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with Wrye Bash; if not, write to the Free Software Foundation, | ||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
# | ||
# Wrye Bash copyright (C) 2005-2009 Wrye, 2010-2019 Wrye Bash Team | ||
# https://github.com/wrye-bash | ||
# | ||
# ============================================================================= | ||
|
||
import argparse | ||
import json | ||
import logging | ||
import os | ||
import re | ||
|
||
import dropbox | ||
|
||
import utils | ||
|
||
LOGGER = logging.getLogger(__name__) | ||
|
||
# constants | ||
SHARED_FOLDER_ID = "4796182912" | ||
FILE_REGEX = r"Wrye Bash \d{3,}\.\d{12,12} - (Installer.exe|Python Source.7z|Standalone Executable.7z)" | ||
COMPILED = re.compile(FILE_REGEX) | ||
|
||
|
||
def setup_parser(parser): | ||
parser.add_argument( | ||
"-t", | ||
"--access-token", | ||
default=argparse.SUPPRESS, | ||
help="The dropbox API access token.\n" | ||
" To get your own access token\n" | ||
" go to https://www.dropbox.com/developers/apps\n" | ||
" register an app and generate your token.", | ||
) | ||
parser.add_argument( | ||
"-b", | ||
"--branch", | ||
default="", | ||
help="Upload a specific branch.\n" | ||
" Will upload to a separate folder\n" | ||
" within the shared folder.", | ||
) | ||
|
||
|
||
def remove_files(dbx, path, dry_run=False): | ||
# get all files in folder | ||
files = [] | ||
for entry in dbx.files_list_folder(path).entries: | ||
if isinstance(entry, dropbox.files.FileMetadata): | ||
files.append(entry.name) | ||
LOGGER.debug("Found '{}' under shared folder.".format(entry.name)) | ||
# delete the previous nightly files | ||
filtered = filter(COMPILED.match, files) | ||
for fname in filtered: | ||
fpath = path + "/" + fname | ||
if dry_run: | ||
LOGGER.info("Would remove '{}'.".format(fpath)) | ||
continue | ||
LOGGER.info("Removing '{}'...".format(fpath)) | ||
dbx.files_delete_v2(fpath) | ||
|
||
|
||
def upload_file(dbx, fpath, folder_path, dry_run=False): | ||
fname = os.path.basename(fpath) | ||
LOGGER.debug("Found '{}' under distributable folder.".format(fname)) | ||
if dry_run: | ||
LOGGER.info("Would upload '{}'.".format(os.path.relpath(fpath, os.getcwd()))) | ||
return | ||
LOGGER.info("Uploading '{}'...".format(os.path.relpath(fpath, os.getcwd()))) | ||
with open(fpath, "rb") as fopen: | ||
upload_path = folder_path + "/" + fname | ||
dbx.files_upload(fopen.read(), upload_path) | ||
|
||
|
||
def main(args): | ||
utils.setup_log(LOGGER, verbosity=args.verbosity, logfile=args.logfile) | ||
creds = utils.parse_deploy_credentials(args, ["access_token"], args.save_config) | ||
# setup dropbox instance | ||
dbx = dropbox.Dropbox(creds["access_token"]) | ||
shared_folder_path = dbx.sharing_get_folder_metadata(SHARED_FOLDER_ID).path_lower | ||
LOGGER.debug("Found shared folder path at '{}'.".format(shared_folder_path)) | ||
# create folder inside shared folder if needed for branch nightly | ||
if args.branch: | ||
shared_folder_path += "/" + args.branch | ||
try: | ||
dbx.files_create_folder_v2(shared_folder_path) | ||
except dropbox.exceptions.ApiError: | ||
pass | ||
LOGGER.debug( | ||
"Using branch folder '{}' at '{}'.".format(args.branch, shared_folder_path) | ||
) | ||
remove_files(dbx, shared_folder_path, args.dry_run) | ||
for fname in os.listdir(args.dist_folder): | ||
fpath = os.path.join(args.dist_folder, fname) | ||
if not os.path.isfile(fpath): | ||
continue | ||
upload_file(dbx, fpath, shared_folder_path, args.dry_run) | ||
|
||
|
||
if __name__ == "__main__": | ||
argparser = argparse.ArgumentParser() | ||
utils.setup_deploy_parser(argparser) | ||
setup_parser(argparser) | ||
parsed_args = argparser.parse_args() | ||
open(parsed_args.logfile, "w").close() | ||
main(parsed_args) |
Oops, something went wrong.
67eab34
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wrye-bash/bashers Requesting low-priority review on this.
If this is accepted, a few things so I won't forget:
I remembered I know a bit of javascript and fixed the "no-deleting" issue that selenium has. Keeping a link to the previous discussion at d38db40
67eab34
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @GandaG how do I make a dropbox app?
67eab34
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Utumno it's pretty simple. Once you're done, all that's left is changing the client id and secret on the script.
67eab34
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well I kinda made an app but not sure about security - should we have the cleintid and secret on the script? I guess not - so probably shouldn't be read from an ini file? On the other hand, if this is already working do we need an app? Or the shared folder id would be enough and then we don't need to worry about security (as only users with access to the shared folder and dropbox installed would be able to post files in there IIUC)
Or should I add you and Infernio to the app
Would be nice to add some docs to the scripts (that could be used as the argparser help too)
67eab34
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not the best with internet-y stuff but I tried to do some research on this back then.
You'll always need a dropbox app since you need to authenticate with a dropbox endpoint to prove it's you.
As for the id+secret, I'd say it mostly depends on whether you can have permissions on the app folder - I'll test that tomorrow. If you can set them, then you can clear us three for modifications and even if someone else were to use the app (which only allows connecting to that specific folder) wouldn't be able to do anything - no problem exposing id and secret.
If you can't though, that's a different story. If we're going with an 'App Folder' type app like you made then exposing the secret is super no bueno and we definitely need to control the app secret and pin it somewhere that's dev-only.
I also dont think you can whitelist users to the app, although that would solve the issue.
Sure about docs, didn't write anything there because I wasn't sure what to write about :P suggestions?
67eab34
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
67eab34
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From a quick google it seems sharing app folders is not allowed :/
You don't! :)
Well, that's true :P
Ok I think I know where you're going with this - you want to keep dragging the files to the local dropbox folder, don't you?! I'll let you know that automating this increases our efficiency by 93% by reducing finger stress from all the clicking and dragging and instead transforming it into the much more manageable cardiac stress from those 'oh my God please work this time' thoughts. Not to mention all the headaches it saved us with beta 4, we were literally uploading files faster than nexus could process them, and with my crappy internet to boot!
Not to mention that CI is on the horizon! And even though you denigrate its merits and drag its name through the mud, it is still a vital member of our future! You push for further infrastructure changes with no thought of their backbone. With tests fully fleshed out, who will run them after every commit? Us! Manually? Madness!
And we still have many changes to go through. Python 3, a proper virtualenv with package version locks, a packaging software that is not 10 years old. Every change brings us new opportunities to expand, maybe even to linux someday! But without proper infrastructure these changes will be costlier and costlier as time goes on and we sink into the void of manual labor.
You may look at this and see just an extra step to uploading files to dropbox, but I see the start of a bright future where the Wrye Bash devs only need to focus on code - a pre-commit hook ensures that all tests pass and backend is solid, a linter and a formatter ensure the code is up-to-standard; a CI server builds and tests our code in multiple OSs and at the end of a release cycle fully deploys our application to all necessary locations. And throughout all this, the humble dev is already picturing the heights that could be achieved in the next release.
Denying our devs the chance for this small improvement in their lives is a fair way to win the battle, but lose the war.
P.S.: I may have been watching too much UK parliament this week. Maybe.
67eab34
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
67eab34
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you like it? :P I felt inspired ahah
Well, the script DOES work right now, BUT you brought up a very valid point before that I, uh, totally had thought of before, obviously.
The app I registered is a 'Full Dropbox' so we could use/test via the existing shared folder. Since the secret is committed someone else could make an app using my registered app - while they wouldn't be able to modify the shared folder they could do some illegal stuff and put my account in trouble. I'm monitoring the number of registered users on the app console but still, I'd like a solution for this :D
We could pin the secret/id in the discord dev channel until we find a better place for it, I'll work on some way to locally store them.
RE: docs - I already documented the shared folder access here.
Aside from all this, there's one thing I've never been happy with, the "credentials" parsing. Any suggestions on this?