summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rwxr-xr-xpr2relnotes.py188
-rw-r--r--src/rebar_git_resource.erl4
-rw-r--r--src/rebar_prv_compile.erl2
-rw-r--r--src/rebar_prv_eunit.erl62
5 files changed, 213 insertions, 44 deletions
diff --git a/.gitignore b/.gitignore
index 8028d9c..c6be7ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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) ->