Skip to content

Commit

Permalink
Make forking optional (#29)
Browse files Browse the repository at this point in the history
* Make forking optional

* Bump version + changelog

* Slight code cleanup
  • Loading branch information
Jonathan Nevelson authored Jul 17, 2020
1 parent 2724b32 commit 74321ee
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 73 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com),
and this project adheres to [Semantic Versioning](https://semver.org).

## [3.0.0] - 2020-07-17
### Changed
- Made forking optional via `--fork` argument, which is mutually exclusive with `--branch`

## [2.1.2] - 2020-06-25
### Added
- Added entrypoint script to meet requirements of official docker image consistency
Expand Down
35 changes: 26 additions & 9 deletions gordian/gordian.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,12 @@ def get_basic_parser():
dest='dry_run',
help='Enable dry run mode'
)
parser.add_argument(
'-b', '--branch',
required=False,
dest='branch',
help='Branch name to use'
)
parser.add_argument(
'-t', '--target-branch',
required=False,
default='master',
dest='target_branch',
help='Target branch'
help='Target branch to create a pull request into'
)
parser.add_argument(
'-l','--labels',
Expand All @@ -86,6 +80,21 @@ def get_basic_parser():
dest='pr_labels',
help='List of space separated label names you wish to add to your pull request(s)'
)
fork = parser.add_mutually_exclusive_group(required=False)
fork.add_argument(
'-f', '--fork',
default=False,
action='store_true',
required=False,
help='Fork the repo'
)
fork.add_argument(
'-b', '--branch',
required=False,
dest='branch',
help='Branch name to commit to and read file contents from'
)

