Skip to content

Commit

Permalink
Add the rest call to create repo using template repo name and owner (#…
Browse files Browse the repository at this point in the history
…2148)

* Add the rest call to create repo using template repo name and owner

* test failures

* test fix

* test fix

* test fix

* test fix

* test fix
  • Loading branch information
ssahay87 committed Dec 29, 2023
1 parent 5e28f2c commit 0728e2b
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 83 deletions.
141 changes: 83 additions & 58 deletions metecho/api/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from cumulusci.salesforce_api.utils import get_simple_salesforce_connection
from cumulusci.tasks.github.util import CommitDir
from cumulusci.tasks.vlocity.vlocity import VlocityRetrieveTask
from cumulusci.utils import download_extract_github, temporary_dir
from cumulusci.utils import temporary_dir
from cumulusci.utils.http.requests_utils import safe_json_from_response
from django.conf import settings
from django.db import transaction
Expand Down Expand Up @@ -241,67 +241,92 @@ def create_repository(
team.add_or_update_membership(login, role=role)

# Create repo on GitHub
repo = org.create_repository(
project.repo_name, description=project.description, private=False
)
team.add_repository(repo.full_name, permission="push")
project.repo_id = repo.id
if tpl_repo:
# Calling rest api to generate repo using github template repo
gh_token = org_gh.session.auth.token
# Extract data from the request body

# GitHub API endpoint URL for repository creation
api_url = f"https://api.github.com/repos/{tpl_repo.owner}/{tpl_repo.name}/generate"

# Headers for the GitHub API request
headers = {
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {gh_token}", # Extract GitHub token from request data
}

with temporary_dir():
# Populate files from the template repository
if tpl_repo:
zipfile = download_extract_github(org_gh, tpl_repo.owner, tpl_repo.name)
zipfile.extractall()
# Data to be sent in the POST request to GitHub API
github_data = {
"owner": project.repo_owner,
"name": project.repo_name,
"description": project.description,
"include_all_branches": False,
"private": False,
}
# Sending a POST request to GitHub API
response = requests.post(api_url, headers=headers, json=github_data)
team.add_repository(response.json()["full_name"], permission="push")
project.repo_id = response.json()["id"]
# Checking the response status code and returning the response
if response.status_code != 201:
raise Exception("Create Repository using Template failed")

runtime = CliRuntime()
else:
repo = org.create_repository(
project.repo_name, description=project.description, private=False
)
team.add_repository(repo.full_name, permission="push")
project.repo_id = repo.id
with temporary_dir():

try:
# Ask the user's Dev Hub what its latest API version is
sf = get_devhub_api(devhub_username=user.sf_username)
response = requests.get(
f"https://{sf.sf_instance}/services/data", headers=sf.headers
)
runtime = CliRuntime()
try:
# Ask the user's Dev Hub what its latest API version is
sf = get_devhub_api(devhub_username=user.sf_username)
response = requests.get(
f"https://{sf.sf_instance}/services/data", headers=sf.headers
)

version = safe_json_from_response(response)[-1]["version"]
except Exception:
version = runtime.universal_config.project__package__api_version

# Bootstrap repository with CumulusCI
context = {
"cci_version": cumulusci.__version__,
"project_name": project.repo_name,
"package_name": project.repo_name,
"package_namespace": None,
"api_version": version,
"source_format": "sfdx",
"dependencies": [
{"type": "github", "url": url} for url in dependencies
],
"git": {
"default_branch": branch_name,
"prefix_feature": "feature/",
"prefix_beta": "beta/",
"prefix_release": "release/",
},
"test_name_match": None,
"code_coverage": 75,
}
init_from_context(context)
cmd = sarge.capture_both(
f"""
git init;
git checkout -b {branch_name};
git config user.name '{user.get_full_name() or user.username}';
git config user.email '{user.email}';
git add --all;
git commit -m 'Bootstrap project (via Metecho)';
git push https://{user_gh.session.auth.token}@github.com/{repo.full_name}.git {branch_name};
""", # noqa: B950
shell=True,
)
if cmd.returncode: # non-zero return code, something's wrong
logger.error(cmd.stderr.text)
raise Exception("Failed to push files to GitHub repository")
version = safe_json_from_response(response)[-1]["version"]
except Exception:
version = runtime.universal_config.project__package__api_version

# Bootstrap repository with CumulusCI
context = {
"cci_version": cumulusci.__version__,
"project_name": project.repo_name,
"package_name": project.repo_name,
"package_namespace": None,
"api_version": version,
"source_format": "sfdx",
"dependencies": [
{"type": "github", "url": url} for url in dependencies
],
"git": {
"default_branch": branch_name,
"prefix_feature": "feature/",
"prefix_beta": "beta/",
"prefix_release": "release/",
},
"test_name_match": None,
"code_coverage": 75,
}
init_from_context(context)
cmd = sarge.capture_both(
f"""
git init;
git checkout -b {branch_name};
git config user.name '{user.get_full_name() or user.username}';
git config user.email '{user.email}';
git add --all;
git commit -m 'Bootstrap project (via Metecho)';
git push https://{user_gh.session.auth.token}@github.com/{repo.full_name}.git {branch_name};
""", # noqa: B950
shell=True,
)
if cmd.returncode: # non-zero return code, something's wrong
logger.error(cmd.stderr.text)
raise Exception("Failed to push files to GitHub repository")

# Copy branch protection rules from the template repo
# See copy_branch_protection() for why we don't use this currently
Expand Down
99 changes: 74 additions & 25 deletions metecho/api/tests/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1378,11 +1378,13 @@ def github_mocks(self, mocker, project, git_hub_collaboration_factory):
gh_user.organizations.return_value = [
mocker.MagicMock(login=project.repo_owner, spec=Organization)
]
gh_org = mocker.patch(
f"{PATCH_ROOT}.gh_as_org", autospec=True
).return_value.organization.return_value
gh_org.create_team.return_value = team
gh_org.create_repository.return_value = repo
gh_org = mocker.patch(f"{PATCH_ROOT}.gh_as_org", autospec=True).return_value
tpl_repo = gh_org.repository.return_value
tpl_repo.owner = "Industries-SolutionFactory-Connect"
tpl_repo.name = "TemplateRepoTest"
gh_org_org = gh_org.organization.return_value
gh_org_org.create_team.return_value = team
gh_org_org.create_repository.return_value = repo

get_devhub_api = mocker.patch(f"{PATCH_ROOT}.get_devhub_api", autospec=True)
get_devhub_api.sf_instance = "foo"
Expand All @@ -1391,7 +1393,7 @@ def github_mocks(self, mocker, project, git_hub_collaboration_factory):
# Wild API version so we can easily detect it came from here
requests.get.return_value.json.return_value = [{"version": "600.0"}]

return project, gh_org, team, repo, get_devhub_api, requests
return project, gh_org_org, team, repo, get_devhub_api, requests

def test_ok(self, mocker, github_mocks, user_factory):
user = user_factory()
Expand All @@ -1400,14 +1402,13 @@ def test_ok(self, mocker, github_mocks, user_factory):
sarge = mocker.patch(f"{PATCH_ROOT}.sarge", autospec=True)
sarge.capture_both.return_value.returncode = 0
async_to_sync = mocker.patch("metecho.api.model_mixins.async_to_sync")
zipfile = mocker.patch(f"{PATCH_ROOT}.download_extract_github").return_value

# zipfile = mocker.patch(f"{PATCH_ROOT}.download_extract_github").return_value
create_repository(
project,
user=user,
dependencies=["http://foo.com"],
template_repo_owner="owner",
template_repo_name="repo",
template_repo_owner=None,
template_repo_name=None,
)
project.refresh_from_db()

Expand All @@ -1426,26 +1427,30 @@ def test_ok(self, mocker, github_mocks, user_factory):
include_user=False,
)
assert sarge.capture_both.called
assert zipfile.extractall.called
# assert zipfile.extractall.called
assert init_from_context.call_args_list[0][0][0]["api_version"] == "600.0"

