def view_issue_raw_file(repo, filename=None, username=None): """ Displays the raw content of a file of a commit for the specified ticket repo. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') reponame = os.path.join(APP.config['TICKETS_FOLDER'], repo.path) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, 'Empty repo cannot have a file') branch = repo_obj.lookup_branch('master') commit = branch.get_object() mimetype = None encoding = None content = __get_file_in_tree(repo_obj, commit.tree, filename.split('/'), bail_on_tree=True) if not content or isinstance(content, pygit2.Tree): flask.abort(404, 'File not found') mimetype, encoding = mimetypes.guess_type(filename) data = repo_obj[content.oid].data if not data: flask.abort(404, 'No content found') if not mimetype and data[:2] == '#!': mimetype = 'text/plain' headers = {} if not mimetype: if '\0' in data: mimetype = 'application/octet-stream' else: mimetype = 'text/plain' elif 'html' in mimetype: mimetype = 'application/octet-stream' headers['Content-Disposition'] = 'attachment' if mimetype.startswith('text/') and not encoding: encoding = chardet.detect(ktc.to_bytes(data))['encoding'] headers['Content-Type'] = mimetype if encoding: headers['Content-Encoding'] = encoding return (data, 200, headers)
def view_issue_raw_file(repo, filename=None, username=None): """ Displays the raw content of a file of a commit for the specified ticket repo. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') reponame = os.path.join(APP.config['TICKETS_FOLDER'], repo.path) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, 'Empty repo cannot have a file') branch = repo_obj.lookup_branch('master') commit = branch.get_object() mimetype = None encoding = None content = __get_file_in_tree( repo_obj, commit.tree, filename.split('/'), bail_on_tree=True) if not content or isinstance(content, pygit2.Tree): flask.abort(404, 'File not found') mimetype, encoding = mimetypes.guess_type(filename) data = repo_obj[content.oid].data if not data: flask.abort(404, 'No content found') if not mimetype and data[:2] == '#!': mimetype = 'text/plain' headers = {} if not mimetype: if '\0' in data: mimetype = 'application/octet-stream' else: mimetype = 'text/plain' elif 'html' in mimetype: mimetype = 'application/octet-stream' headers['Content-Disposition'] = 'attachment' if mimetype.startswith('text/') and not encoding: encoding = chardet.detect(ktc.to_bytes(data))['encoding'] headers['Content-Type'] = mimetype if encoding: headers['Content-Encoding'] = encoding return (data, 200, headers)
def new_issue(repo, username=None, namespace=None): """ Create a new issue """ repo = flask.g.repo if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') form = pagure.forms.IssueFormSimplied() if form.validate_on_submit(): title = form.title.data content = form.issue_content.data private = form.private.data try: user_obj = pagure.lib.get_user( SESSION, flask.g.fas_user.username) except pagure.exceptions.PagureException: flask.abort( 404, 'No such user found in the database: %s' % ( flask.g.fas_user.username)) try: issue = pagure.lib.new_issue( SESSION, repo=repo, title=title, content=content, private=private or False, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() # If there is a file attached, attach it. filestream = flask.request.files.get('filestream') if filestream and '<!!image>' in issue.content: new_filename = pagure.lib.git.add_file_to_git( repo=repo, issue=issue, ticketfolder=APP.config['TICKETS_FOLDER'], user=user_obj, filename=filestream.filename, filestream=filestream.stream, ) # Replace the <!!image> tag in the comment with the link # to the actual image filelocation = flask.url_for( 'view_issue_raw_file', repo=repo.name, username=username, filename=new_filename, ) new_filename = new_filename.split('-', 1)[1] url = '[![%s](%s)](%s)' % ( new_filename, filelocation, filelocation) issue.content = issue.content.replace('<!!image>', url) SESSION.add(issue) SESSION.commit() return flask.redirect(flask.url_for( '.view_issue', username=username, repo=repo.name, namespace=namespace, issueid=issue.id)) except pagure.exceptions.PagureException as err: flask.flash(str(err), 'error') except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error') types = None default = None ticketrepopath = os.path.join(APP.config['TICKETS_FOLDER'], repo.path) if os.path.exists(ticketrepopath): ticketrepo = pygit2.Repository(ticketrepopath) if not ticketrepo.is_empty and not ticketrepo.head_is_unborn: commit = ticketrepo[ticketrepo.head.target] # Get the different ticket types files = __get_file_in_tree( ticketrepo, commit.tree, ['templates'], bail_on_tree=True) if files: types = [f.name.rstrip('.md') for f in files] # Get the default template default_file = __get_file_in_tree( ticketrepo, commit.tree, ['templates', 'default.md'], bail_on_tree=True) if default_file: default, _ = pagure.doc_utils.convert_readme( default_file.data, 'md') if flask.request.method == 'GET': form.private.data = repo.settings.get( 'issues_default_to_private', False) return flask.render_template( 'new_issue.html', select='issues', form=form, repo=repo, username=username, types=types, default=default, )
def view_repo(repo, username=None): """ Front page of a specific repo. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if repo is None: flask.abort(404, 'Project not found') reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if not repo_obj.is_empty and not repo_obj.head_is_unborn: head = repo_obj.head.shorthand else: head = None cnt = 0 last_commits = [] tree = [] if not repo_obj.is_empty: try: for commit in repo_obj.walk( repo_obj.head.target, pygit2.GIT_SORT_TIME): last_commits.append(commit) cnt += 1 if cnt == 3: break tree = sorted(last_commits[0].tree, key=lambda x: x.filemode) except pygit2.GitError: pass readme = None safe = False if not repo_obj.is_empty and not repo_obj.head_is_unborn: branchname = repo_obj.head.shorthand else: branchname = None for i in tree: name, ext = os.path.splitext(i.name) if name == 'README': content = __get_file_in_tree( repo_obj, last_commits[0].tree, [i.name]).data readme, safe = pagure.doc_utils.convert_readme( content, ext, view_file_url=flask.url_for( 'view_raw_file', username=username, repo=repo.name, identifier=branchname, filename='')) diff_commits = [] if repo.is_fork: parentname = os.path.join( APP.config['GIT_FOLDER'], repo.parent.path) if repo.parent.is_fork: parentname = os.path.join( APP.config['FORK_FOLDER'], repo.parent.path) else: parentname = os.path.join(APP.config['GIT_FOLDER'], repo.path) orig_repo = pygit2.Repository(parentname) if not repo_obj.is_empty and not orig_repo.is_empty: orig_branch = orig_repo.lookup_branch('master') branch = repo_obj.lookup_branch('master') if orig_branch and branch: master_commits = [ commit.oid.hex for commit in orig_repo.walk( orig_branch.get_object().hex, pygit2.GIT_SORT_TIME) ] repo_commit = repo_obj[branch.get_object().hex] 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.oid.hex) return flask.render_template( 'repo_info.html', select='overview', repo=repo, repo_obj=repo_obj, username=username, head=head, readme=readme, safe=safe, branches=sorted(repo_obj.listall_branches()), branchname=branchname, last_commits=last_commits, tree=tree, diff_commits=diff_commits, repo_admin=is_repo_admin(repo), form=pagure.forms.ConfirmationForm(), )
def view_raw_file(repo, identifier, filename=None, username=None): """ Displays the raw content of a file of a commit for the specified repo. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, 'Empty repo cannot have a file') if identifier in repo_obj.listall_branches(): branch = repo_obj.lookup_branch(identifier) commit = branch.get_object() else: try: commit = repo_obj.get(identifier) except ValueError: if 'master' not in repo_obj.listall_branches(): flask.abort(404, 'Branch no found') # If it's not a commit id then it's part of the filename commit = repo_obj[repo_obj.head.target] if not commit: flask.abort(400, 'Commit %s not found' % (identifier)) mimetype = None encoding = None if filename: content = __get_file_in_tree( repo_obj, commit.tree, filename.split('/'), bail_on_tree=True) if not content or isinstance(content, pygit2.Tree): flask.abort(404, 'File not found') mimetype, encoding = mimetypes.guess_type(filename) data = repo_obj[content.oid].data else: if commit.parents: diff = commit.tree.diff_to_tree() try: parent = repo_obj.revparse_single('%s^' % identifier) diff = repo_obj.diff(parent, commit) except (KeyError, ValueError): flask.abort(404, 'Identifier not found') else: # First commit in the repo diff = commit.tree.diff_to_tree(swap=True) data = diff.patch if not data: flask.abort(404, 'No content found') if not mimetype and data[:2] == '#!': mimetype = 'text/plain' if not mimetype: if '\0' in data: mimetype = 'application/octet-stream' else: mimetype = 'text/plain' if mimetype.startswith('text/') and not encoding: encoding = chardet.detect(ktc.to_bytes(data))['encoding'] headers = {'Content-Type': mimetype} if encoding: headers['Content-Encoding'] = encoding return (data, 200, headers)
def view_file(repo, identifier, filename, username=None): """ Displays the content of a file or a tree for the specified repo. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, 'Empty repo cannot have a file') if identifier in repo_obj.listall_branches(): branchname = identifier branch = repo_obj.lookup_branch(identifier) commit = branch.get_object() else: try: commit = repo_obj.get(identifier) branchname = identifier except ValueError: if 'master' not in repo_obj.listall_branches(): flask.abort(404, 'Branch no found') # If it's not a commit id then it's part of the filename commit = repo_obj[repo_obj.head.target] branchname = 'master' if commit and not isinstance(commit, pygit2.Blob): content = __get_file_in_tree( repo_obj, commit.tree, filename.split('/'), bail_on_tree=True) if not content: flask.abort(404, 'File not found') content = repo_obj[content.oid] else: content = commit if not content: flask.abort(404, 'File not found') if isinstance(content, pygit2.Blob): if content.is_binary or not pagure.lib.could_be_text(content.data): ext = filename[filename.rfind('.'):] if ext in ( '.gif', '.png', '.bmp', '.tif', '.tiff', '.jpg', '.jpeg', '.ppm', '.pnm', '.pbm', '.pgm', '.webp', '.ico'): try: Image.open(StringIO(content.data)) output_type = 'image' except IOError as err: LOG.debug( 'Failed to load image %s, error: %s', filename, err ) output_type = 'binary' else: output_type = 'binary' else: try: lexer = guess_lexer_for_filename( filename, content.data ) except (ClassNotFound, TypeError): lexer = TextLexer() content = highlight( content.data, lexer, HtmlFormatter( noclasses=True, style="tango",) ) output_type = 'file' else: content = sorted(content, key=lambda x: x.filemode) output_type = 'tree' return flask.render_template( 'file.html', select='tree', repo=repo, username=username, branchname=branchname, filename=filename, content=content, output_type=output_type, repo_admin=is_repo_admin(repo), )
def edit_file(repo, branchname, filename, username=None): """ Edit a file online. """ repo = pagure.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') user = pagure.lib.search_user( SESSION, username=flask.g.fas_user.username) reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, 'Empty repo cannot have a file') form = pagure.forms.EditFileForm(emails=user.emails) branch = None if branchname in repo_obj.listall_branches(): branch = repo_obj.lookup_branch(branchname) commit = branch.get_object() else: flask.abort(400, 'Invalid branch specified') if form.validate_on_submit(): try: pagure.lib.git.update_file_in_git( repo, branch=branchname, branchto=form.branch.data, filename=filename, content=form.content.data, message='%s\n\n%s' % ( form.commit_title.data.strip(), form.commit_message.data.strip() ), user=flask.g.fas_user, email=form.email.data, ) flask.flash('Changes committed') return flask.redirect( flask.url_for( '.view_commits', repo=repo.name, username=username, branchname=form.branch.data) ) except pagure.exceptions.PagureException as err: # pragma: no cover APP.logger.exception(err) flask.flash('Commit could not be done', 'error') data = form.content.data elif flask.request.method == 'GET': content = __get_file_in_tree( repo_obj, commit.tree, filename.split('/')) if not content or isinstance(content, pygit2.Tree): flask.abort(404, 'File not found') data = repo_obj[content.oid].data if content.is_binary or not pagure.lib.could_be_text(data): flask.abort(400, 'Cannot edit binary files') else: data = form.content.data return flask.render_template( 'edit_file.html', select='tree', repo=repo, username=username, branchname=branchname, data=data, filename=filename, form=form, user=user, branches=repo_obj.listall_branches(), )
def view_file(repo, identifier, filename, username=None): """ Displays the content of a file or a tree for the specified repo. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, "Project not found") reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, "Empty repo cannot have a file") if identifier in repo_obj.listall_branches(): branchname = identifier branch = repo_obj.lookup_branch(identifier) commit = branch.get_object() else: try: commit = repo_obj.get(identifier) branchname = identifier except ValueError: if "master" not in repo_obj.listall_branches(): flask.abort(404, "Branch no found") # If it's not a commit id then it's part of the filename commit = repo_obj[repo_obj.head.target] branchname = "master" if isinstance(commit, pygit2.Tag): commit = commit.get_object() if commit and not isinstance(commit, pygit2.Blob): content = __get_file_in_tree(repo_obj, commit.tree, filename.split("/"), bail_on_tree=True) if not content: flask.abort(404, "File not found") content = repo_obj[content.oid] else: content = commit if not content: flask.abort(404, "File not found") if isinstance(content, pygit2.Blob): ext = filename[filename.rfind(".") :] if ext in ( ".gif", ".png", ".bmp", ".tif", ".tiff", ".jpg", ".jpeg", ".ppm", ".pnm", ".pbm", ".pgm", ".webp", ".ico", ): try: Image.open(StringIO(content.data)) output_type = "image" except IOError as err: LOG.debug("Failed to load image %s, error: %s", filename, err) output_type = "binary" elif not content.is_binary and pagure.lib.could_be_text(content.data): file_content = content.data.decode("utf-8") try: lexer = guess_lexer_for_filename(filename, file_content) except (ClassNotFound, TypeError): lexer = TextLexer() content = highlight(file_content, lexer, HtmlFormatter(noclasses=True, style="tango")) output_type = "file" else: output_type = "binary" else: content = sorted(content, key=lambda x: x.filemode) output_type = "tree" return flask.render_template( "file.html", select="tree", repo=repo, username=username, branchname=branchname, filename=filename, content=content, output_type=output_type, repo_admin=is_repo_admin(repo), )
def view_file(repo, identifier, filename, username=None): """ Displays the content of a file or a tree for the specified repo. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, 'Empty repo cannot have a file') if identifier in repo_obj.listall_branches(): branchname = identifier branch = repo_obj.lookup_branch(identifier) commit = branch.get_object() else: try: commit = repo_obj.get(identifier) branchname = identifier except ValueError: if 'master' not in repo_obj.listall_branches(): flask.abort(404, 'Branch no found') # If it's not a commit id then it's part of the filename commit = repo_obj[repo_obj.head.target] branchname = 'master' if commit and not isinstance(commit, pygit2.Blob): content = __get_file_in_tree(repo_obj, commit.tree, filename.split('/')) if not content: flask.abort(404, 'File not found') content = repo_obj[content.oid] else: content = commit if isinstance(content, pygit2.Blob): if content.is_binary or not pagure.lib.could_be_text(content.data): ext = filename[filename.rfind('.'):] if ext in ('.gif', '.png', '.bmp', '.tif', '.tiff', '.jpg', '.jpeg', '.ppm', '.pnm', '.pbm', '.pgm', '.webp', '.ico'): try: Image.open(StringIO(content.data)) output_type = 'image' except IOError as err: LOG.debug('Failed to load image %s, error: %s', filename, err) output_type = 'binary' else: output_type = 'binary' else: try: lexer = guess_lexer_for_filename(filename, content.data) except ClassNotFound: lexer = TextLexer() content = highlight(content.data, lexer, HtmlFormatter( noclasses=True, style="tango", )) output_type = 'file' else: content = sorted(content, key=lambda x: x.filemode) output_type = 'tree' return flask.render_template( 'file.html', select='tree', repo=repo, username=username, branchname=branchname, filename=filename, content=content, output_type=output_type, repo_admin=is_repo_admin(repo), )
def view_repo_branch(repo, branchname, username=None): ''' Returns the list of branches in the repo. ''' repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if branchname not in repo_obj.listall_branches(): flask.abort(404, 'Branch no found') branch = repo_obj.lookup_branch(branchname) if not repo_obj.is_empty and not repo_obj.head_is_unborn: head = repo_obj.head.shorthand else: head = None cnt = 0 last_commits = [] for commit in repo_obj.walk(branch.get_object().hex, pygit2.GIT_SORT_TIME): last_commits.append(commit) cnt += 1 if cnt == 10: break diff_commits = [] if repo.is_fork: parentname = os.path.join( APP.config['GIT_FOLDER'], repo.parent.path) if repo.parent.is_fork: parentname = os.path.join( APP.config['FORK_FOLDER'], repo.parent.path) else: parentname = os.path.join(APP.config['GIT_FOLDER'], repo.path) orig_repo = pygit2.Repository(parentname) tree = None safe=False readme = None if not repo_obj.is_empty and not orig_repo.is_empty: if not orig_repo.head_is_unborn: compare_branch = orig_repo.lookup_branch(orig_repo.head.shorthand) else: compare_branch = None compare_commits = [] if compare_branch: compare_commits = [ commit.oid.hex for commit in orig_repo.walk( compare_branch.get_object().hex, pygit2.GIT_SORT_TIME) ] repo_commit = repo_obj[branch.get_object().hex] for commit in repo_obj.walk( repo_commit.oid.hex, pygit2.GIT_SORT_TIME): if commit.oid.hex in compare_commits: break diff_commits.append(commit.oid.hex) tree=sorted(last_commits[0].tree, key=lambda x: x.filemode) for i in tree: name, ext = os.path.splitext(i.name) if name == 'README': content = __get_file_in_tree( repo_obj, last_commits[0].tree, [i.name]).data readme, safe = pagure.doc_utils.convert_readme( content, ext, view_file_url=flask.url_for( 'view_raw_file', username=username, repo=repo.name, identifier=branchname, filename='')) return flask.render_template( 'repo_info.html', select='overview', repo=repo, head=head, username=username, branches=sorted(repo_obj.listall_branches()), branchname=branchname, origin='view_repo_branch', last_commits=last_commits, tree=tree, safe=safe, readme=readme, diff_commits=diff_commits, repo_admin=is_repo_admin(repo), form=pagure.forms.ConfirmationForm(), )
def new_request_pull(repo, branch_to, branch_from, username=None): """ Request pulling the changes from the fork into the project. """ repo = pagure.lib.get_project(SESSION, repo, user=username) branch_to = flask.request.values.get('branch_to', branch_to) if not repo: flask.abort(404) parent = repo if repo.parent: parent = repo.parent if not parent.settings.get('pull_requests', True): flask.abort(404, 'No pull-request allowed on this project') repopath = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(repopath) parentpath = _get_parent_repo_path(repo) orig_repo = pygit2.Repository(parentpath) try: diff, diff_commits, orig_commit = _get_pr_info(repo_obj, orig_repo, branch_from, branch_to) except pagure.exceptions.PagureException as err: flask.flash(err.message, 'error') return flask.redirect( flask.url_for('view_repo', username=username, repo=repo.name)) repo_admin = is_repo_admin(repo) form = pagure.forms.RequestPullForm() if form.validate_on_submit() and repo_admin: try: if repo.settings.get('Enforce_signed-off_commits_in_pull-request', False): for commit in diff_commits: if 'signed-off-by' not in commit.message.lower(): raise pagure.exceptions.PagureException( 'This repo enforces that all commits are ' 'signed off by their author. ') if orig_commit: orig_commit = orig_commit.oid.hex initial_comment = form.initial_comment.data.strip() or None request = pagure.lib.new_pull_request( SESSION, repo_to=parent, branch_to=branch_to, branch_from=branch_from, repo_from=repo, title=form.title.data, initial_comment=initial_comment, user=flask.g.fas_user.username, requestfolder=APP.config['REQUESTS_FOLDER'], ) try: SESSION.commit() except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() APP.logger.exception(err) flask.flash( 'Could not register this pull-request in the database', 'error') if not parent.is_fork: url = flask.url_for('request_pull', requestid=request.id, username=None, repo=parent.name) else: url = flask.url_for('request_pull', requestid=request.id, username=parent.user, repo=parent.name) return flask.redirect(url) except pagure.exceptions.PagureException as err: # pragma: no cover # There could be a PagureException thrown if the flask.g.fas_user # wasn't in the DB but then it shouldn't be recognized as a # repo admin and thus, if we ever are here, we are in trouble. flask.flash(str(err), 'error') except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error') if not is_repo_admin(repo): form = None # if the pull request we are creating only has one commit, # we automatically fill out the form fields for the PR with # the commit title and bodytext if len(diff_commits) == 1 and form: form.title.data = diff_commits[0].message.strip().split('\n')[0] form.initial_comment.data = diff_commits[0].message.partition('\n')[2] # Get the contributing templates from the requests git repo contributing = None requestrepopath = _get_parent_request_repo_path(repo) if os.path.exists(requestrepopath): requestrepo = pygit2.Repository(requestrepopath) if not requestrepo.is_empty and not requestrepo.head_is_unborn: commit = requestrepo[requestrepo.head.target] contributing = __get_file_in_tree(requestrepo, commit.tree, ['templates', 'contributing.md'], bail_on_tree=True) if contributing: contributing, _ = pagure.doc_utils.convert_readme( contributing.data, 'md') return flask.render_template( 'pull_request.html', select='requests', repo=repo, username=username, repo_obj=repo_obj, orig_repo=orig_repo, diff_commits=diff_commits, diff=diff, form=form, branches=sorted(orig_repo.listall_branches()), branch_to=branch_to, branch_from=branch_from, repo_admin=repo_admin, contributing=contributing, )
def get_ticket_template(repo, username=None): """ Return the template asked for the specified project """ form = pagure.forms.ConfirmationForm() if not form.validate_on_submit(): response = flask.jsonify({ 'code': 'ERROR', 'message': 'Invalid input submitted', }) response.status_code = 400 return response template = flask.request.args.get('template', None) if not template: response = flask.jsonify({ 'code': 'ERROR', 'message': 'No template provided', }) response.status_code = 400 return response repo = pagure.lib.get_project(pagure.SESSION, repo, user=username) if repo is None: response = flask.jsonify({ 'code': 'ERROR', 'message': 'Project not found', }) response.status_code = 404 return response if not repo.settings.get('issue_tracker', True): response = flask.jsonify({ 'code': 'ERROR', 'message': 'No issue tracker found for this project', }) response.status_code = 404 return response ticketrepopath = os.path.join( pagure.APP.config['TICKETS_FOLDER'], repo.path) content = None if os.path.exists(ticketrepopath): ticketrepo = pygit2.Repository(ticketrepopath) if not ticketrepo.is_empty and not ticketrepo.head_is_unborn: commit = ticketrepo[ticketrepo.head.target] # Get the asked template content_file = pagure.__get_file_in_tree( ticketrepo, commit.tree, ['templates', '%s.md' % template], bail_on_tree=True) if content_file: content, _ = pagure.doc_utils.convert_readme( content_file.data, 'md') if content: response = flask.jsonify({ 'code': 'OK', 'message': content, }) else: response = flask.jsonify({ 'code': 'ERROR', 'message': 'No such template found', }) response.status_code = 404 return response
def view_repo(repo, username=None): """ Front page of a specific repo. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if repo is None: flask.abort(404, 'Project not found') reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if not repo_obj.is_empty and not repo_obj.head_is_unborn: head = repo_obj.head.shorthand else: head = None cnt = 0 last_commits = [] tree = [] if not repo_obj.is_empty: try: for commit in repo_obj.walk(repo_obj.head.target, pygit2.GIT_SORT_TIME): last_commits.append(commit) cnt += 1 if cnt == 3: break tree = sorted(last_commits[0].tree, key=lambda x: x.filemode) except pygit2.GitError: pass readme = None safe = False if not repo_obj.is_empty and not repo_obj.head_is_unborn: branchname = repo_obj.head.shorthand else: branchname = None for i in tree: name, ext = os.path.splitext(i.name) if name == 'README': content = __get_file_in_tree(repo_obj, last_commits[0].tree, [i.name]).data readme, safe = pagure.doc_utils.convert_readme( content, ext, view_file_url=flask.url_for('view_raw_file', username=username, repo=repo.name, identifier=branchname, filename='')) diff_commits = [] if repo.is_fork: parentname = os.path.join(APP.config['GIT_FOLDER'], repo.parent.path) if repo.parent.is_fork: parentname = os.path.join(APP.config['FORK_FOLDER'], repo.parent.path) else: parentname = os.path.join(APP.config['GIT_FOLDER'], repo.path) orig_repo = pygit2.Repository(parentname) if not repo_obj.is_empty and not orig_repo.is_empty: orig_branch = orig_repo.lookup_branch('master') branch = repo_obj.lookup_branch('master') if orig_branch and branch: master_commits = [ commit.oid.hex for commit in orig_repo.walk( orig_branch.get_object().hex, pygit2.GIT_SORT_TIME) ] repo_commit = repo_obj[branch.get_object().hex] 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.oid.hex) return flask.render_template( 'repo_info.html', select='overview', repo=repo, repo_obj=repo_obj, username=username, head=head, readme=readme, safe=safe, branches=sorted(repo_obj.listall_branches()), branchname=branchname, last_commits=last_commits, tree=tree, diff_commits=diff_commits, repo_admin=is_repo_admin(repo), form=pagure.forms.ConfirmationForm(), )
def view_issue_raw_file( repo, filename=None, username=None, namespace=None): """ Displays the raw content of a file of a commit for the specified ticket repo. """ repo = flask.g.repo if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') reponame = os.path.join(APP.config['TICKETS_FOLDER'], repo.path) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, 'Empty repo cannot have a file') branch = repo_obj.lookup_branch('master') commit = branch.get_object() mimetype = None encoding = None content = __get_file_in_tree( repo_obj, commit.tree, filename.split('/'), bail_on_tree=True) if not content or isinstance(content, pygit2.Tree): flask.abort(404, 'File not found') mimetype, encoding = mimetypes.guess_type(filename) data = repo_obj[content.oid].data if not data: flask.abort(404, 'No content found') if (filename.endswith('.patch') or filename.endswith('.diff')) \ and not is_binary_string(content.data): # We have a patch file attached to this issue, render the diff in html orig_filename = filename.partition('-')[2] return flask.render_template( 'patchfile.html', select='issues', repo=repo, username=username, diff=data, patchfile=orig_filename, form=pagure.forms.ConfirmationForm(), ) if not mimetype and data[:2] == '#!': mimetype = 'text/plain' headers = {} if not mimetype: if '\0' in data: mimetype = 'application/octet-stream' else: mimetype = 'text/plain' elif 'html' in mimetype: mimetype = 'application/octet-stream' headers['Content-Disposition'] = 'attachment' if mimetype.startswith('text/') and not encoding: try: encoding = pagure.lib.encoding_utils.guess_encoding( ktc.to_bytes(data)) except pagure.exceptions.PagureException: # We cannot decode the file, so bail but warn the admins LOG.exception('File could not be decoded') if encoding: mimetype += '; charset={encoding}'.format(encoding=encoding) headers['Content-Type'] = mimetype return (data, 200, headers)
def get_ticket_template(repo, username=None): """ Return the template asked for the specified project """ form = pagure.forms.ConfirmationForm() if not form.validate_on_submit(): response = flask.jsonify({ 'code': 'ERROR', 'message': 'Invalid input submitted', }) response.status_code = 400 return response template = flask.request.args.get('template', None) if not template: response = flask.jsonify({ 'code': 'ERROR', 'message': 'No template provided', }) response.status_code = 400 return response repo = pagure.lib.get_project(pagure.SESSION, repo, user=username) if repo is None: response = flask.jsonify({ 'code': 'ERROR', 'message': 'Project not found', }) response.status_code = 404 return response if not repo.settings.get('issue_tracker', True): response = flask.jsonify({ 'code': 'ERROR', 'message': 'No issue tracker found for this project', }) response.status_code = 404 return response ticketrepopath = os.path.join(pagure.APP.config['TICKETS_FOLDER'], repo.path) content = None if os.path.exists(ticketrepopath): ticketrepo = pygit2.Repository(ticketrepopath) if not ticketrepo.is_empty and not ticketrepo.head_is_unborn: commit = ticketrepo[ticketrepo.head.target] # Get the asked template content_file = pagure.__get_file_in_tree( ticketrepo, commit.tree, ['templates', '%s.md' % template], bail_on_tree=True) if content_file: content, _ = pagure.doc_utils.convert_readme( content_file.data, 'md') if content: response = flask.jsonify({ 'code': 'OK', 'message': content, }) else: response = flask.jsonify({ 'code': 'ERROR', 'message': 'No such template found', }) response.status_code = 404 return response
def edit_file(repo, branchname, filename, username=None): """ Edit a file online. """ repo = pagure.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') user = pagure.lib.search_user(SESSION, username=flask.g.fas_user.username) reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, 'Empty repo cannot have a file') form = pagure.forms.EditFileForm(emails=user.emails) branch = None if branchname in repo_obj.listall_branches(): branch = repo_obj.lookup_branch(branchname) commit = branch.get_object() else: flask.abort(400, 'Invalid branch specified') if form.validate_on_submit(): try: pagure.lib.git.update_file_in_git( repo, branch=branchname, branchto=form.branch.data, filename=filename, content=form.content.data, message='%s\n\n%s' % (form.commit_title.data.strip(), form.commit_message.data.strip()), user=flask.g.fas_user, email=form.email.data, ) flask.flash('Changes committed') return flask.redirect( flask.url_for('.view_commits', repo=repo.name, username=username, branchname=form.branch.data)) except pagure.exceptions.PagureException as err: # pragma: no cover APP.logger.exception(err) flask.flash('Commit could not be done', 'error') data = form.content.data elif flask.request.method == 'GET': content = __get_file_in_tree(repo_obj, commit.tree, filename.split('/')) if not content or isinstance(content, pygit2.Tree): flask.abort(404, 'File not found') data = repo_obj[content.oid].data if content.is_binary or not pagure.lib.could_be_text(data): flask.abort(400, 'Cannot edit binary files') else: data = form.content.data return flask.render_template( 'edit_file.html', select='tree', repo=repo, username=username, branchname=branchname, data=data, filename=filename, form=form, user=user, branches=repo_obj.listall_branches(), )
def new_request_pull(repo, branch_to, branch_from, username=None): """ Request pulling the changes from the fork into the project. """ repo = pagure.lib.get_project(SESSION, repo, user=username) branch_to = flask.request.values.get('branch_to', branch_to) if not repo: flask.abort(404) parent = repo if repo.parent: parent = repo.parent if not parent.settings.get('pull_requests', True): flask.abort(404, 'No pull-request allowed on this project') repopath = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(repopath) parentpath = _get_parent_repo_path(repo) orig_repo = pygit2.Repository(parentpath) try: diff, diff_commits, orig_commit = _get_pr_info( repo_obj, orig_repo, branch_from, branch_to) except pagure.exceptions.PagureException as err: flask.flash(err.message, 'error') return flask.redirect(flask.url_for( 'view_repo', username=username, repo=repo.name)) repo_admin = is_repo_admin(repo) form = pagure.forms.RequestPullForm() if form.validate_on_submit() and repo_admin: try: if repo.settings.get( 'Enforce_signed-off_commits_in_pull-request', False): for commit in diff_commits: if 'signed-off-by' not in commit.message.lower(): raise pagure.exceptions.PagureException( 'This repo enforces that all commits are ' 'signed off by their author. ') if orig_commit: orig_commit = orig_commit.oid.hex initial_comment = form.initial_comment.data.strip() or None request = pagure.lib.new_pull_request( SESSION, repo_to=parent, branch_to=branch_to, branch_from=branch_from, repo_from=repo, title=form.title.data, initial_comment=initial_comment, user=flask.g.fas_user.username, requestfolder=APP.config['REQUESTS_FOLDER'], ) try: SESSION.commit() except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() APP.logger.exception(err) flask.flash( 'Could not register this pull-request in the database', 'error') if not parent.is_fork: url = flask.url_for( 'request_pull', requestid=request.id, username=None, repo=parent.name) else: url = flask.url_for( 'request_pull', requestid=request.id, username=parent.user, repo=parent.name) return flask.redirect(url) except pagure.exceptions.PagureException as err: # pragma: no cover # There could be a PagureException thrown if the flask.g.fas_user # wasn't in the DB but then it shouldn't be recognized as a # repo admin and thus, if we ever are here, we are in trouble. flask.flash(str(err), 'error') except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error') if not is_repo_admin(repo): form = None if len(diff_commits) == 1 and form: form.title.data = diff_commits[0].message.strip().split('\n')[0] # Get the contributing templates from the requests git repo contributing = None requestrepopath = _get_parent_request_repo_path(repo) if os.path.exists(requestrepopath): requestrepo = pygit2.Repository(requestrepopath) if not requestrepo.is_empty and not requestrepo.head_is_unborn: commit = requestrepo[requestrepo.head.target] contributing = __get_file_in_tree( requestrepo, commit.tree, ['templates', 'contributing.md'], bail_on_tree=True) if contributing: contributing, safe = pagure.doc_utils.convert_readme( contributing.data, 'md') output_type = 'markup' return flask.render_template( 'pull_request.html', select='requests', repo=repo, username=username, repo_obj=repo_obj, orig_repo=orig_repo, diff_commits=diff_commits, diff=diff, form=form, branches=sorted(orig_repo.listall_branches()), branch_to=branch_to, branch_from=branch_from, repo_admin=repo_admin, contributing=contributing, )
def view_raw_file(repo, identifier, filename=None, username=None): """ Displays the raw content of a file of a commit for the specified repo. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, 'Empty repo cannot have a file') if identifier in repo_obj.listall_branches(): branch = repo_obj.lookup_branch(identifier) commit = branch.get_object() else: try: commit = repo_obj.get(identifier) except ValueError: if 'master' not in repo_obj.listall_branches(): flask.abort(404, 'Branch no found') # If it's not a commit id then it's part of the filename commit = repo_obj[repo_obj.head.target] if not commit: flask.abort(400, 'Commit %s not found' % (identifier)) mimetype = None encoding = None if filename: content = __get_file_in_tree(repo_obj, commit.tree, filename.split('/')) if not content or isinstance(content, pygit2.Tree): flask.abort(404, 'File not found') mimetype, encoding = mimetypes.guess_type(filename) data = repo_obj[content.oid].data else: if commit.parents: diff = commit.tree.diff_to_tree() try: parent = repo_obj.revparse_single('%s^' % identifier) diff = repo_obj.diff(parent, commit) except (KeyError, ValueError): flask.abort(404, 'Identifier not found') else: # First commit in the repo diff = commit.tree.diff_to_tree(swap=True) data = diff.patch if not data: flask.abort(404, 'No content found') if not mimetype and data[:2] == '#!': mimetype = 'text/plain' if not mimetype: if '\0' in data: mimetype = 'application/octet-stream' else: mimetype = 'text/plain' if mimetype.startswith('text/') and not encoding: encoding = chardet.detect(ktc.to_bytes(data))['encoding'] headers = {'Content-Type': mimetype} if encoding: headers['Content-Encoding'] = encoding return (data, 200, headers)
def new_issue(repo, username=None): """ Create a new issue """ repo = pagure.lib.get_project(SESSION, repo, user=username) if repo is None: flask.abort(404, 'Project not found') if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') form = pagure.forms.IssueFormSimplied() if form.validate_on_submit(): title = form.title.data content = form.issue_content.data private = form.private.data try: issue = pagure.lib.new_issue( SESSION, repo=repo, title=title, content=content, private=private or False, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() # If there is a file attached, attach it. filestream = flask.request.files.get('filestream') if filestream and '<!!image>' in issue.content: new_filename = pagure.lib.git.add_file_to_git( repo=repo, issue=issue, ticketfolder=APP.config['TICKETS_FOLDER'], user=flask.g.fas_user, filename=filestream.filename, filestream=filestream.stream, ) # Replace the <!!image> tag in the comment with the link # to the actual image filelocation = flask.url_for( 'view_issue_raw_file', repo=repo.name, username=username, filename=new_filename, ) new_filename = new_filename.split('-', 1)[1] url = '[![%s](%s)](%s)' % ( new_filename, filelocation, filelocation) issue.content = issue.content.replace('<!!image>', url) SESSION.add(issue) SESSION.commit() return flask.redirect(flask.url_for( '.view_issue', username=username, repo=repo.name, issueid=issue.id)) except pagure.exceptions.PagureException as err: flask.flash(str(err), 'error') except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error') types = None default = None ticketrepopath = os.path.join(APP.config['TICKETS_FOLDER'], repo.path) if os.path.exists(ticketrepopath): ticketrepo = pygit2.Repository(ticketrepopath) if not ticketrepo.is_empty and not ticketrepo.head_is_unborn: commit = ticketrepo[ticketrepo.head.target] # Get the different ticket types files = __get_file_in_tree( ticketrepo, commit.tree, ['templates'], bail_on_tree=True) if files: types = [f.name.rstrip('.md') for f in files] # Get the default template default_file = __get_file_in_tree( ticketrepo, commit.tree, ['templates', 'default.md'], bail_on_tree=True) if default_file: default, _ = pagure.doc_utils.convert_readme( default_file.data, 'md') return flask.render_template( 'new_issue.html', select='issues', form=form, repo=repo, username=username, repo_admin=is_repo_admin(repo), types=types, default=default, )