def delete_repo(repo, username=None): """ Delete the present project. """ repo = progit.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to change the settings for this project') for issue in repo.issues: for comment in issue.comments: SESSION.delete(comment) SESSION.delete(issue) for request in repo.requests: SESSION.delete(request) SESSION.delete(repo) repopath = os.path.join(APP.config['GIT_FOLDER'], repo.path) if repo.is_fork: repopath = os.path.join(APP.config['FORK_FOLDER'], repo.path) docpath = os.path.join(APP.config['DOCS_FOLDER'], repo.path) try: shutil.rmtree(repopath) shutil.rmtree(docpath) SESSION.commit() except (OSError, IOError), err: APP.logger.exception(err) flask.flash('Could not delete the project from the system', 'error')
def edit_issue(repo, issueid, username=None): """ Edit the specified issue """ repo = progit.lib.get_project(SESSION, repo, user=username) if repo is None: flask.abort(404, 'Project not found') if not repo.issue_tracker: flask.abort(404, 'No issue tracker found for this project') if not is_repo_admin(repo): flask.abort(403, 'You are not allowed to edit issues for this project') issue = progit.lib.get_issue(SESSION, issueid) if issue is None or issue.project != repo: flask.abort(404, 'Issue not found') status = progit.lib.get_issue_statuses(SESSION) form = progit.forms.IssueForm(status=status) if form.validate_on_submit(): title = form.title.data content = form.issue_content.data status = form.status.data try: message = progit.lib.edit_issue( SESSION, issue=issue, title=title, content=content, status=status, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() flask.flash(message) url = flask.url_for('view_issue', username=username, repo=repo.name, issueid=issueid) return flask.redirect(url) except progit.exceptions.ProgitException, err: flask.flash(str(err), 'error') except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error')
def edit_issue(repo, issueid, username=None): """ Edit the specified issue """ repo = progit.lib.get_project(SESSION, repo, user=username) if repo is None: flask.abort(404, 'Project not found') if not repo.issue_tracker: flask.abort(404, 'No issue tracker found for this project') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to edit issues for this project') issue = progit.lib.get_issue(SESSION, issueid) if issue is None or issue.project != repo: flask.abort(404, 'Issue not found') status = progit.lib.get_issue_statuses(SESSION) form = progit.forms.IssueForm(status=status) if form.validate_on_submit(): title = form.title.data content = form.issue_content.data status = form.status.data try: message = progit.lib.edit_issue( SESSION, issue=issue, title=title, content=content, status=status, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() flask.flash(message) url = flask.url_for( 'view_issue', username=username, repo=repo.name, issueid=issueid) return flask.redirect(url) except progit.exceptions.ProgitException, err: flask.flash(str(err), 'error') except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error')
def view_issue(repo, issueid, username=None): """ List all issues associated to a repo """ repo = progit.lib.get_project(SESSION, repo, user=username) if repo is None: flask.abort(404, 'Project not found') if not repo.issue_tracker: flask.abort(404, 'No issue tracker found for this project') issue = progit.lib.get_issue(SESSION, issueid) if issue is None or issue.project != repo: flask.abort(404, 'Issue not found') status = progit.lib.get_issue_statuses(SESSION) form_comment = progit.forms.AddIssueCommentForm() form = None if authenticated() and is_repo_admin(repo): form = progit.forms.UpdateIssueStatusForm(status=status) if form.validate_on_submit(): try: message = progit.lib.edit_issue( SESSION, issue=issue, status=form.status.data, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() flask.flash(message) url = flask.url_for('view_issues', username=username, repo=repo.name) return flask.redirect(url) except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error') elif flask.request.method == 'GET': form.status.data = issue.status
def view_issue(repo, issueid, username=None): """ List all issues associated to a repo """ repo = progit.lib.get_project(SESSION, repo, user=username) if repo is None: flask.abort(404, 'Project not found') if not repo.issue_tracker: flask.abort(404, 'No issue tracker found for this project') issue = progit.lib.get_issue(SESSION, issueid) if issue is None or issue.project != repo: flask.abort(404, 'Issue not found') status = progit.lib.get_issue_statuses(SESSION) form_comment = progit.forms.AddIssueCommentForm() form = None if authenticated() and is_repo_admin(repo): form = progit.forms.UpdateIssueStatusForm(status=status) if form.validate_on_submit(): try: message = progit.lib.edit_issue( SESSION, issue=issue, status=form.status.data, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() flask.flash(message) url = flask.url_for( 'view_issues', username=username, repo=repo.name) return flask.redirect(url) except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error') elif flask.request.method == 'GET': form.status.data = issue.status
def view_settings(repo, username=None): """ Presents the settings of the project. """ repo = progit.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to change the settings for this project') plugins = progit.plugins.get_plugin_names() form = progit.forms.ProjectSettingsForm() if form.validate_on_submit(): issue_tracker = form.issue_tracker.data project_docs = form.project_docs.data try: message = progit.lib.update_project_settings( SESSION, repo=repo, issue_tracker=issue_tracker, project_docs=project_docs, ) SESSION.commit() flask.flash(message) return flask.redirect(flask.url_for( 'view_repo', username=username, repo=repo.name)) except progit.exceptions.ProgitException, err: flask.flash(str(err), 'error') except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error')
def request_pull(repo, requestid, username=None): """ Request pulling the changes from the fork into the project. """ repo = progit.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') request = progit.lib.get_pull_request(SESSION, project_id=repo.id, requestid=requestid) if not request: flask.abort(404, 'Pull-request not found') repo = request.repo_from if repo.is_fork: repopath = os.path.join(APP.config['FORK_FOLDER'], repo.path) else: repopath = os.path.join(APP.config['GIT_FOLDER'], repo.path) repo_obj = pygit2.Repository(repopath) if repo.parent: parentname = os.path.join(APP.config['GIT_FOLDER'], repo.parent.path) else: parentname = os.path.join(APP.config['GIT_FOLDER'], repo.path) orig_repo = pygit2.Repository(parentname) diff_commits = [] diffs = [] repo_commit = repo_obj[request.stop_id] if not repo_obj.is_empty and not orig_repo.is_empty: orig_commit = orig_repo[orig_repo.lookup_branch( 'master').get_object().hex] master_commits = [ commit.oid.hex for commit in orig_repo.walk( orig_repo.lookup_branch('master').get_object().hex, pygit2.GIT_SORT_TIME) ] repo_commit = repo_obj[request.start_id] for commit in repo_obj.walk(request.stop_id, pygit2.GIT_SORT_TIME): if commit.oid.hex in master_commits: break diff_commits.append(commit) diffs.append( repo_obj.diff( repo_obj.revparse_single(commit.parents[0].oid.hex), repo_obj.revparse_single(commit.oid.hex))) elif orig_repo.is_empty: orig_commit = None diff = repo_commit.tree.diff_to_tree(swap=True) else: flask.flash('Fork is empty, there are no commits to request pulling', 'error') return flask.redirect( flask.url_for('view_repo', username=username, repo=repo.name)) html_diffs = [] for diff in diffs: html_diffs.append( highlight(diff.patch, DiffLexer(), HtmlFormatter( noclasses=True, style="tango", ))) return flask.render_template( 'pull_request.html', select='requests', requestid=requestid, repo=repo, username=username, request=request, repo_admin=is_repo_admin(request.repo), repo_obj=repo_obj, orig_repo=orig_repo, diff_commits=diff_commits, diffs=diffs, html_diffs=html_diffs, )
def new_request_pull(repo, username=None, commitid=None): """ Request pulling the changes from the fork into the project. """ repo = progit.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404) if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to create pull-requests for this project') if repo.is_fork: repopath = os.path.join(APP.config['FORK_FOLDER'], repo.path) else: repopath = os.path.join(APP.config['GIT_FOLDER'], repo.path) repo_obj = pygit2.Repository(repopath) if repo.parent: parentname = os.path.join(APP.config['GIT_FOLDER'], repo.parent.path) else: parentname = os.path.join(APP.config['GIT_FOLDER'], repo.path) orig_repo = pygit2.Repository(parentname) frombranchname = flask.request.args.get('from_branch', 'master') frombranch = repo_obj.lookup_branch(frombranchname) if not frombranch: flask.flash('Branch %s does not exist' % frombranchname, 'error') frombranchname = 'master' branchname = flask.request.args.get('branch', 'master') branch = orig_repo.lookup_branch(branchname) if not branch: flask.flash('Branch %s does not exist' % branchname, 'error') branchname = 'master' if commitid is None: commitid = repo_obj.head.target if branchname: branch = repo_obj.lookup_branch(frombranchname) commitid = branch.get_object().hex diff_commits = [] diffs = [] if not repo_obj.is_empty and not orig_repo.is_empty: orig_commit = orig_repo[orig_repo.lookup_branch( branchname).get_object().hex] master_commits = [ commit.oid.hex for commit in orig_repo.walk( orig_repo.lookup_branch(branchname).get_object().hex, pygit2.GIT_SORT_TIME) ] repo_commit = repo_obj[commitid] for commit in repo_obj.walk(repo_commit.oid.hex, pygit2.GIT_SORT_TIME): if commit.oid.hex in master_commits: break diff_commits.append(commit) diffs.append( repo_obj.diff( repo_obj.revparse_single(commit.parents[0].oid.hex), repo_obj.revparse_single(commit.oid.hex))) elif orig_repo.is_empty: orig_commit = None repo_commit = repo_obj[repo_obj.head.target] diff = repo_commit.tree.diff_to_tree(swap=True) else: flask.flash('Fork is empty, there are no commits to request pulling', 'error') return flask.redirect( flask.url_for('view_repo', username=username, repo=repo.name)) html_diffs = [] for diff in diffs: html_diffs.append( highlight(diff.patch, DiffLexer(), HtmlFormatter( noclasses=True, style="tango", ))) form = progit.forms.RequestPullForm() if form.validate_on_submit(): try: if orig_commit: orig_commit = orig_commit.oid.hex parent = repo if repo.parent: parent = repo.parent message = progit.lib.new_pull_request( SESSION, repo=parent, repo_from=repo, branch=branchname, title=form.title.data, start_id=orig_commit, stop_id=repo_commit.oid.hex, user=flask.g.fas_user.username, ) SESSION.commit() flask.flash(message) if not parent.is_fork: url = flask.url_for('request_pulls', username=None, repo=parent.name) else: url = flask.url_for('request_pulls', username=parent.user, repo=parent.name) return flask.redirect(url) except progit.exceptions.ProgitException, err: flask.flash(str(err), 'error') except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error')
def merge_request_pull(repo, requestid, username=None): """ Request pulling the changes from the fork into the project. """ repo = progit.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') request = progit.lib.get_pull_request(SESSION, project_id=repo.id, requestid=requestid) if not request: flask.abort(404, 'Pull-request not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to merge pull-request for this project') error_output = flask.url_for('request_pull', repo=repo.name, requestid=requestid) if username: error_output = flask.url_for('fork_request_pull', repo=repo.name, requestid=requestid, username=username) # Get the fork if request.repo_from.is_fork: repopath = os.path.join(APP.config['FORK_FOLDER'], request.repo_from.path) else: repopath = os.path.join(APP.config['GIT_FOLDER'], request.repo_from.path) fork_obj = pygit2.Repository(repopath) # Get the original repo parentpath = os.path.join(APP.config['GIT_FOLDER'], request.repo.path) orig_repo = pygit2.Repository(parentpath) # Clone the original repo into a temp folder newpath = tempfile.mkdtemp() new_repo = pygit2.clone_repository(parentpath, newpath) repo_commit = fork_obj[request.stop_id] ori_remote = new_repo.remotes[0] # Add the fork as remote repo reponame = '%s_%s' % (request.user.user, repo.name) remote = new_repo.create_remote(reponame, repopath) # Fetch the commits remote.fetch() merge = new_repo.merge(repo_commit.oid) master_ref = new_repo.lookup_reference('HEAD').resolve() refname = '%s:%s' % (master_ref.name, master_ref.name) if merge.is_uptodate: flask.flash('Nothing to do, changes were already merged', 'error') progit.lib.close_pull_request(SESSION, request) SESSION.commit() return flask.redirect(error_output) elif merge.is_fastforward: master_ref.target = merge.fastforward_oid ori_remote.push(refname) flask.flash('Changes merged!') else: new_repo.index.write() try: tree = new_repo.index.write_tree() except pygit2.GitError: shutil.rmtree(newpath) flask.flash('Merge conflicts!', 'error') return flask.redirect( flask.url_for('request_pull', repo=repo.name, username=username, requestid=requestid)) head = new_repo.lookup_reference('HEAD').get_object() commit = new_repo[head.oid] sha = new_repo.create_commit( 'refs/heads/master', repo_commit.author, repo_commit.committer, 'Merge #%s `%s`' % (request.id, request.title), tree, [head.hex, repo_commit.oid.hex]) ori_remote.push(refname) flask.flash('Changes merged!') # Update status progit.lib.close_pull_request(SESSION, request) SESSION.commit() shutil.rmtree(newpath) return flask.redirect(flask.url_for('view_repo', repo=repo.name))
def view_plugin_page(repo, plugin, full, username=None): """ Presents the settings of the project. """ repo = progit.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to change the settings for this project') plugin = get_plugin(plugin) fields = [] new = True dbobj = plugin.db_object() if hasattr(repo, plugin.backref): dbobj = getattr(repo, plugin.backref) # There should always be only one, but let's double check if dbobj and len(dbobj) > 0: dbobj = dbobj[0] new = False else: dbobj = plugin.db_object() form = plugin.form(obj=dbobj) for field in plugin.form_fields: fields.append(getattr(form, field)) if form.validate_on_submit(): form.populate_obj(obj=dbobj) if new: dbobj.project_id = repo.id SESSION.add(dbobj) try: SESSION.flush() except SQLAlchemyError, err: SESSION.rollback() APP.logger.debug('Could not add plugin %s', plugin.name) APP.logger.exception(err) flask.flash( 'Could not add plugin %s, please contact an admin' % plugin.name) return flask.render_template( 'plugin.html', select='settings', full=full, repo=repo, username=username, plugin=plugin, form=form, fields=fields, ) if form.active.data: # Set up the main script if necessary plugin.set_up(repo) # Install the plugin itself plugin.install(repo, dbobj) flask.flash('Hook activated') else: plugin.remove(repo) flask.flash('Hook inactived') SESSION.commit()
def request_pull(repo, requestid, username=None): """ Request pulling the changes from the fork into the project. """ repo = progit.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') request = progit.lib.get_pull_request( SESSION, project_id=repo.id, requestid=requestid) if not request: flask.abort(404, 'Pull-request not found') repo = request.repo_from if repo.is_fork: repopath = os.path.join(APP.config['FORK_FOLDER'], repo.path) else: repopath = os.path.join(APP.config['GIT_FOLDER'], repo.path) repo_obj = pygit2.Repository(repopath) if repo.parent: parentname = os.path.join(APP.config['GIT_FOLDER'], repo.parent.path) else: parentname = os.path.join(APP.config['GIT_FOLDER'], repo.path) orig_repo = pygit2.Repository(parentname) diff_commits = [] diffs = [] repo_commit = repo_obj[request.stop_id] if not repo_obj.is_empty and not orig_repo.is_empty: orig_commit = orig_repo[ orig_repo.lookup_branch('master').get_object().hex] master_commits = [ commit.oid.hex for commit in orig_repo.walk( orig_repo.lookup_branch('master').get_object().hex, pygit2.GIT_SORT_TIME) ] repo_commit = repo_obj[request.start_id] for commit in repo_obj.walk( request.stop_id, pygit2.GIT_SORT_TIME): if commit.oid.hex in master_commits: break diff_commits.append(commit) diffs.append( repo_obj.diff( repo_obj.revparse_single(commit.parents[0].oid.hex), repo_obj.revparse_single(commit.oid.hex) ) ) elif orig_repo.is_empty: orig_commit = None diff = repo_commit.tree.diff_to_tree(swap=True) else: flask.flash( 'Fork is empty, there are no commits to request pulling', 'error') return flask.redirect(flask.url_for( 'view_repo', username=username, repo=repo.name)) html_diffs = [] for diff in diffs: html_diffs.append( highlight( diff.patch, DiffLexer(), HtmlFormatter( noclasses=True, style="tango",) ) ) return flask.render_template( 'pull_request.html', select='requests', requestid=requestid, repo=repo, username=username, request=request, repo_admin=is_repo_admin(request.repo), repo_obj=repo_obj, orig_repo=orig_repo, diff_commits=diff_commits, diffs=diffs, html_diffs=html_diffs, )
def new_request_pull(repo, username=None, commitid=None): """ Request pulling the changes from the fork into the project. """ repo = progit.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404) if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to create pull-requests for this project') if repo.is_fork: repopath = os.path.join(APP.config['FORK_FOLDER'], repo.path) else: repopath = os.path.join(APP.config['GIT_FOLDER'], repo.path) repo_obj = pygit2.Repository(repopath) if repo.parent: parentname = os.path.join(APP.config['GIT_FOLDER'], repo.parent.path) else: parentname = os.path.join(APP.config['GIT_FOLDER'], repo.path) orig_repo = pygit2.Repository(parentname) frombranchname = flask.request.args.get('from_branch', 'master') frombranch = repo_obj.lookup_branch(frombranchname) if not frombranch: flask.flash('Branch %s does not exist' % frombranchname, 'error') frombranchname = 'master' branchname = flask.request.args.get('branch', 'master') branch = orig_repo.lookup_branch(branchname) if not branch: flask.flash('Branch %s does not exist' % branchname, 'error') branchname = 'master' if commitid is None: commitid = repo_obj.head.target if branchname: branch = repo_obj.lookup_branch(frombranchname) commitid = branch.get_object().hex diff_commits = [] diffs = [] if not repo_obj.is_empty and not orig_repo.is_empty: orig_commit = orig_repo[ orig_repo.lookup_branch(branchname).get_object().hex] master_commits = [ commit.oid.hex for commit in orig_repo.walk( orig_repo.lookup_branch(branchname).get_object().hex, pygit2.GIT_SORT_TIME) ] repo_commit = repo_obj[commitid] for commit in repo_obj.walk( repo_commit.oid.hex, pygit2.GIT_SORT_TIME): if commit.oid.hex in master_commits: break diff_commits.append(commit) diffs.append( repo_obj.diff( repo_obj.revparse_single(commit.parents[0].oid.hex), repo_obj.revparse_single(commit.oid.hex) ) ) elif orig_repo.is_empty: orig_commit = None repo_commit = repo_obj[repo_obj.head.target] diff = repo_commit.tree.diff_to_tree(swap=True) else: flask.flash( 'Fork is empty, there are no commits to request pulling', 'error') return flask.redirect(flask.url_for( 'view_repo', username=username, repo=repo.name)) html_diffs = [] for diff in diffs: html_diffs.append( highlight( diff.patch, DiffLexer(), HtmlFormatter( noclasses=True, style="tango",) ) ) form = progit.forms.RequestPullForm() if form.validate_on_submit(): try: if orig_commit: orig_commit = orig_commit.oid.hex parent = repo if repo.parent: parent = repo.parent message = progit.lib.new_pull_request( SESSION, repo=parent, repo_from=repo, branch=branchname, title=form.title.data, start_id=orig_commit, stop_id=repo_commit.oid.hex, user=flask.g.fas_user.username, ) SESSION.commit() flask.flash(message) if not parent.is_fork: url = flask.url_for( 'request_pulls', username=None, repo=parent.name) else: url = flask.url_for( 'request_pulls', username=parent.user, repo=parent.name) return flask.redirect(url) except progit.exceptions.ProgitException, err: flask.flash(str(err), 'error') except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error')
def merge_request_pull(repo, requestid, username=None): """ Request pulling the changes from the fork into the project. """ repo = progit.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') request = progit.lib.get_pull_request( SESSION, project_id=repo.id, requestid=requestid) if not request: flask.abort(404, 'Pull-request not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to merge pull-request for this project') error_output = flask.url_for( 'request_pull', repo=repo.name, requestid=requestid) if username: error_output = flask.url_for( 'fork_request_pull', repo=repo.name, requestid=requestid, username=username) # Get the fork if request.repo_from.is_fork: repopath = os.path.join( APP.config['FORK_FOLDER'], request.repo_from.path) else: repopath = os.path.join( APP.config['GIT_FOLDER'], request.repo_from.path) fork_obj = pygit2.Repository(repopath) # Get the original repo parentpath = os.path.join(APP.config['GIT_FOLDER'], request.repo.path) orig_repo = pygit2.Repository(parentpath) # Clone the original repo into a temp folder newpath = tempfile.mkdtemp() new_repo = pygit2.clone_repository(parentpath, newpath) repo_commit = fork_obj[request.stop_id] ori_remote = new_repo.remotes[0] # Add the fork as remote repo reponame = '%s_%s' % (request.user.user, repo.name) remote = new_repo.create_remote(reponame, repopath) # Fetch the commits remote.fetch() merge = new_repo.merge(repo_commit.oid) master_ref = new_repo.lookup_reference('HEAD').resolve() refname = '%s:%s' % (master_ref.name, master_ref.name) if merge.is_uptodate: flask.flash('Nothing to do, changes were already merged', 'error') progit.lib.close_pull_request(SESSION, request) SESSION.commit() return flask.redirect(error_output) elif merge.is_fastforward: master_ref.target = merge.fastforward_oid ori_remote.push(refname) flask.flash('Changes merged!') else: new_repo.index.write() try: tree = new_repo.index.write_tree() except pygit2.GitError: shutil.rmtree(newpath) flask.flash('Merge conflicts!', 'error') return flask.redirect(flask.url_for( 'request_pull', repo=repo.name, username=username, requestid=requestid)) head = new_repo.lookup_reference('HEAD').get_object() commit = new_repo[head.oid] sha = new_repo.create_commit( 'refs/heads/master', repo_commit.author, repo_commit.committer, 'Merge #%s `%s`' % (request.id, request.title), tree, [head.hex, repo_commit.oid.hex]) ori_remote.push(refname) flask.flash('Changes merged!') # Update status progit.lib.close_pull_request(SESSION, request) SESSION.commit() shutil.rmtree(newpath) return flask.redirect(flask.url_for('view_repo', repo=repo.name))