bumpers = parser.add_mutually_exclusive_group(required=False)
bumpers.add_argument(
'-M', '--major',
Expand Down Expand Up @@ -167,7 +176,14 @@ def transform(args, transformations, repositories, pr_description, pr_created_ca
pull_request_urls = []
for repo_name in repositories:
logger.info(f'Processing repo: {repo_name}')
repo = Repo(repo_name, github_api_url=args.github_api, branch=args.branch, semver_label=args.semver_label, target_branch=args.target_branch)
repo = Repo(
repo_name,
github_api_url=args.github_api,
branch=args.branch,
semver_label=args.semver_label,
target_branch=args.target_branch,
fork=args.fork
)
for transformation in transformations:
transformation(args, repo).run()
if repo.dirty:
Expand All @@ -181,7 +197,8 @@ def transform(args, transformations, repositories, pr_description, pr_created_ca
pr_created_callback(repo_name, pull_request)
logger.info(f'PR created: {args.pr_message}. Branch: {repo.branch_name}. Labels: {args.pr_labels}')
except GithubException as e:
logger.info(f'PR already exists for {repo.branch_name}. Error: {e}')
logger.info(f'PR already exists for {repo.branch_name}')
logger.debug(f'Error: {e}')

if pull_request_urls:
logger.info('Pull requests')
Expand Down
90 changes: 54 additions & 36 deletions gordian/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import datetime
import logging
import os
import sys
import time
from retry import retry
from gordian.files import *
Expand All @@ -14,7 +15,7 @@

class Repo:

def __init__(self, repo_name, github_api_url=None, branch=None, github=None, files=None, semver_label=None, target_branch='master'):
def __init__(self, repo_name, github_api_url=None, branch=None, github=None, files=None, semver_label=None, target_branch='master', fork=False):
if github_api_url is None:
self.github_api_url = BASE_URL
else:
Expand All @@ -34,36 +35,18 @@ def __init__(self, repo_name, github_api_url=None, branch=None, github=None, fil
files = []
self.files = files

self.repo_name = repo_name
self._original_repo = self._github.get_repo(repo_name)
self._initialize_repos(repo_name, fork)

self.version_file = None
self.changelog_file = None
self.branch_exists = False
self.dirty = False
self.new_version = None
self.semver_label = semver_label
self.target_branch = None
self.set_target_branch(target_branch)
self._set_target_branch(target_branch, branch)

if branch:
self.branch_name = f"refs/heads/{branch}"
else:
self.branch_name = f"refs/heads/{datetime.datetime.now().strftime('%Y-%m-%d-%H%M%S.%f')}"

logger.debug(f'Github api url: {self.github_api_url}')
logger.debug(f'Repo name: {self.repo_name}')
logger.debug(f'Target ref: {self.target_branch}')
logger.debug(f'Branch name for this changes: {self.branch_name}')

def set_target_branch(self, branch):
if branch == self.target_branch:
return

self.target_branch = branch
self.target_ref = f"refs/heads/{self.target_branch}"
# Resetting the file cache when we change the branch
self.files = []
logger.debug(f'Github API: {self.github_api_url}')
logger.debug(f'Repo name: {repo_name}')

def get_objects(self, filename, klass=None):
file = self.find_file(filename)
Expand All @@ -88,16 +71,16 @@ def get_objects(self, filename, klass=None):

def get_files(self):
if not self.files:
logger.debug(f'Getting repo content')
contents = self._original_repo.get_contents('', self.target_ref)
contents = self._get_repo_contents('')

while contents:
file = contents.pop(0)
if file.path == 'version':
self.version_file = file
elif file.path == 'CHANGELOG.md':
self.changelog = ChangelogFile(file, self)
elif file.type == 'dir':
contents.extend(self._original_repo.get_contents(file.path, self.target_ref))
contents.extend(self._get_repo_contents(file.path))
else:
self.files.append(file)

Expand All @@ -110,22 +93,57 @@ def find_file(self, filename):
if file.path == filename:
return file

def _initialize_repos(self, repo_name, fork):
self._target_repo = self._github.get_repo(repo_name)
if fork:
logger.info('Forking repo...')
self._source_repo = self._target_repo.create_fork()
else:
self._source_repo = self._target_repo

def _set_target_branch(self, target_branch, source_branch=None):
logger.debug(f'Target branch: {target_branch}')
logger.debug(f'Source branch: {source_branch}')

# Resetting the file cache when we change the branch
self.files = []

self.target_branch = target_branch
self.target_ref = f"refs/heads/{self.target_branch}"

if source_branch:
self.branch_name = f"refs/heads/{source_branch}"
self.source_branch = self.branch_name
else:
self.branch_name = f"refs/heads/{datetime.datetime.now().strftime('%Y-%m-%d-%H%M%S.%f')}"
self.source_branch = self.target_ref

@retry(GithubException, tries=3, delay=1, backoff=2)
def _get_repo_contents(self, path):
try:
logger.debug(f'Fetching repo contents {path}...')
return self._source_repo.get_contents(path, self.source_branch)
except GithubException as e:
if e.status == 404:
logger.info(f'Repo does not contain {self.source_branch} branch. Exiting...')
sys.exit(1)
else:
raise e

@retry(GithubException, tries=3, delay=1, backoff=2)
def _make_branch(self):
logger.info('Forking repo...')
self._forked_repo = self._original_repo.create_fork()
branch = self._get_branch()
logger.debug(f'Creating branch {self.branch_name}')

try:
ref = self._forked_repo.create_git_ref(ref=self.branch_name, sha=branch.commit.sha)
ref = self._source_repo.create_git_ref(ref=self.branch_name, sha=branch.commit.sha)
except GithubException as e:
logger.debug(f'Branch {self.branch_name} already exists in github')
self.branch_exists = True

@retry(GithubException, tries=3, delay=1, backoff=2)
def _get_branch(self):
logger.debug(f'Fetching branch {self.target_branch}...')
return self._forked_repo.get_branch(self.target_branch)
return self._source_repo.get_branch(self.target_branch)

def bump_version(self, dry_run=False):
if self.new_version is None:
Expand All @@ -150,7 +168,7 @@ def update_file(self, repo_file, content, message, dry_run=False):
self._make_branch()

logger.debug(f'Updating file {repo_file.path}')
self._forked_repo.update_file(
self._source_repo.update_file(
repo_file.path,
message,
content,
Expand All @@ -169,7 +187,7 @@ def create_file(self, path, contents, message, dry_run=False):
self._make_branch()

logger.debug(f'Creating file {path}')
self._forked_repo.create_file(
self._source_repo.create_file(
path,
message,
contents,
Expand All @@ -187,19 +205,19 @@ def delete_file(self, file, message, dry_run=False):
self._make_branch()

logger.debug(f'Deleting file {file.path}')
self._forked_repo.delete_file(
self._source_repo.delete_file(
file.path,
message,
file.sha,
branch=self.branch_name
)

def create_pr(self, pr_message, pr_body, target_branch, labels):
pr = self._original_repo.create_pull(
pr = self._target_repo.create_pull(
pr_message,
pr_body,
target_branch,
f'{self._forked_repo.owner.login}:{self.branch_name}'
f'{self._source_repo.owner.login}:{self.branch_name}'
)
pr.set_labels(*labels)
return pr
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
setup_reqs = ['pytest', 'pytest-cov', 'pytest-runner', 'flake8']
setuptools.setup(
name="gordian",
version="2.1.2",
version="3.0.0",
author="Intuit",
author_email="[email protected]",
description="A tool to search and replace files in a Git repo",
Expand Down
5 changes: 3 additions & 2 deletions tests/test_gordian.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,16 @@ def __init__(self, config_file='./tests/fixtures/test_config.yaml', dry_run = Fa
self.pr_labels = ['test']
self.description = ''
self.description_file = None
self.fork = False

def test_apply_transformations_without_changes(self):
with patch('gordian.gordian.Repo') as RepoMock, patch('gordian.transformations.Transformation') as TransformationMockClass:
instance = RepoMock.return_value
instance.dirty = False
apply_transformations(TestGordian.Args(), [TransformationMockClass])
RepoMock.assert_has_calls([
call('testOrg/TestService1', github_api_url=None, branch='test', semver_label=None, target_branch='master'),
call('testOrg/TestService2', github_api_url=None, branch='test', semver_label=None, target_branch='master')
call('testOrg/TestService1', github_api_url=None, branch='test', semver_label=None, target_branch='master', fork=False),
call('testOrg/TestService2', github_api_url=None, branch='test', semver_label=None, target_branch='master', fork=False)
])

def test_apply_transformations_with_changes(self):
Expand Down
Loading

0 comments on commit 74321ee

Please sign in to comment.