<% # API my $api = gitprep_api; # Parameters my $base_user_id = param('user'); my $base_project_id = param('project'); my $base_branch = param('rev1'); my $user_id_and_target_branch = param('rev2'); my $page = param('page') || 0; my $expand = param('expand'); # Default base branch $base_branch //= app->manager->default_branch($base_user_id, $base_project_id); # Base project my $base_project = app->dbi->model('project')->select( [ {__MY__ => '*'}, {user => ['id']} ], where => {'project.id' => $base_project_id, 'user.id' => $base_user_id} )->one; # Get target user, project, branch my $target_user_id; my $target_branch; my $target_project; if (defined $user_id_and_target_branch && $user_id_and_target_branch =~ /^([^:]+):(.+)/) { $target_user_id = $1; $target_branch = $2; $target_project = $self->app->manager->child_project($base_user_id, $base_project_id, $target_user_id); } else { $target_user_id = $base_user_id; $target_branch = $user_id_and_target_branch // $base_branch; $target_project = $base_project } # Already pull request exists my $pull_request_already = app->dbi->model('pull_request')->select( where => { base_project => $base_project->{row_id}, base_branch => $base_branch, target_project => $target_project->{row_id}, target_branch => $target_branch } )->one; # Git my $git = $self->app->git; my $errors; if (lc $self->req->method eq 'post') { my $op = param('op'); if ($op eq 'create-pull-request') { if ($pull_request_already) { $self->render_exception("Error"); } # Parameters my $title = param('title'); my $message = param('message'); # Validation my $vc = app->vc; my $validation = $vc->validation; # Check title if (!(defined $title && length $title)) { $validation->add_failed(title => 'title is empty'); } elsif (length $title > 300) { $validation->add_failed(title => 'title is too long'); } # Message if (!(defined $message && length $message)) { $message = ''; if (length $message > 1000) { $validation->add_failed(message => 'message is too long'); } } if ($validation->is_valid) { my $project_row_id = app->dbi->model('project')->select( 'project.row_id', where => {'user.id' => $base_user_id, 'project.id' => $base_project_id} )->value; my $pull_request = app->dbi->model('pull_request')->select( where => { base_project => $project_row_id, base_branch => $base_branch, target_project => $target_project->{row_id}, target_branch => $target_branch } )->one; my $issue; if ($pull_request) { $issue = app->dbi->model('issue')->select( where => {pull_request => $pull_request->{row_id}} )->one; $self->redirect_to("/$base_user_id/$base_project_id/pull/$issue->{number}"); return; } else { my $now_tm = Time::Moment->now_utc; my $now_epoch = $now_tm->epoch; my $session_user_row_id = $api->session_user_row_id; my $issue_number; app->dbi->connector->txn(sub { # New pull request my $new_pull_request = { base_project => $project_row_id, base_branch => $base_branch, target_project => $target_project->{row_id}, target_branch => $target_branch, }; # last pull request row id app->dbi->model('pull_request')->insert($new_pull_request); my $new_pull_request_row_id = app->dbi->execute("select LAST_INSERT_ROWID()")->value; # issue number $issue_number = app->dbi->model('issue')->select( 'max(number)', where => {project => $project_row_id}, append => 'group by project' )->value; $issue_number++; # New issue my $new_issue = { title => $title, open => 1, open_time => $now_epoch, open_user => $session_user_row_id, pull_request => $new_pull_request_row_id, project => $project_row_id, number => $issue_number }; app->dbi->model('issue')->insert($new_issue); my $new_issue_row_id = app->dbi->execute("select LAST_INSERT_ROWID()")->value; # New issue message my $new_issue_message = { issue => $new_issue_row_id, number => 1, message => $message, create_time => $now_epoch, update_time => $now_epoch, user => $session_user_row_id }; app->dbi->model('issue_message')->insert($new_issue_message); }); $self->redirect_to("/$base_user_id/$base_project_id/pull/$issue_number"); return; } } else { $errors = $validation->messages; } } } # Can merge my $base_rep_info = app->rep_info($base_user_id, $base_project_id); my $merge_success; my $target_rep_info; if ($target_project) { $target_rep_info = app->rep_info($target_user_id, $target_project->{id}); } else { $target_rep_info = $base_rep_info; } # Create working repository if it don't exist $self->app->manager->create_work_rep($base_user_id, $base_project_id); # Lock working repository my $work_rep_info = app->work_rep_info($base_user_id, $base_project_id); { my $lock_fh = $self->app->manager->lock_rep($work_rep_info); # Prepare merge $self->app->manager->prepare_merge( $work_rep_info, $base_rep_info, $base_branch, $target_rep_info, $target_branch ); # Check merge automatically $merge_success = $self->app->manager->merge( $work_rep_info, $target_rep_info, $target_branch ); } # Commits my $commits = $git->forward_commits( $work_rep_info, $base_rep_info, $base_branch, $target_rep_info, $target_branch ); my $commits_count = @$commits; my $commits_date = {}; my $authors = {}; for my $commit (@$commits) { my $date = $commit->{age_string_date_local}; $commits_date->{$date} ||= []; $authors->{$commit->{author}} = 1; push @{$commits_date->{$date}}, $commit; } my $authors_count = keys %$authors; # Start commit my $start_commit_id = app->git->ref_to_object_id($base_rep_info, $base_branch); # End commit my $end_commit_id = app->git->ref_to_object_id($target_rep_info, $target_branch); if (!$start_commit_id || !$end_commit_id) { $self->reply->not_found; return; } # Member projects my $member_projects = app->manager->member_projects($base_user_id, $base_project_id); unshift @$member_projects, $base_project; # Base branches my $base_branches = $git->branches($base_rep_info); @$base_branches = sort { $a->{commit}{age} <=> $b->{commit}{age} } @$base_branches; # Target branches my $target_branches = $git->branches($target_rep_info); @$target_branches = sort { $a->{commit}{age} <=> $b->{commit}{age} } @$target_branches; # Can open pull request my $can_open_pull_request; if (keys %$commits_date && $expand) { $can_open_pull_request = 1; } # commit_body args my %commit_body_args = ( user => $target_user_id, project => $target_project->{id}, rep_info => $work_rep_info, rev => $end_commit_id, from_rev => $start_commit_id ); layout 'common', title => "Comparing $base_branch...$target_branch \x{30fb} $base_user_id/$base_project_id"; %> %= javascript begin $(document).ready(function () { // Change base fork $('#base-fork-btn').on('click', function () { $('#base-fork-popup') .css('display', 'block') .css('top', '40px') .css('left', '10px') ; }); $('#base-fork-popup').on('click', function () { $('#base-fork-popup').css('display', 'none'); }); // close popup $(document).click(function() { $('#base-fork-popup').hide(); }); $('#base-fork-btn').click(function() { event.stopPropagation(); }); $('#base-fork-popup').click(function() { event.stopPropagation(); }); // Change head fork $('#head-fork-btn').on('click', function () { $('#head-fork-popup') .css('display', 'block') .css('top', '40px') .css('left', '10px') ; }); $('#head-fork-popup').on('click', function () { $('#head-fork-popup').css('display', 'none'); }); // close popup $(document).click(function() { $('#head-fork-popup').hide(); }); $('#head-fork-btn').click(function() { event.stopPropagation(); }); $('#head-fork-popup').click(function() { event.stopPropagation(); }); // Change base branch $('#base-branch-btn').on('click', function () { $('#base-branch-popup') .css('display', 'block') .css('top', '40px') .css('left', '10px') ; }); $('#base-branch-close').on('click', function () { $('#base-branch-popup').css('display', 'none'); }); $('[name=base-branch]').on('keypress', function (e) { // Enter if (e.which == 13) { var href; % if ($base_user_id eq $target_user_id) { href = '<%= url_for("/$base_user_id/$base_project_id/compare/") %>' + $(this).val() + '...<%= $target_branch %>'; % } else { href = '<%= url_for("/$base_user_id/$base_project_id/compare/") %>' + $(this).val() + '...<%= $target_user_id %>:<%= $target_branch %>'; % } if (<%= $expand ? 1 : 0 %>) { href = href + '?expand=1'; } location.href = href; } }); // close popup $(document).click(function() { $('#base-branch-popup').hide(); }); $('#base-branch-btn').click(function() { event.stopPropagation(); }); $('#base-branch-popup').click(function() { event.stopPropagation(); }); // Change compare branch $('#target-branch-btn').on('click', function () { $('#target-branch-popup') .css('display', 'block') .css('top', '40px') .css('left', '96px') ; }); $('#target-branch-close').on('click', function () { $('#target-branch-popup').css('display', 'none'); }); $('[name=target-branch]').on('keypress', function (e) { // Enter if (e.which == 13) { var href = '<%= url_for("/$base_user_id/$base_project_id/compare/") %>' + '<%= $base_branch %>...' + $(this).val(); if (<%= $expand ? 1 : 0 %>) { href = href + '?expand=1'; } location.href = href; } }); // close popup $(document).click(function() { $('#target-branch-popup').hide(); }); $('#target-branch-btn').click(function() { event.stopPropagation(); }); $('#target-branch-popup').click(function() { event.stopPropagation(); }); %= include '/include/add_issue_form_js'; }); % end %= javascript begin $(document).ready(function () { $('#comapre-across-btn').on('click', function () { $('#base-fork-btn').toggle(); $('#head-fork-btn').toggle(); }); }); % end %= include '/include/header';
%= include '/include/errors', errors => $errors;
% if ($can_open_pull_request) { Open a pull request % } else { Compare changes % }
Compare changes across branches, commits, tags, and more below. If you need to, you can also compare across forks.
...
% if ($can_open_pull_request) { % if ($merge_success) { <%= "\x{2714}" %>Able to merge. These branches can be automatically merged. % } else { Not able to merge. These branches can't be automatically merged. % } % }
% if ($pull_request_already) { <% my $issue = app->dbi->model('issue')->select( where => { project => $base_project->{row_id}, pull_request => $pull_request_already->{row_id} } )->one; %> % } elsif (keys %$commits_date && $merge_success) {
<%= hidden_field op => 'create-pull-request' %>
<%= text_field 'title' => $commits->[0]{title_short} %>
%= include '/include/issue_comment_icon';
<%= text_area 'message' %>
Styling with Markdown is supported
% } % if (keys %$commits_date) {
% for my $date (reverse sort keys %$commits_date) { % my $commits = $commits_date->{$date};
Commits on <%= $date %>
% }
%= include '/include/commit_body', %commit_body_args; % } else {
There isn't anything to compare.
<%= $base_branch %> is up to date with all commits from <%= $target_branch %>. Try ">switching the base for your comparison.
% }
%= include '/include/footer';