diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rwxr-xr-x | pr2relnotes.py | 188 | ||||
-rw-r--r-- | src/rebar_git_resource.erl | 4 | ||||
-rw-r--r-- | src/rebar_prv_compile.erl | 2 | ||||
-rw-r--r-- | src/rebar_prv_eunit.erl | 62 |
5 files changed, 213 insertions, 44 deletions
@@ -18,3 +18,4 @@ logs priv/templates/*.dtl.erl ebin .edts +env diff --git a/pr2relnotes.py b/pr2relnotes.py new file mode 100755 index 0000000..6e9a4f4 --- /dev/null +++ b/pr2relnotes.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python + +## Install info +## $ virtualenv env +## $ source env/bin/activate +## $ pip install PyGithub +## +## Examples: +## Find the differences from last tag to current +## $ pr2relnotes.py alpha-6 HEAD + +import argparse +import re +import os +import subprocess +from github import Github +from github import GithubException + + +def dprint(*args): + if VERBOSE: + print str(args) + +def get_args(): + """ + Get command line arguments + """ + parser = argparse.ArgumentParser(description="Find the PR's between two versions") + parser.add_argument("old", help = "old version to use") + parser.add_argument("new", help = "new version to use") + parser.add_argument("-v", "--verbose", help="Enable debug output", + default=False, + action="store_true") + parser.add_argument("-f", "--file", + help="Output file to store results (default: tagdiff.md)", + default="tagdiff.md") + return parser.parse_args() + +def search_prs(log): + """ + Search lines of text for PR numbers + """ + # Find all matches using regex iterator, using the PR # as the group match + resultlist = [str(m.group(1)) for m in re.finditer(r"erge pull request #(\d+)", log)] + return sorted(resultlist) + +def get_env(env): + return os.environ[env] + +def get_formatted_issue(repo, issue, title, url): + """ + Single place to adjust formatting output of PR data + """ + # Newline support writelines() call which doesn't add newlines + # on its own + return("* {}/{}: [{}]({})\n".format(repo, issue, title, url)) + +def gh_get_issue_output(org, repo, issuenum): + """ + Look up PR information using the GitHub api + """ + # Attempt to look up the PR, and don't take down the whole + # shebang if a API call fails + # This will fail often on forks who don't have the + # PRs numbers associated with the forked account + # Return empty string on error + try: + repoObj = gh.get_repo(org + "/" + repo) + issue = repoObj.get_issue(int(issuenum)) + title = issue.title + html_url = issue.html_url + except GithubException as e: + print "Github error({0}): {1}".format(e.status, e.data) + return "" + except: + print "Some github error" + return "" + + return(get_formatted_issue(repo, issuenum, title, html_url)) + + +def get_org(repourl): + """ + Simple function to parse the organization out of a GitHub URL + """ + dprint("Current repourl to search: " + repourl) + # GitHub URLs can be: + # http[s]://www.github.com/org/repo + # or git@github.com:/org/repo + pattern = re.compile(r"github.com[/:]+(\w+)/") + m = re.search(pattern, repourl) + # Fail fast if this is wrong so we can add a pattern to the search + if m: + return m.group(1) + else: + raise Exception("Incorrect regex pattern finding repo org") + +def get_name(repourl): + """ + Simple function to parse the repository name out of a GitHub URL + """ + dprint("Current repourl to search: " + repourl) + repo_pattern = re.compile(r"github.com[/:]\w+/(\w+)") + m = re.search(repo_pattern, repourl) + if m: + return m.group(1) + else: + raise Exception("Incorrect rexex pattern finding repo url") + +def get_repo_url_from_remote(): + """ + Function that gets the repository URL from the `git remote` listing + """ + git_remote_bytes = subprocess.check_output(["git", "remote", "-v"]) + # check_output returns the command results in raw byte format + remote_string = git_remote_bytes.decode('utf-8') + + pattern = re.compile(r"github.com[/:]\w+/\w+") + m = re.search(pattern, remote_string) + if m: + return m.group(0) + else: + raise Exception("Incorrect rexex pattern finding repo url") + +def process_log(gitlog, repo_url): + """ + Handles the processing of the gitlog and returns a list + of PRs already formatted for output + """ + pr_list = search_prs(gitlog) + repoorg = get_org(repo_url) + reponame = get_name(repo_url) + pr_buffer = [] + for issue in pr_list: + pr_buffer.append(gh_get_issue_output(repoorg, reponame, issue)) + + return pr_buffer + +def fetch_log(old_ver, new_ver): + """ + Function that processes the git log between the old and new versions + """ + dprint("Current working directory", os.getcwd()) + gitlogbytes = subprocess.check_output(["git", "log", + str(old_ver + ".." + new_ver)]) + return gitlogbytes.decode('utf-8') + + +def compare_versions(repo_url, old_ver, new_ver): + # Formatted list of all PRs for all repos + pr_out = [] + gitlog = fetch_log(old_ver, new_ver) + pr_out.extend(process_log(gitlog, repo_url)) + return pr_out + +def main(): + args = get_args() + + # Setup the GitHub object for later use + global gh + gh = Github(get_env("GHAUTH")) + + if gh == "": + raise Exception("Env var GHAUTH must be set to a valid GitHub API key") + + if args.verbose: + global VERBOSE + VERBOSE=True + + dprint("Inspecting difference in between: ", args.old, " and ", args.new) + + # Find the github URL of the repo we are operating on + repo_url = get_repo_url_from_remote() + + # Compare old and new versions + pr_list = compare_versions(repo_url, args.old, args.new) + + # Writeout PR listing + print "Writing output to file %s" % args.file + with open(args.file, 'w') as output: + output.writelines(pr_list) + + +if __name__ == "__main__": + VERBOSE=False + gh=None + topdir=os.getcwd() + main() diff --git a/src/rebar_git_resource.erl b/src/rebar_git_resource.erl index e2f3f69..a0690bf 100644 --- a/src/rebar_git_resource.erl +++ b/src/rebar_git_resource.erl @@ -133,9 +133,10 @@ collect_default_refcount(Dir) -> {ok, RawCount} = case Tag of undefined -> - AbortMsg2 = "Getting rev-list of git depedency failed in " ++ rebar_dir:get_cwd(), + AbortMsg2 = "Getting rev-list of git depedency failed in " ++ Dir, {ok, PatchLines} = rebar_utils:sh("git rev-list HEAD", [{use_stdout, false}, + {cd, Dir}, {debug_abort_on_error, AbortMsg2}]), rebar_utils:line_count(PatchLines); _ -> @@ -164,6 +165,7 @@ get_patch_count(Dir, RawRef) -> [Ref]), {ok, PatchLines} = rebar_utils:sh(Cmd, [{use_stdout, false}, + {cd, Dir}, {debug_abort_on_error, AbortMsg}]), rebar_utils:line_count(PatchLines). diff --git a/src/rebar_prv_compile.erl b/src/rebar_prv_compile.erl index d76fbda..74be7a6 100644 --- a/src/rebar_prv_compile.erl +++ b/src/rebar_prv_compile.erl @@ -142,7 +142,7 @@ copy_app_dirs(State, OldAppDir, AppDir) -> end, %% link to src_dirs to be adjacent to ebin is needed for R15 use of cover/xref - SrcDirs = rebar_dir:all_src_dirs(State, ["src"], ["test"]), + SrcDirs = rebar_dir:all_src_dirs(State, ["src"], []), [symlink_or_copy(OldAppDir, AppDir, Dir) || Dir <- ["priv", "include"] ++ SrcDirs]; false -> ok diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index 28c0ed6..41dd434 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -85,7 +85,8 @@ format_error({error_running_tests, Reason}) -> test_state(State) -> ErlOpts = rebar_state:get(State, eunit_compile_opts, []), TestOpts = safe_define_test_macro(ErlOpts), - first_files(State) ++ [{erl_opts, TestOpts}]. + TestDir = [{extra_src_dirs, ["test"]}], + first_files(State) ++ [{erl_opts, TestOpts ++ TestDir}]. safe_define_test_macro(Opts) -> %% defining a compile macro twice results in an exception so @@ -106,49 +107,38 @@ first_files(State) -> prepare_tests(State) -> {RawOpts, _} = rebar_state:command_parsed_args(State), - resolve_apps(State, RawOpts). + ok = maybe_cover_compile(State, RawOpts), + ProjectApps = project_apps(State), + resolve_apps(ProjectApps, RawOpts). -resolve_apps(State, RawOpts) -> +maybe_cover_compile(State, Opts) -> + State1 = case proplists:get_value(cover, Opts, false) of + true -> rebar_state:set(State, cover_enabled, true); + false -> State + end, + rebar_prv_cover:maybe_cover_compile(State1). + +resolve_apps(ProjectApps, RawOpts) -> case proplists:get_value(app, RawOpts) of - undefined -> resolve_suites(State, RawOpts); + undefined -> resolve_suites(ProjectApps, RawOpts); %% convert app name strings to `rebar_app_info` objects Apps -> AppNames = string:tokens(Apps, [$,]), - ProjectApps = project_apps(State), case filter_apps_by_name(AppNames, ProjectApps) of - {ok, TestApps} -> resolve_suites(State, TestApps, RawOpts); + {ok, TestApps} -> resolve_suites(TestApps, RawOpts); Error -> Error end end. -resolve_suites(State, RawOpts) -> resolve_suites(State, project_apps(State), RawOpts). - -resolve_suites(State, Apps, RawOpts) -> +resolve_suites(Apps, RawOpts) -> case proplists:get_value(suite, RawOpts) of - undefined -> compile_tests(State, Apps, all, RawOpts); + undefined -> test_set(Apps, all); Suites -> SuiteNames = string:tokens(Suites, [$,]), case filter_suites_by_apps(SuiteNames, Apps) of - {ok, S} -> compile_tests(State, Apps, S, RawOpts); + {ok, S} -> test_set(Apps, S); Error -> Error end end. -compile_tests(State, TestApps, Suites, RawOpts) -> - F = fun(AppInfo) -> - S = rebar_app_info:state_or_new(State, AppInfo), - ok = rebar_erlc_compiler:compile(replace_src_dirs(S), - ec_cnv:to_list(rebar_app_info:out_dir(AppInfo))) - end, - lists:foreach(F, TestApps), - ok = maybe_cover_compile(State, RawOpts), - {ok, test_set(TestApps, Suites)}. - -maybe_cover_compile(State, Opts) -> - State1 = case proplists:get_value(cover, Opts, false) of - true -> rebar_state:set(State, cover_enabled, true); - false -> State - end, - rebar_prv_cover:maybe_cover_compile(State1). - project_apps(State) -> filter_checkouts(rebar_state:project_apps(State)). @@ -215,20 +205,8 @@ app_modules([App|Rest], Acc) -> app_modules(Rest, NewAcc) end. -replace_src_dirs(State) -> - %% replace any `src_dirs` with the test dirs - ErlOpts = rebar_state:get(State, erl_opts, []), - StrippedOpts = filter_src_dirs(ErlOpts), - case rebar_dir:extra_src_dirs(State) of - [] -> rebar_state:set(State, erl_opts, [{src_dirs, ["test"]}|StrippedOpts]); - _ -> rebar_state:set(State, erl_opts, StrippedOpts) - end. - -filter_src_dirs(ErlOpts) -> - lists:filter(fun({src_dirs, _}) -> false; (_) -> true end, ErlOpts). - -test_set(Apps, all) -> set_apps(Apps, []); -test_set(_Apps, Suites) -> set_suites(Suites, []). +test_set(Apps, all) -> {ok, set_apps(Apps, [])}; +test_set(_Apps, Suites) -> {ok, set_suites(Suites, [])}. set_apps([], Acc) -> lists:reverse(Acc); set_apps([App|Rest], Acc) -> |