Skip to content

Commit 596c351

Browse files
Merge pull request easybuilders#2631 from boegel/fix_from_pr
make --from-pr always try to apply PR patch on top of PR target branch
2 parents 5fc2125 + d1e5ca7 commit 596c351

2 files changed

Lines changed: 68 additions & 45 deletions

File tree

easybuild/tools/github.py

Lines changed: 64 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,10 @@
4646
from vsc.utils.missing import nub
4747

4848
from easybuild.framework.easyconfig.easyconfig import copy_easyconfigs, copy_patch_files, process_easyconfig
49-
from easybuild.framework.easyconfig.format.one import EB_FORMAT_EXTENSION
50-
from easybuild.framework.easyconfig.format.yeb import YEB_FORMAT_EXTENSION
5149
from easybuild.tools.build_log import EasyBuildError, print_msg, print_warning
5250
from easybuild.tools.config import build_option
5351
from easybuild.tools.filetools import apply_patch, copy_dir, det_patched_files, download_file, extract_file
54-
from easybuild.tools.filetools import mkdir, read_file, which, write_file
52+
from easybuild.tools.filetools import mkdir, read_file, symlink, which, write_file
5553
from easybuild.tools.systemtools import UNKNOWN, get_tool_version
5654
from easybuild.tools.utilities import only_if_module_is_available
5755

@@ -368,87 +366,108 @@ def fetch_easyconfigs_from_pr(pr, path=None, github_user=None):
368366
# make sure path exists, create it if necessary
369367
mkdir(path, parents=True)
370368

371-
_log.debug("Fetching easyconfigs from PR #%s into %s" % (pr, path))
372-
pr_url = lambda g: g.repos[GITHUB_EB_MAIN][GITHUB_EASYCONFIGS_REPO].pulls[pr]
369+
github_account = build_option('pr_target_account')
370+
github_repo = GITHUB_EASYCONFIGS_REPO
371+
372+
def pr_url(gh):
373+
"""Utility function to fetch data for a specific PR."""
374+
return gh.repos[github_account][github_repo].pulls[pr]
375+
376+
_log.debug("Fetching easyconfigs from %s/%s PR #%s into %s", github_account, github_repo, pr, path)
373377

374378
status, pr_data = github_api_get_request(pr_url, github_user)
375379
if status != HTTP_STATUS_OK:
376380
raise EasyBuildError("Failed to get data for PR #%d from %s/%s (status: %d %s)",
377-
pr, GITHUB_EB_MAIN, GITHUB_EASYCONFIGS_REPO, status, pr_data)
378-
379-
# if PR is open and mergable, download develop and patch
380-
stable = pr_data['mergeable_state'] == GITHUB_MERGEABLE_STATE_CLEAN
381-
closed = pr_data['state'] == GITHUB_STATE_CLOSED and not pr_data['merged']
381+
pr, github_account, github_repo, status, pr_data)
382382

383-
# 'clean' on successful (or missing) test, 'unstable' on failed tests or merge conflict
384-
if not stable:
385-
_log.warning("Mergeable state for PR #%d is not '%s': %s.",
386-
pr, GITHUB_MERGEABLE_STATE_CLEAN, pr_data['mergeable_state'])
383+
pr_merged = pr_data['merged']
384+
pr_closed = pr_data['state'] == GITHUB_STATE_CLOSED and not pr_merged
387385

388-
if (stable or pr_data['merged']) and not closed:
389-
# whether merged or not, download develop
390-
final_path = download_repo(repo=GITHUB_EASYCONFIGS_REPO, branch='develop', github_user=github_user)
386+
pr_target_branch = pr_data['base']['ref']
387+
_log.info("Target branch for PR #%s: %s", pr, pr_target_branch)
391388

392-
else:
393-
final_path = path
389+
# download target branch of PR so we can try and apply the PR patch on top of it
390+
repo_target_branch = download_repo(repo=github_repo, account=github_account, branch=pr_target_branch,
391+
github_user=github_user)
394392

395393
# determine list of changed files via diff
396394
diff_fn = os.path.basename(pr_data['diff_url'])
397-
diff_filepath = os.path.join(final_path, diff_fn)
395+
diff_filepath = os.path.join(path, diff_fn)
398396
download_file(diff_fn, pr_data['diff_url'], diff_filepath, forced=True)
399397
diff_txt = read_file(diff_filepath)
400398

401399
patched_files = det_patched_files(txt=diff_txt, omit_ab_prefix=True, github=True, filter_deleted=True)
402400
_log.debug("List of patched files: %s" % patched_files)
403401

404402
for key, val in sorted(pr_data.items()):
405-
_log.debug("\n%s:\n\n%s\n" % (key, val))
403+
_log.debug("\n%s:\n\n%s\n", key, val)
406404

