Privacy Policy
Snippets index

  Export Gitlab Issue

file "export_gitlab_issues.py"

#!/usr/bin/env python3
import pprint
import json
import gitlab
import argparse
import markdown

# Requirements
# python-gitlab==4.11.1
# Markdown-3.7

GITLAB_URL = "https://gitlab.brainstorm.it"
GITLAB_PRIVATE_TOKEN = "glpat-******************"
GITLAB_PROJECT = 77
PAGE_BREAK_STRING = '<div style="page-break-after: always;"></div>'


class GitlabClient(gitlab.Gitlab):

    def __init__(self, project_id):
        super().__init__(GITLAB_URL, GITLAB_PRIVATE_TOKEN, order_by='created_at')
        self.project = self.projects.get(project_id)

    def retrieve_issue(self, issue_id):

        issue = self.project.issues.get(issue_id)

        base_url = issue.web_url
        # Es: 'https://gitlab.brainstorm.it/group/project/-/issues/36'
        position = base_url.find('/-/')
        if position >= 0:
            base_url = base_url[:position]
        # Es: 'https://gitlab.brainstorm.it/group/project'

        data = json.loads(issue.to_json())
        self.fix_image_links(data, base_url)
        data['notes'] = []

        notes = issue.notes.list(all=True)
        notes = sorted([n for n in notes if not n.system], key=lambda k: k.created_at)

        for n in notes:
            note = json.loads(n.to_json())
            self.fix_image_links(note, base_url)
            data['notes'].append(note)

        return data

    def fix_image_links(self, data, base_url):
        text = data.get('description', data.get('body'))
        text = text.replace('/uploads/', base_url+'/uploads/')
        if 'description' in data:
            data['description'] = text
        else:
            data['body'] = text

def to_markdown(data):
    text = ""
    for k, v in data.items():

        text += '\n# [%d] %s\n\n' % (k, v['title'])
        text += "### %s (%s)\n\n" % (v['author']['name'], v['created_at'])
        text += "**Link**: %s\n\n" % v['web_url']
        text += v['description']
        text += "\n\n"

        for n in v['notes']:

            text += "\n\n" + (80*'-') + "\n\n"
            text += "### %s (%s)\n\n" % (n['author']['name'], v['created_at'])
            text += n['body']
            text += "\n\n"

        text += "\n\n" + PAGE_BREAK_STRING

    return text


def markdown_to_html(md_text):
    extensions = [
        "tables",
        "fenced_code",
        "codehilite",
        "toc"
    ]
    #safe_mode = True
    html = markdown.markdown(
        md_text,
        extensions=extensions,
        # safe_mode=safe_mode,
        # enable_attributes=(not safe_mode),
    )
    return html


def markdown_to_pdf(md_file, pdf_file, verbose=False):
    # Read Markdown file
    with open(md_file, "r", encoding="utf-8") as file:
        md_text = file.read()
    html_text = markdown_to_html(md_text)
    return html_to_pdf(html_text, pdf_file, verbose=False)


def html_to_pdf(html_text, pdf_file, verbose=False):
    from weasyprint import HTML
    from pygments.formatters import HtmlFormatter

    # Generate Pygments CSS for styling
    pygments_css = HtmlFormatter().get_style_defs('.codehilite')

    # Custom CSS for better styling
    css = """
body {
    font-family: Arial, sans-serif;
    padding: 20px;
}
pre {
    background: #f4f4f4;
    padding: 10px;
    border-radius: 5px;
    overflow-x: auto;
    font-size: 10px;
}
code {
    font-family: monospace;
}
img {
    display: block;
    max-width: 98%;
    height: auto;
    margin: 0 auto;
    border: 2px solid #ccc;
}

""" + pygments_css

    # Wrap HTML with styling
    html = f"""
<html>
    <head>
        <style>{css}</style>
    </head>
    <body>
        {html_text}
    </body>
</html>"""

    # Convert HTML to PDF
    if verbose:
        print(html)
    print('build "%s" ...' % pdf_file)
    HTML(string=html).write_pdf(pdf_file)
    print('done')


def main():
    parser = argparse.ArgumentParser(description="...")
    parser.add_argument('issue_ids', nargs="+", type=int)
    parser.add_argument("--project_id", "-p", type=int, default=GITLAB_PROJECT, help="Default: %d" % GITLAB_PROJECT)
    parser.add_argument("--format", type=str, choices=["", "json", "markdown", "html", "pdf", ], default="")
    parser.add_argument("--filename", type=str, default="result.pdf", help='filename when required (i.e.: PDF format); default: "result.pdf"')
    args = parser.parse_args()

    project_id = args.project_id
    client = GitlabClient(GITLAB_PROJECT)
    data = {}
    for issue_id in args.issue_ids:
        issue_data = client.retrieve_issue(issue_id)
        data[issue_id] = issue_data

    if args.format == 'json':
        print(json.dumps(data, indent=4))
    if args.format == 'markdown':
        print(to_markdown(data))
    elif args.format == 'html':
        md = to_markdown(data)
        html = markdown_to_html(md)
        print(html)
    elif args.format == 'pdf':
        md = to_markdown(data)
        html = markdown_to_html(md)
        html_to_pdf(html, args.filename, verbose=False)
    else:
        pprint.pprint(data)


if __name__ == '__main__':
    main()