def test_ok__no_version_from_devhub(self, mocker, github_mocks, user_factory):
user = user_factory()
project, org, team, repo, get_devhub_api, requests = github_mocks
get_devhub_api.side_effect = Exception
init_from_context = mocker.patch(f"{PATCH_ROOT}.init_from_context")
# init_from_context = mocker.patch(f"{PATCH_ROOT}.init_from_context")
sarge = mocker.patch(f"{PATCH_ROOT}.sarge", autospec=True)
sarge.capture_both.return_value.returncode = 0
async_to_sync = mocker.patch("metecho.api.model_mixins.async_to_sync")
zipfile = mocker.patch(f"{PATCH_ROOT}.download_extract_github").return_value

create_repository(
project,
user=user,
dependencies=["http://foo.com"],
template_repo_owner="owner",
template_repo_name="repo",
)
# zipfile = mocker.patch(f"{PATCH_ROOT}.download_extract_github").return_value
with patch("requests.post") as mock_post:
response = mocker.patch(f"{PATCH_ROOT}.requests.post").return_value
response.status_code = 201
response.json.return_value = {"full_name": "value", "id": 123456}
mock_post.return_value = response
create_repository(
project,
user=user,
dependencies=["http://foo.com"],
template_repo_owner="Industries-SolutionFactory-Connect",
template_repo_name="TemplateRepoTest",
)
project.refresh_from_db()