407405
# obtain last commit
408406
# get all commits, increase to (max of) 100 per page
409407
if pr_data['commits'] > GITHUB_MAX_PER_PAGE:
410-
raise EasyBuildError("PR #%s contains more than %s commits, can't obtain last commit", pr, GITHUB_MAX_PER_PAGE)
411-
status, commits_data = github_api_get_request(lambda g: pr_url(g).commits, github_user,
408+
raise EasyBuildError("PR #%s contains more than %s commits, can't obtain last commit",
409+
pr, GITHUB_MAX_PER_PAGE)
410+
411+
status, commits_data = github_api_get_request(lambda gh: pr_url(gh).commits, github_user,
412412
per_page=GITHUB_MAX_PER_PAGE)
413413
if status != HTTP_STATUS_OK:
414414
raise EasyBuildError("Failed to get data for PR #%d from %s/%s (status: %d %s)",
415-
pr, GITHUB_EB_MAIN, GITHUB_EASYCONFIGS_REPO, status, commits_data)
415+
pr, github_account, github_repo, status, commits_data)
416416
last_commit = commits_data[-1]
417-
_log.debug("Commits: %s, last commit: %s" % (commits_data, last_commit['sha']))
418-
419-
if not(pr_data['merged']):
420-
if not stable or closed:
421-
state_msg = "unstable (pending/failed tests or merge conflict)" if not stable else "closed (but not merged)"
422-
print "\n*** WARNING: Using easyconfigs from %s PR #%s ***\n" % (state_msg, pr)
423-
# obtain most recent version of patched files
424-
for patched_file in patched_files:
425-
# path to patch file, incl. subdir it is in
426-
fn = os.path.sep.join(patched_file.split(os.path.sep)[-3:])
427-
sha = last_commit['sha']
428-
full_url = URL_SEPARATOR.join([GITHUB_RAW, GITHUB_EB_MAIN, GITHUB_EASYCONFIGS_REPO, sha, patched_file])
429-
_log.info("Downloading %s from %s" % (fn, full_url))
430-
download_file(fn, full_url, path=os.path.join(path, fn), forced=True)
431-
else:
432-
apply_patch(diff_filepath, final_path, level=1)
417+
_log.debug("Commits: %s, last commit: %s", commits_data, last_commit['sha'])
418+
419+
final_path = None
433420

421+
# try to apply PR patch on top of target branch, unless the PR is closed or already merged
422+
if pr_merged:
423+
_log.info("PR is already merged, so using current version of PR target branch")
424+
final_path = repo_target_branch
425+
426+
elif not pr_closed:
427+
try:
428+
_log.debug("Trying to apply PR patch %s to %s...", diff_filepath, repo_target_branch)
429+
apply_patch(diff_filepath, repo_target_branch, level=1)
430+
_log.info("Using %s which included PR patch to test PR #%s", repo_target_branch, pr)
431+
final_path = repo_target_branch
432+
433+
except EasyBuildError as err:
434+
_log.warning("Ignoring problem that occured when applying PR patch: %s", err)
435+
436+
if final_path is None:
437+
438+
if pr_closed:
439+
print_warning("Using easyconfigs from closed PR #%s" % pr)
440+
441+
# obtain most recent version of patched files
442+
for patched_file in patched_files:
443+
# path to patch file, incl. subdir it is in
444+
fn = os.path.sep.join(patched_file.split(os.path.sep)[-3:])
445+
sha = last_commit['sha']
446+
full_url = URL_SEPARATOR.join([GITHUB_RAW, github_account, github_repo, sha, patched_file])
447+
_log.info("Downloading %s from %s", fn, full_url)
448+
download_file(fn, full_url, path=os.path.join(path, fn), forced=True)
449+
450+
final_path = path
451+
452+
# symlink directories into expected place if they're not there yet
434453
if final_path != path:
435454
dirpath = os.path.join(final_path, 'easybuild', 'easyconfigs')
436455
for eb_dir in os.listdir(dirpath):
437-
os.symlink(os.path.join(dirpath, eb_dir), os.path.join(path, os.path.basename(eb_dir)))
456+
symlink(os.path.join(dirpath, eb_dir), os.path.join(path, os.path.basename(eb_dir)))
438457

439458
# sanity check: make sure all patched files are downloaded
440459
ec_files = []
441460
for patched_file in [f for f in patched_files if not f.startswith('test/')]:
442461
fn = os.path.sep.join(patched_file.split(os.path.sep)[-3:])
443-
if os.path.exists(os.path.join(path, fn)):
444-
ec_files.append(os.path.join(path, fn))
462+
full_path = os.path.join(path, fn)
463+
if os.path.exists(full_path):
464+
ec_files.append(full_path)
445465
else:
446-
raise EasyBuildError("Couldn't find path to patched file %s", os.path.join(path, fn))
466+
raise EasyBuildError("Couldn't find path to patched file %s", full_path)
447467

448468
return ec_files
449469

450470

451-
452471
def create_gist(txt, fn, descr=None, github_user=None):
453472
"""Create a gist with the provided text."""
454473
if descr is None:

test/framework/github.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ def test_fetch_easyconfigs_from_pr(self):
120120
print "Skipping test_fetch_easyconfigs_from_pr, no GitHub token available?"
121121
return
122122

123+
init_config(build_options={
124+
'pr_target_account': gh.GITHUB_EB_MAIN,
125+
})
126+
123127
# PR for rename of ffmpeg to FFmpeg,
124128
# see https://github.com/easybuilders/easybuild-easyconfigs/pull/2481/files
125129
all_ecs_pr2481 = [

0 commit comments

Comments
 (0)