Пример #1
0
def sync_updates(repo, push=False):
    """Updates the local `repo` with origin, pulling and push when necessary.

    True is returned when any changes were made (aside fetch), otherwise False.

    Args:
        repo (git.objects.Repo): The git repository to sync updates on
        push (bool): True to push local changes, False to only pull

    Returns:
        bool: True if `repo` was sync'd, False otherwise

    """
    ref = repo.remotes.origin.refs[0].name
    repo_dir = repo.working_dir
    branch = repo.active_branch

    io.info('fetching remote for "%s"@:%s' % (
        os.path.split(repo_dir)[-1],
        branch,
    ))
    repo.remotes.origin.fetch()

    ahead, behind = helpers.get_ahead_behind_count(repo)
    is_dirty = repo.is_dirty()

    if not ahead and not behind and not is_dirty:
        return False

    io.info('(found) [ahead: %s, behind: %s] [dirty: %s]' % (
        ahead,
        behind,
        is_dirty,
    ))

    # possible merge conflicts
    if (ahead and behind) or (behind and is_dirty):
        raise FetchRemoteUnknownNextStep(
            'possible merge conflict. please manually resolve')

    # we're ahead so let's push these changes up
    if ahead and push:
        io.warn('ahead, pushing local changes to %s' % (ref, ))
        repo.remotes.origin.push()

    # we're behind so let's pull changes down
    if behind:
        io.warn('behind, pulling changes from %s' % (ref, ))
        repo.remotes.origin.pull()
    return True
Пример #2
0
    def _get_artifact(self, deployment_repo, dockerhub_auth, env):
        io.info('retrieving image tags for "%s" from dockerhub' %
                (self.service_name, ))
        artifacts = dockerhub.list_image_tags(dockerhub_auth,
                                              self.service_name)
        artifacts = artifacts[:Bump.MAX_ARTIFACTS_SHOWN]

        if not artifacts:
            io.err('no artifacts found "%s/%s"' % (
                self.config.get('dockerhub')['organization'],
                self.service_name,
            ))
            return None
        return self._prompt_artifact_selection(self.service_name,
                                               self.artifact_key,
                                               deployment_repo, env, artifacts)
Пример #3
0
    def run(self):
        io.info('performing git sync across all specified repositories...')
        for deployment_repo in self.config.get('terraformRepositories'):
            git_ext.sync_updates(deployment_repo['git'])
            deployment_repo['tfvars'].load(
            )  # sync_updates may have changed tfvars.

            env = self.env or deployment_repo['defaultEnvironment']
            table_data = self._build_status_table(deployment_repo, env)
            docker_org = self.config.get('dockerhub')['organization']
            io.info('displaying "%s" active&inactive services on "%s"' % (
                docker_org,
                env,
            ))
            io.print_table(table_data, 'current %s artifacts' % (env, ))
        io.warn('only dockerized services are shown here (i.e. no lambda)')
Пример #4
0
def tag_commit(repo, tag_name, message, ref='HEAD'):
    """Creates a tag to the `ref` of the given git `repo`.

    Args:
        repo (git.objects.Repo): The git repository commit changes to
        tag_name (str): The name of the tag
        message (str): The tag message body
        ref (Optional[str, git.objects.Commit]): The commit to tag on

    Returns:
        bool: True if a tag was successfully created

    """
    repo.create_tag(tag_name, ref=ref, message=message)
    io.info('created tag: (name) %s' % (tag_name, ))
    return True
Пример #5
0
    def run(self):
        io.info('authenticating "%s" against dockerhub' %
                (self.config.get('dockerhub')['organization'], ))

        # Authenticate against DockerHub for artifact access.
        dockerhub_auth = dockerhub.DockerHubAuthentication(
            self.config.get('dockerhub')['username'],
            self.config.get('dockerhub')['password'],
            self.config.get('dockerhub')['organization'],
        )

        # Determine the deployment repo we want to make changes to.
        deployment_repo = TFVarsHelpers.find_deployment_repo(
            self.service_name, self.config.get('terraformRepositories'))
        if not deployment_repo:
            io.err('could not find service %r' % (self.service_name, ))
            return None

        # Determine the environment and safe guard based on active branch.
        env = self.env or deployment_repo['defaultEnvironment']
        active_branch = deployment_repo['git'].active_branch.name
        if active_branch != deployment_repo['defaultGitBranch']:
            raise InvalidOperatingBranch(active_branch)

        # Select the artifact we want to bump with.
        artifact = self._get_artifact(deployment_repo, dockerhub_auth, env)
        if artifact is None:  # An artifact wasn't selected, end command.
            return None

        git_ext.sync_updates(deployment_repo['git'])
        deployment_repo['tfvars'].load(
        )  # Reload tfvars in case the sync introduced new changes.

        # Update deployment repo and bump artifact.
        self._commit_bump(dockerhub_auth, deployment_repo, artifact, env)

        # Push changes up to GitHub to trigger changes in the build pipeline.
        if self.should_push:
            git_ext.push_commits(deployment_repo['git'])
        else:
            io.warn('commit to tfvars was NOT pushed to remote!')
            io.warn(
                "it's your responsibility to bundle changes and explicitly push"
            )
