def test_it_loads_pages_json_when_it_exists(self, patch_clone_dir):
     filename = 'pages.json'
     json_contents = json.dumps({
         'name': filename,
     })
     create_file(patch_clone_dir / filename, contents=json_contents)
     result = repo_config.from_json_file(patch_clone_dir)
     assert result.config['name'] == filename
     assert len(os.listdir(patch_clone_dir)) == 1
Esempio n. 2
0
def build(aws_access_key_id,
          aws_default_region,
          aws_secret_access_key,
          status_callback,
          baseurl,
          branch,
          bucket,
          build_id,
          config,
          generator,
          github_token,
          owner,
          repository,
          site_prefix,
          user_environment_variables=[]):
    '''
    Main task to run a full site build process.

    All values needed for the build are loaded from
    environment variables.
    '''
    # keep track of total time
    start_time = datetime.now()

    logger = None
    commit_sha = None

    cache_control = os.getenv('CACHE_CONTROL', 'max-age=60')
    database_url = os.environ['DATABASE_URL']
    user_environment_variable_key = os.environ['USER_ENVIRONMENT_VARIABLE_KEY']

    try:
        post_build_processing(status_callback)
        # throw a timeout exception after TIMEOUT_SECONDS
        with Timeout(TIMEOUT_SECONDS, swallow_exc=False):
            build_info = f'{owner}/{repository}@id:{build_id}'

            decrypted_uevs = decrypt_uevs(user_environment_variable_key,
                                          user_environment_variables)

            priv_vals = [uev['value'] for uev in decrypted_uevs]
            priv_vals.append(aws_access_key_id)
            priv_vals.append(aws_secret_access_key)
            if github_token:
                priv_vals.append(github_token)

            logattrs = {
                'branch': branch,
                'buildid': build_id,
                'owner': owner,
                'repository': repository,
            }

            init_logging(priv_vals, logattrs, database_url)

            logger = get_logger('main')

            def run_step(returncode, msg):
                if returncode != 0:
                    raise StepException(msg)

            logger.info(f'Running build for {owner}/{repository}/{branch}')

            if generator not in GENERATORS:
                raise ValueError(f'Invalid generator: {generator}')

            ##
            # FETCH
            #
            run_step(
                fetch_repo(owner, repository, branch, github_token),
                'There was a problem fetching the repository, see the above logs for details.'
            )

            commit_sha = fetch_commit_sha(CLONE_DIR_PATH)

            federalist_config = repo_config.from_json_file(
                CLONE_DIR_PATH,
                dict(headers=dict([('cache-control', cache_control)]),
                     excludePaths=[
                         '*/Dockerfile', '*/docker-compose.yml',
                         '/federalist.json', '/pages.json'
                     ],
                     includePaths=['/.well-known/security.txt']))

            if federalist_config.full_clone():
                run_step(
                    update_repo(CLONE_DIR_PATH),
                    'There was a problem updating the repository, see the above logs for details.'
                )

            ##
            # BUILD
            #
            run_step(
                setup_node(),
                'There was a problem setting up Node, see the above logs for details.'
            )

            # Run the npm `federalist` task (if it is defined)
            run_step(
                run_build_script(branch, owner, repository, site_prefix,
                                 baseurl, decrypted_uevs),
                'There was a problem running the federalist script, see the above logs for details.'
            )

            # Run the appropriate build engine based on generator
            if generator == 'jekyll':
                run_step(
                    setup_ruby(),
                    'There was a problem setting up Ruby, see the above logs for details.'
                )

                run_step(
                    setup_bundler(),
                    'There was a problem setting up Bundler, see the above logs for details.'
                )

                run_step(
                    build_jekyll(branch, owner, repository, site_prefix,
                                 baseurl, config, decrypted_uevs),
                    'There was a problem running Jekyll, see the above logs for details.'
                )

            elif generator == 'hugo':
                # extra: --hugo-version (not yet used)
                run_step(
                    download_hugo(),
                    'There was a problem downloading Hugo, see the above logs for details.'
                )

                run_step(
                    build_hugo(branch, owner, repository, site_prefix, baseurl,
                               decrypted_uevs),
                    'There was a problem running Hugo, see the above logs for details.'
                )

            elif generator == 'static':
                # no build arguments are needed
                build_static()

            elif (generator == 'node.js' or generator == 'script only'):
                logger.info('build already ran in \'npm run federalist\'')

            else:
                raise ValueError(f'Invalid generator: {generator}')

            ##
            # PUBLISH
            #
            publish(baseurl, site_prefix, bucket, federalist_config,
                    aws_default_region, aws_access_key_id,
                    aws_secret_access_key)

            delta_string = delta_to_mins_secs(datetime.now() - start_time)
            logger.info(f'Total build time: {delta_string}')

            # Finished!
            post_build_complete(status_callback, commit_sha)

            sys.exit(0)

    except StepException as err:
        '''
        Thrown when a step itself fails, usually because a command exited
        with a non-zero return code
        '''
        logger.error(str(err))
        post_build_error(status_callback, str(err), commit_sha)
        sys.exit(1)

    except TimeoutException:
        logger.warning(f'Build({build_info}) has timed out')
        post_build_timeout(status_callback, commit_sha)

    except Exception as err:  # pylint: disable=W0703
        # Getting here means something really weird has happened
        # since all errors caught during tasks should be caught
        # in the previous block as `UnexpectedExit` exceptions.
        err_string = str(err)

        # log the original exception
        msg = f'Unexpected exception raised during build({build_info}): {err_string}'
        if logger:
            logger.warning(msg)
        else:
            print(msg)

        err_message = (f'Unexpected build({build_info}) error. Please try '
                       'again and contact federalist-support if it persists.')

        post_build_error(status_callback, err_message, commit_sha)