def set_dotted_attributes(build, unexpanded_local_config_values): """Save a local_config value given in dotted form to the local_config.json for the current build. Example use:: set_dotted_attribute(build, 'android.profile.sdk', '/opt/android-sdk-linux') """ from forge import build_config local_config_values = { expand_profile(build, k): v for k, v in unexpanded_local_config_values.items() } LOG.info('Updating local config with %s' % json.dumps(local_config_values, indent=4)) with cd(build.orig_wd): local_config = build_config.load_local() for attribute_name, value in local_config_values.items(): current_level = local_config crumbs = attribute_name.split('.') for k in crumbs[:-1]: if k not in current_level: current_level[k] = {} current_level = current_level[k] current_level[crumbs[-1]] = value build_config.save_local(local_config)
def _set_dotted_attribute(path_to_app, attribute_name, value): from forge import build_config LOG.info('Saving %s as %s in local_config.json' % (value, attribute_name)) with cd(path_to_app): local_config = build_config.load_local() current_level = local_config crumbs = attribute_name.split('.') for k in crumbs[:-1]: if k not in current_level: current_level[k] = {} current_level = current_level[k] current_level[crumbs[-1]] = value build_config.save_local(local_config)
def set_dotted_attribute(build, attribute_name, value): """Save a local_config value given in dotted form to the local_config.json for the current build. Example use:: set_dotted_attribute(build, 'android.profiles.DEFAULT.sdk', '/opt/android-sdk-linux') """ # TODO: would be good to not have to import the build_config module here, maybe emit an event instead? from forge import build_config LOG.info('Saving %s as %s in local_config.json' % (value, attribute_name)) with cd(build.orig_wd): local_config = build_config.load_local() current_level = local_config crumbs = attribute_name.split('.') for k in crumbs[:-1]: if k not in current_level: current_level[k] = {} current_level = current_level[k] current_level[crumbs[-1]] = value build_config.save_local(local_config)
def set_dotted_attribute(build, attribute_name, value): """Save a local_config value given in dotted form to the local_config.json for the current build. Example use:: set_dotted_attribute(build, 'android.profiles.DEFAULT.sdk', '/opt/android-sdk-linux') """ # TODO: would be good to not have to import the build_config module here, maybe emit an event instead? from forge import build_config LOG.info("Saving %s as %s in local_config.json" % (value, attribute_name)) with cd(build.orig_wd): local_config = build_config.load_local() current_level = local_config crumbs = attribute_name.split(".") for k in crumbs[:-1]: if k not in current_level: current_level[k] = {} current_level = current_level[k] current_level[crumbs[-1]] = value build_config.save_local(local_config)
def set_dotted_attributes(build, unexpanded_local_config_values): """Save a local_config value given in dotted form to the local_config.json for the current build. Example use:: set_dotted_attribute(build, 'android.profile.sdk', '/opt/android-sdk-linux') """ from forge import build_config local_config_values = {expand_profile(build, k): v for k, v in unexpanded_local_config_values.items()} LOG.info('Updating local config with %s' % json.dumps(local_config_values, indent=4)) with cd(build.orig_wd): local_config = build_config.load_local() for attribute_name, value in local_config_values.items(): current_level = local_config crumbs = attribute_name.split('.') for k in crumbs[:-1]: if k not in current_level: current_level[k] = {} current_level = current_level[k] current_level[crumbs[-1]] = value build_config.save_local(local_config)
def package_web(build): path_to_app = path.abspath('') interactive = build.tool_config.get('general.interactive', True) development = path.abspath(path.join('development', 'web')) output = path.abspath(path.join('release', 'web', 'heroku')) # deploy to Heroku if sys.platform.startswith("win"): heroku = "heroku.bat" else: heroku = "heroku" with cd(development): username = None api_key = build.tool_config.get('web.profile.heroku_api_key') while api_key is None: if not interactive: raise Exception("You need to specify an API Key for interaction with heroku") try: # TODO: may want to check the api key is actually valid by hitting the api? username, api_key = _heroku_credentials() except IOError: login_call = subprocess.call([heroku, 'login']) if login_call != 0: raise Exception("Failed to login with the heroku api") chosen_app = build.tool_config.get('web.profile.heroku_app_name') if not path.isdir(output): os.makedirs(output) with cd(output): if not path.isdir('.git'): LOG.debug('Creating git repo') _git('init') LOG.debug('Create dummy first commit') with open('.forge.txt', 'w') as forge_file: forge_file.write('') _git('add', '.') _git('commit', '-am', '"first commit"') if chosen_app is None: chosen_app = _request_app_to_push_to(build, api_key, interactive) from forge import build_config LOG.info('Saving %s as chosen as web.profiles.%s.heroku_app_name in local_config.json' % (chosen_app, build.tool_config.profile())) with cd(path_to_app): local_config = build_config.load_local() current_level = local_config for k in ['web','profiles', build.tool_config.profile()]: if k not in current_level: current_level[k] = {} current_level = current_level[k] current_level['heroku_app_name'] = chosen_app build_config.save_local(local_config) # remove all previous files/folders except for .git! with cd(output): for f in os.listdir('.'): if not f == '.git': if path.isfile(f): os.remove(f) elif path.isdir(f): shutil.rmtree(f) # copy code from development to release! with cd(development): for f in os.listdir('.'): if path.isfile(f): shutil.copy2(f, output) elif path.isdir(f) and path.basename(f) != '.git': shutil.copytree(f, path.join(output, f), ignore=shutil.ignore_patterns('.git')) with cd(output): # setup with the specified remote LOG.debug('Setting up git remote for %s' % chosen_app) # remove any previous remote try: _git('remote', 'rm', 'heroku') except WebError: pass _git('remote', 'add', 'heroku', '[email protected]:%s.git' % chosen_app) # commit _git('add', '.') diff = _git('diff', 'HEAD') if not diff.strip(): if interactive: LOG.warning("No app changes detected: did you forget to forge build?") else: # not interactive basically means we're using the trigger toolkit, where 'forge build' # doesn't really make sense LOG.warning("No app changes detected, pushing to heroku anyway") else: _git('commit', '-am', 'forge package web') # push LOG.info('Deploying to %s.herokuapp.com' % chosen_app) if not interactive: LOG.warning('You may need to check the commandline to enter an SSH key passphrase') push_output = _git('push', 'heroku', '--all', '--force', command_log_level=logging.INFO) if push_output.startswith('Everything up-to-date'): remote_output = _git('remote', '-v') remote_pattern = re.compile(r'[email protected]:(.*?).git \(fetch\)') remote_match = remote_pattern.search(remote_output) if remote_match: app_url = 'http://%s.herokuapp.com' % remote_match.group(1) _open_url(app_url) LOG.info('Deployed at %s' % app_url) else: deploy_pattern = re.compile(r'(http://[^ ]+) deployed to Heroku') deploy_match = deploy_pattern.search(push_output) if deploy_match: _open_url(deploy_match.group(1)) LOG.info('Deployed at %s' % deploy_match.group(1))