Пример #6
0
    def _prompt_artifact_selection(self, service_name, artifact_key,
                                   deployment_repo, env, artifacts):
        current_image = deployment_repo['tfvars'].get(artifact_key, env)

        io.info('found artifacts for "%s/%s"' % (
            self.config.get('dockerhub')['organization'],
            service_name,
        ))
        table_data = [
            (
                'id',
                'tag name (* = current)',
                'created at',
                'size',
            ),
        ]
        for i, artifact in enumerate(artifacts, 1):
            created_at = datetime.strptime(artifact['last_updated'],
                                           '%Y-%m-%dT%H:%M:%S.%fZ')
            created_at = pretty_print_datetime(created_at)

            image_size = humanize.naturalsize(artifact['full_size'])
            image_name = artifact['name']
            if image_name in current_image:  # indicate the current artifact.
                image_name += ' *'

            table_data.append((
                str(i),
                image_name,
                created_at,
                image_size,
            ))
        io.print_table(table_data, 'recent artifacts')

        # Handle the case where the selected artifact is the current artifact.
        selected_artifact = io.collect_input(
            'select the artifact you want to use [q]:', artifacts)
        if selected_artifact and selected_artifact['name'] in current_image:
            io.err('selected artifact is already the current active artifact')
            return None
        return selected_artifact
Пример #7
0
def commit_changes(repo, commit_message):
    """Commits all changes (staged and untracked) in a single commit.

    Args:
        repo (git.objects.Repo): The git repository to commit changes to
        commit_message (str): The commit message to use

    Returns:
        bool: True if a commit was made, False otherwise

    """
    if not repo.is_dirty():
        return False

    repo.git.add(u=True)
    actor = Actor(const.COMMIT_AUTHOR_NAME, email=const.COMMIT_AUTHOR_EMAIL)
    commit = repo.index.commit(commit_message, author=actor, committer=actor)

    io.info('commit message: "%s"' % (commit_message.split('\n')[0]), )
    io.info('created commit: (id) %s' % (commit.name_rev, ))
    return True
Пример #8
0
def commit_empty_changes(repo, commit_message):
    """Similar to `git_extensions.extensions.commit_changes` except --allow-empty.

    Args:
        repo (git.objects.Repo): The git repository to commit changes to
        commit_message (str): The commit message to use

    Returns:
        git.objects.Commit: The commit that was just created, None if failed

    """
    if repo.is_dirty():
        return None

    repo.git.commit(*shlex.split('--allow-empty -m "%s" --author "%s"' % (
        commit_message,
        const.COMMIT_AUTHOR_NAME,
    )))
    commit = repo.iter_commits().next()

    io.info('commit message: "%s"' % (commit_message.split('\n')[0], ))
    io.info('created commit: (id) %s' % (commit.name_rev, ))
    return commit
Пример #9
0
    def _commit_bump(self, dockerhub_auth, deployment_repo, artifact, env):
        image_abspath = dockerhub.build_image_abspath(dockerhub_auth,
                                                      self.service_name,
                                                      artifact['name'])
        io.info('updating "%s"' % (image_abspath, ))
        deployment_repo['tfvars'].set(self.artifact_key, image_abspath, env)
        deployment_repo['tfvars'].save()

        commit_message = git_ext.generate_service_bump_commit_message(
            deployment_repo['git'],
            self.service_name,
            env,
            artifact['name'],
        )

        did_commit = git_ext.commit_changes(deployment_repo['git'],
                                            commit_message)
        if not did_commit:
            raise NoChangesEmptyCommit('"%s" has nothing to commit' %
                                       (deployment_repo['git'].working_dir, ))
        if env == 'production':
            git_ext.tag_commit(deployment_repo['git'],
                               git_ext.generate_deploy_commit_tag(),
                               commit_message)
Пример #10
0
def push_commits(repo):
    io.info('pushing changes to %s' % (repo.remotes.origin.refs[0].name, ))
    repo.git.push('origin', 'master', tags=True)
    io.ok('successfully pushed changes to %s' %
          (repo.remotes.origin.refs[0].name, ))