assert project.repo_id == 123456
Expand All @@ -1462,9 +1467,53 @@ def test_ok__no_version_from_devhub(self, mocker, github_mocks, user_factory):
group_name=None,
include_user=False,
)
assert sarge.capture_both.called
assert zipfile.extractall.called
assert init_from_context.call_args_list[0][0][0]["api_version"] != "600.0"
# assert sarge.capture_both.called
# assert zipfile.extractall.called
# assert init_from_context.call_args_list[0][0][0]["api_version"] != "600.0"

def test_ok__exception_from_template(self, mocker, github_mocks, user_factory):
user = user_factory()
project, org, team, repo, get_devhub_api, requests = github_mocks
get_devhub_api.side_effect = Exception
sarge = mocker.patch(f"{PATCH_ROOT}.sarge", autospec=True)
sarge.capture_both.return_value.returncode = 0

with patch(f"{PATCH_ROOT}.Exception") as mock_exception:
mock_exception.side_effect = Exception(
"Create Repository using Template failed"
)

with patch("requests.post") as mock_post:
response = mocker.patch(f"{PATCH_ROOT}.requests.post").return_value
response.status_code = 404
response.json.return_value = {"full_name": "value", "id": 123456}
mock_post.return_value = response
with pytest.raises(Exception, match="Create Repository using Template failed"):
create_repository(
project,
user=user,
dependencies=["http://foo.com"],
template_repo_owner="dummy1",
template_repo_name="dummy2",
)

def test_ok__exception_from_repo(self, mocker, github_mocks, user_factory):
user = user_factory()
project, org, team, repo, get_devhub_api, requests = github_mocks
get_devhub_api.side_effect = Exception
init_from_context = mocker.patch(f"{PATCH_ROOT}.init_from_context")
sarge = mocker.patch(f"{PATCH_ROOT}.sarge", autospec=True)
sarge.capture_both.return_value.returncode = 0

with patch(f"{PATCH_ROOT}"):
create_repository(
project,
user=user,
dependencies=["http://foo.com"],
template_repo_owner=None,
template_repo_name=None,
)
assert init_from_context.call_args_list[0][0][0]["api_version"] != "600.0"

def test__gh_error(self, mocker, caplog, project, user_factory, github_mocks):
user = user_factory()
Expand Down Expand Up @@ -1507,7 +1556,7 @@ def test__team_name_taken(self, mocker, github_mocks, project, user_factory):
sarge = mocker.patch(f"{PATCH_ROOT}.sarge", autospec=True)
sarge.capture_both.return_value.returncode = 0
mocker.patch("metecho.api.model_mixins.async_to_sync")
mocker.patch(f"{PATCH_ROOT}.download_extract_github").return_value
# mocker.patch(f"{PATCH_ROOT}.download_extract_github").return_value

create_repository(project, user=user, dependencies=[])

Expand Down

0 comments on commit 0728e2b

Please sign in to comment.