From e0bde6e7badb7fbc561d9cdd504aa7f1d1abf9fd Mon Sep 17 00:00:00 2001
From: Julen Landa Alustiza <jlanda@fedoraproject.org>
Date: Mar 05 2020 13:07:13 +0000
Subject: [PATCH 1/5] api: fix api_view_plugins docstring


---

diff --git a/pagure/api/plugins.py b/pagure/api/plugins.py
index cc8af48..a5fa1c5 100644
--- a/pagure/api/plugins.py
+++ b/pagure/api/plugins.py
@@ -345,7 +345,7 @@ def api_view_plugins():
                 },
             ],
             'total_issues': 3
-    }
+        }
 
     """
     plugins = plugins_lib.get_plugin_names()

From bd3026bcbe85dcc035ad480a3a12ec8b02db4941 Mon Sep 17 00:00:00 2001
From: Julen Landa Alustiza <jlanda@fedoraproject.org>
Date: Mar 05 2020 13:07:13 +0000
Subject: [PATCH 2/5] api: fix api_project_tab_delete docstring


---

diff --git a/pagure/api/project.py b/pagure/api/project.py
index 7312b7a..03ce8fe 100644
--- a/pagure/api/project.py
+++ b/pagure/api/project.py
@@ -254,6 +254,7 @@ def api_project_tag_delete(repo, tag, username=None, namespace=None):
     ^^^^^^^^^^^^^^^
 
     ::
+
         {
             "message": "Tag blue has been deleted"
         }

From 18b56ab648d5919bd5204ce461427d5c4a5f86fb Mon Sep 17 00:00:00 2001
From: Julen Landa Alustiza <jlanda@fedoraproject.org>
Date: Mar 05 2020 13:07:13 +0000
Subject: [PATCH 3/5] doc_utils: new helper methods


---

diff --git a/pagure/doc_utils.py b/pagure/doc_utils.py
index 021bc44..3238120 100644
--- a/pagure/doc_utils.py
+++ b/pagure/doc_utils.py
@@ -1,11 +1,12 @@
 # -*- coding: utf-8 -*-
 
 """
- (c) 2014-2016 - Copyright Red Hat Inc
+ (c) 2014-2020 - Copyright Red Hat Inc
 
  Authors:
    Ralph Bean <rbean@redhat.com>
    Pierre-Yves Chibon <pingou@pingoured.fr>
+   Julen Landa Alustiza <jlanda@fedoraproject.org>
 
 """
 
@@ -125,3 +126,25 @@ def load_doc(endpoint):
 
     api_docs = markupsafe.Markup(api_docs)
     return api_docs
+
+
+def load_doc_title(endpoint):
+    """ Utility to load docstring title from a method """
+    rst = modify_rst(textwrap.dedent(endpoint.__doc__))
+
+    parts = docutils.examples.html_parts(rst)
+    fragment = parts["title"]
+
+    return fragment
+
+
+def load_doc_title_and_name(endpoint):
+    """ Utility to load the HTML doc version and the title from a method. """
+
+    result = {
+        "doc": load_doc(endpoint),
+        "title": load_doc_title(endpoint),
+        "name": endpoint.__name__,
+    }
+
+    return result

From 1f2b600f5bbe3eeefe421c6730efd1b94704898e Mon Sep 17 00:00:00 2001
From: Julen Landa Alustiza <jlanda@fedoraproject.org>
Date: Mar 05 2020 13:52:04 +0000
Subject: [PATCH 4/5] api: refactor doc UI


---

diff --git a/pagure/api/__init__.py b/pagure/api/__init__.py
index aecde30..62de640 100644
--- a/pagure/api/__init__.py
+++ b/pagure/api/__init__.py
@@ -33,7 +33,11 @@ API = flask.Blueprint("api_ns", __name__, url_prefix="/api/0")
 import pagure.lib.query  # noqa: E402
 import pagure.lib.tasks  # noqa: E402
 from pagure.config import config as pagure_config  # noqa: E402
-from pagure.doc_utils import load_doc, modify_rst, modify_html  # noqa: E402
+from pagure.doc_utils import (
+    load_doc_title_and_name,
+    modify_rst,
+    modify_html,
+)  # noqa: E402
 from pagure.exceptions import APIError  # noqa: E402
 from pagure.utils import authenticated, check_api_acls  # noqa: E402
 
@@ -59,6 +63,17 @@ def preload_docs(endpoint):
 APIDOC = preload_docs("api")
 
 
+def build_docs_section(name, endpoints):
+    """ Utility to build a documentation section to feed the template. """
+
+    result = {"name": name, "endpoints": []}
+
+    for endpoint in endpoints:
+        result["endpoints"].append(load_doc_title_and_name(endpoint))
+
+    return result
+
+
 class APIERROR(enum.Enum):
     """ Clast listing as Enum all the possible error thrown by the API.
     """
@@ -492,160 +507,109 @@ def api_error_codes():
 @API.route("/")
 def api():
     """ Display the api information page. """
-    api_project_doc = load_doc(project.api_project)
-    api_projects_doc = load_doc(project.api_projects)
-    api_project_watchers_doc = load_doc(project.api_project_watchers)
-    api_project_tags_doc = load_doc(project.api_project_tags)
-    api_project_tags_new_doc = load_doc(project.api_project_tags_new)
-    api_project_tag_delete_doc = load_doc(project.api_project_tag_delete)
-    api_git_tags_doc = load_doc(project.api_git_tags)
-    api_project_git_urls_doc = load_doc(project.api_project_git_urls)
-    api_git_branches_doc = load_doc(project.api_git_branches)
-    api_new_project_doc = load_doc(project.api_new_project)
-    api_modify_project_doc = load_doc(project.api_modify_project)
-    api_fork_project_doc = load_doc(project.api_fork_project)
-    api_modify_acls_doc = load_doc(project.api_modify_acls)
-    api_generate_acls_doc = load_doc(project.api_generate_acls)
-    api_new_branch_doc = load_doc(project.api_new_branch)
-    api_commit_flags_doc = load_doc(project.api_commit_flags)
-    api_commit_add_flag_doc = load_doc(project.api_commit_add_flag)
-    api_update_project_watchers_doc = load_doc(
-        project.api_update_project_watchers
-    )
-    api_get_project_options_doc = load_doc(project.api_get_project_options)
-    api_modify_project_options_doc = load_doc(
-        project.api_modify_project_options
-    )
-    api_project_block_user_doc = load_doc(project.api_project_block_user)
-    api_get_project_webhook_token_doc = load_doc(
-        project.api_get_project_webhook_token
-    )
 
-    issues = []
+    sections = []
+
+    projects_methods = [
+        project.api_new_project,
+        project.api_modify_project,
+        project.api_project,
+        project.api_projects,
+        project.api_project_tags,
+        project.api_project_tags_new,
+        project.api_project_tag_delete,
+        project.api_git_tags,
+        project.api_new_git_tags,
+        project.api_project_git_urls,
+        project.api_project_watchers,
+        project.api_git_branches,
+        project.api_new_branch,
+        project.api_fork_project,
+        project.api_modify_acls,
+        project.api_generate_acls,
+        project.api_commit_flags,
+        project.api_commit_add_flag,
+        project.api_update_project_watchers,
+        project.api_get_project_options,
+        project.api_modify_project_options,
+        project.api_project_block_user,
+        project.api_get_project_webhook_token,
+    ]
+    sections.append(build_docs_section("projects", projects_methods))
+
     if pagure_config.get("ENABLE_TICKETS", True):
-        issues.append(load_doc(issue.api_new_issue))
-        issues.append(load_doc(issue.api_issue_update))
-        issues.append(load_doc(issue.api_view_issues))
-        issues.append(load_doc(issue.api_view_issue))
-        issues.append(load_doc(issue.api_view_issue_comment))
-        issues.append(load_doc(issue.api_comment_issue))
-        issues.append(load_doc(issue.api_update_custom_field))
-        issues.append(load_doc(issue.api_update_custom_fields))
-        issues.append(load_doc(issue.api_change_status_issue))
-        issues.append(load_doc(issue.api_change_milestone_issue))
-        issues.append(load_doc(issue.api_assign_issue))
-        issues.append(load_doc(issue.api_subscribe_issue))
-        issues.append(load_doc(user.api_view_user_issues))
-
-    ci_doc = []
+        issues_methods = [
+            issue.api_new_issue,
+            issue.api_issue_update,
+            issue.api_view_issues,
+            issue.api_view_issue,
+            issue.api_view_issue_comment,
+            issue.api_comment_issue,
+            issue.api_update_custom_field,
+            issue.api_update_custom_fields,
+            issue.api_change_status_issue,
+            issue.api_change_milestone_issue,
+            issue.api_assign_issue,
+            issue.api_subscribe_issue,
+            user.api_view_user_issues,
+        ]
+        sections.append(build_docs_section("issues", issues_methods))
+
+    pull_requests_methods = [
+        fork.api_pull_request_create,
+        fork.api_pull_request_views,
+        fork.api_pull_request_view,
+        fork.api_pull_request_diffstats,
+        fork.api_pull_request_by_uid_view,
+        fork.api_pull_request_merge,
+        fork.api_pull_request_rebase,
+        fork.api_pull_request_close,
+        fork.api_pull_request_add_comment,
+        fork.api_pull_request_add_flag,
+        fork.api_pull_request_assign,
+        fork.api_pull_request_update,
+    ]
+    sections.append(build_docs_section("pull_requests", pull_requests_methods))
+
+    users_methods = [
+        api_users,
+        user.api_view_user,
+        user.api_view_user_activity_stats,
+        user.api_view_user_activity_date,
+        user.api_view_user_requests_filed,
+        user.api_view_user_requests_actionable,
+    ]
+    sections.append(build_docs_section("users", users_methods))
+
+    groups_methods = [group.api_groups, group.api_view_group]
+    sections.append(build_docs_section("groups", groups_methods))
+
+    plugins_methods = [
+        plugins.api_install_plugin,
+        plugins.api_remove_plugin,
+        plugins.api_view_plugins_project,
+        plugins.api_view_plugins,
+    ]
+    sections.append(build_docs_section("plugins", plugins_methods))
+
     if pagure_config.get("PAGURE_CI_SERVICES", False):
+        ci_methods = []
         if "jenkins" in pagure_config["PAGURE_CI_SERVICES"]:
-            ci_doc.append(load_doc(jenkins.jenkins_ci_notification))
-
-    api_pull_request_create_doc = load_doc(fork.api_pull_request_create)
-    api_pull_request_views_doc = load_doc(fork.api_pull_request_views)
-    api_pull_request_view_doc = load_doc(fork.api_pull_request_view)
-    api_pull_request_diffstats_doc = load_doc(fork.api_pull_request_diffstats)
-    api_pull_request_by_uid_view_doc = load_doc(
-        fork.api_pull_request_by_uid_view
-    )
-    api_pull_request_merge_doc = load_doc(fork.api_pull_request_merge)
-    api_pull_request_rebase_doc = load_doc(fork.api_pull_request_rebase)
-    api_pull_request_close_doc = load_doc(fork.api_pull_request_close)
-    api_pull_request_add_comment_doc = load_doc(
-        fork.api_pull_request_add_comment
-    )
-    api_pull_request_add_flag_doc = load_doc(fork.api_pull_request_add_flag)
-    api_pull_request_assign_doc = load_doc(fork.api_pull_request_assign)
-    api_pull_request_update_doc = load_doc(fork.api_pull_request_update)
-
-    api_version_doc = load_doc(api_version)
-    api_whoami_doc = load_doc(api_whoami)
-    api_users_doc = load_doc(api_users)
-    api_view_user_doc = load_doc(user.api_view_user)
-    api_view_user_activity_stats_doc = load_doc(
-        user.api_view_user_activity_stats
-    )
-    api_view_user_activity_date_doc = load_doc(
-        user.api_view_user_activity_date
-    )
-    api_view_user_requests_filed_doc = load_doc(
-        user.api_view_user_requests_filed
-    )
-    api_view_user_requests_actionable_doc = load_doc(
-        user.api_view_user_requests_actionable
-    )
-
-    api_view_group_doc = load_doc(group.api_view_group)
-    api_groups_doc = load_doc(group.api_groups)
+            ci_methods.append(jenkins.jenkins_ci_notification)
 
-    api_install_plugin_doc = load_doc(plugins.api_install_plugin)
-    api_remove_plugin_doc = load_doc(plugins.api_remove_plugin)
-    api_view_plugins_project_doc = load_doc(plugins.api_view_plugins_project)
-    api_view_plugins_doc = load_doc(plugins.api_view_plugins)
-
-    api_error_codes_doc = load_doc(api_error_codes)
+        if ci_methods:
+            sections.append(
+                build_docs_section(
+                    "continous_integration_services", ci_methods
+                )
+            )
 
-    extras = [api_whoami_doc, api_version_doc, api_error_codes_doc]
+    extras_methods = [api_whoami, api_version, api_error_codes]
+    sections.append(build_docs_section("extras", extras_methods))
 
     return flask.render_template(
         "api.html",
         version=pagure.__api_version__,
         api_doc=APIDOC,
-        projects=[
-            api_new_project_doc,
-            api_modify_project_doc,
-            api_project_doc,
-            api_projects_doc,
-            api_project_tags_doc,
-            api_project_tags_new_doc,
-            api_project_tag_delete_doc,
-            api_git_tags_doc,
-            api_project_git_urls_doc,
-            api_project_watchers_doc,
-            api_git_branches_doc,
-            api_fork_project_doc,
-            api_modify_acls_doc,
-            api_generate_acls_doc,
-            api_new_branch_doc,
-            api_commit_flags_doc,
-            api_commit_add_flag_doc,
-            api_update_project_watchers_doc,
-            api_get_project_options_doc,
-            api_modify_project_options_doc,
-            api_project_block_user_doc,
-            api_get_project_webhook_token_doc,
-        ],
-        issues=issues,
-        requests=[
-            api_pull_request_create_doc,
-            api_pull_request_views_doc,
-            api_pull_request_view_doc,
-            api_pull_request_diffstats_doc,
-            api_pull_request_by_uid_view_doc,
-            api_pull_request_merge_doc,
-            api_pull_request_rebase_doc,
-            api_pull_request_close_doc,
-            api_pull_request_add_comment_doc,
-            api_pull_request_add_flag_doc,
-            api_pull_request_assign_doc,
-            api_pull_request_update_doc,
-        ],
-        users=[
-            api_users_doc,
-            api_view_user_doc,
-            api_view_user_activity_stats_doc,
-            api_view_user_activity_date_doc,
-            api_view_user_requests_filed_doc,
-            api_view_user_requests_actionable_doc,
-        ],
-        groups=[api_groups_doc, api_view_group_doc],
-        plugins=[
-            api_install_plugin_doc,
-            api_remove_plugin_doc,
-            api_view_plugins_project_doc,
-            api_view_plugins_doc,
-        ],
-        ci=ci_doc,
-        extras=extras,
+        sections=sections,
     )
diff --git a/pagure/static/pagure.css b/pagure/static/pagure.css
index 63c7568..d57520b 100644
--- a/pagure/static/pagure.css
+++ b/pagure/static/pagure.css
@@ -534,3 +534,19 @@ th[data-sort] {
   display: inline;
   position: relative;
 }
+
+.api-doc .accordion {
+  padding-bottom: 13px;
+}
+
+.api-doc nav {
+  height: 100%;
+}
+
+.api-doc .nav-sidetabs {
+  border-bottom: 0;
+}
+
+.api-doc .card-body h2.title {
+  display: none;
+}
\ No newline at end of file
diff --git a/pagure/templates/api.html b/pagure/templates/api.html
index e4b4ecd..105a199 100644
--- a/pagure/templates/api.html
+++ b/pagure/templates/api.html
@@ -5,130 +5,84 @@
 {% set tag = "index" %}
 
 {% block content %}
-<div class="p-t-2 api">
-  <div class="container">
-    <header>
-        <h2 class="repo-name m-b-0">
-            <span class="fa fa-th"></span>
-            &nbsp; Pagure API Reference
-        </h2>
-        <div class="m-t-0">
-          This documentation describes the Pagure API v{{ version[0] }}
-          revision {{ version[1] }}.
+<div class="p-t-2 api-doc container">
+  <div class="row">
+    <div class="col-3">
+      <nav>
+        <div class="nav nav-tabs nav-sidetabs flex-column" id="nav-tab" role="tablist">
+          <h5 class="pl-2 font-weight-bold text-muted">Pagure API Reference</h5>
+          <a class="nav-item nav-link active" id="general" data-toggle="tab"
+            href="#general-tab" role="tab" aria-controls="general" aria-selected="true">General</a>
+          {% for section in sections %}
+          <a class="nav-item nav-link text-capitalize" id="{{ section.name }}" data-toggle="tag"
+            href="#{{ section.name }}-tab" role="tab" aria-controls="{{ section.name }}">{{ section.name | replace('_', ' ')}}</a>
+          {% endfor %}
         </div>
-        <div class="projectinfo m-t-1">
-        </div>
-    </header>
-    <div class="row">
-      <div class="col-md-10">
-
-        {{ api_doc |replace('h1', 'h2') }}
-
-        <h1>List of the API endpoints:</h1>
-
-        <h2>
-            Projects
-            <a name="projects" title="Permalink to this headline" href="#projects">
-              <span class="fa fa-link"></span>
-            </a>
-        </h2>
-        <div class="accordion">
-        {% for html in projects %}
-        {{ html | InsertDiv | safe }}
-        {% endfor %}
-        </div>
-
-        {% if issues %}
-        <h2>
-            Issues
-            <a name="users" title="Permalink to this headline" href="#issues">
-              <span class="fa fa-link"></span>
-            </a>
-        </h2>
-        <div class="accordion">
-        {% for html in issues %}
-        {{ html | InsertDiv | safe }}
-        {% endfor %}
-        </div>
-        {% endif %}
-
-        <h2>
-            Pull-requests
-            <a name="users"title="Permalink to this headline" href="#pull-requests">
-              <span class="fa fa-link"></span>
-            </a>
-        </h2>
-        <div class="accordion">
-        {% for html in requests %}
-        {{ html | InsertDiv | safe }}
-        {% endfor %}
-        </div>
-
-        <h2>
-            Users
-            <a name="users" title="Permalink to this headline" href="#users">
-              <span class="fa fa-link"></span>
-            </a>
-        </h2>
-        <div class="accordion">
-        {% for html in users %}
-        {{ html | InsertDiv | safe }}
-        {% endfor %}
-        </div>
-
-        <h2>
-            Groups
-            <a name="groups" title="Permalink to this headline" href="#groups">
-              <span class="fa fa-link"></span>
-            </a>
-        </h2>
-        <div class="accordion">
-        {% for html in groups %}
-        {{ html | InsertDiv | safe }}
-        {% endfor %}
+      </nav>
+    </div>
+    <div class="col-9">
+      <div class="tab-content mt-4" id="nav-tagContent">
+        <div class="tab-pane fade active show" id="general-tab" role="tabpanel" aria-labelledby="general-tab">
+          <h1 class="font-weight-bold mb-3">
+            General
+          </h1>
+          <p>
+            This documentation describes the Pagure API v{{ version[0] }} revision {{ version[1] }}
+          </p>
+          <div>
+            {{ api_doc | replace('h1', 'h2') }}
+          </div>
         </div>
-
-        <h2>
-            Plugins
-            <a name="plugins" title="Permalink to this headline" href="#plugins">
-                <span class="fa fa-link"></span>
-            </a>
-        </h2>
-        <div class="accordion">
-            {% for html in plugins %}
-            {{ html | InsertDiv | safe }}
+        {% for section in sections %}
+        <div class="tab-pane" id="{{ section.name }}-tab" role="tabpanel" aria-labelledby="{{ section.name }}-tab">
+          <h3 class="font-weight-bold mb-3 text-capitalize">{{ section.name | replace('_', ' ') }}</h3>
+          <div class="accordion" id="accordion-{{ section.name }}">
+            {% for endpoint in section.endpoints %}
+            <div class="card">
+              <div class="card-header" id="heading-{{ section.name }}-{{ endpoint.name }}">
+                <h3 class="mb-0">
+                  <button class="btn btn-link" data-toggle="collapse" data-target="#{{ section.name }}-{{ endpoint.name }}" aria-expanded="false" aria-controls="{{ section.name }}-{{ endpoint.name }}">
+                    {{ endpoint.title }}
+                  </button>
+                </h3>
+              </div>
+              <div id="{{ section.name }}-{{ endpoint.name }}" class="collapse" aria-labelledby="heading-{{ section.name }}-{{ endpoint.name }}" data-parent="#accordion-{{ section.name }}">
+                <div class="card-body">
+                  {{ endpoint.doc | replace('h1', 'h2') }}
+                </div>
+              </div>
+            </div>
             {% endfor %}
+          </div>
         </div>
-
-        {% if config.get('PAGURE_CI_SERVICES') %}
-        <h2>
-            Continous Integration Services
-            <a name="ci" title="Permalink to this headline" href="#ci">
-              <span class="fa fa-link"></span>
-            </a>
-        </h2>
-
-        <div class="accordion">
-        {% for html in ci %}
-        {{ html | InsertDiv |safe }}
         {% endfor %}
-        {% endif %}
-
-        <h2>
-            Extras
-            <a name="extras" title="Permalink to this headline" href="#extras">
-              <span class="fa fa-link"></span>
-            </a>
-        </h2>
-
-        <div class="accordion">
-        {% for html in extras %}
-        {{ html | InsertDiv |safe }}
-        {% endfor %}
-        </div>
-
       </div>
     </div>
   </div>
 </div>
 {% endblock %}
+
+{% block jscripts %}
+{{ super() }}
+
+<script type="text/javascript" nonce="{{ g.nonce }}">
+  $(document).ready(function() {
+    $('#nav-tab a.nav-link').on('shown.bs.tab', function (e) {
+      window.location.hash = e.target.hash;
+      window.scrollTo(0,0);
+    });
+
+    if (!window.location.hash){
+      window.location.hash = "#general-tab"
+    }
+
+    window.onhashchange = function () {
+      $(window.location.hash.slice(0,-4)).tab('show');
+    }
+    const _anchor = window.location.hash.slice(0,-4);
+    console.log(_anchor);
+    $(_anchor).tab('show');
+    window.scrollTo(0,0);
+  });
+</script>
+{% endblock %}
\ No newline at end of file
diff --git a/tests/test_pagure_flask_api.py b/tests/test_pagure_flask_api.py
index 9cf4d61..a6ef4f5 100644
--- a/tests/test_pagure_flask_api.py
+++ b/tests/test_pagure_flask_api.py
@@ -39,9 +39,7 @@ class PagureFlaskApitests(tests.SimplePagureTest):
         output = self.app.get("/api/0/")
         output_text = output.get_data(as_text=True)
         self.assertIn("<title> API | pagure  - Pagure</title>\n", output_text)
-        self.assertIn(
-            "&nbsp; Pagure API Reference\n        </h2>\n", output_text
-        )
+        self.assertIn(">Pagure API Reference</h5>\n", output_text)
 
     def test_api_doc_authenticated(self):
         """ Test the API documentation page. """
@@ -52,9 +50,7 @@ class PagureFlaskApitests(tests.SimplePagureTest):
             self.assertIn(
                 "<title> API | pagure  - Pagure</title>\n", output_text
             )
-            self.assertIn(
-                "&nbsp; Pagure API Reference\n        </h2>\n", output_text
-            )
+            self.assertIn(">Pagure API Reference</h5>\n", output_text)
 
     def test_api_get_request_data(self):
         data = {"foo": "bar"}

From 7afe0cc27988f852dfd96438ab1e4aab9e04a615 Mon Sep 17 00:00:00 2001
From: Julen Landa Alustiza <jlanda@fedoraproject.org>
Date: Mar 05 2020 14:00:39 +0000
Subject: [PATCH 5/5] pagure/api: rephrase some docstring titles


---

diff --git a/pagure/api/project.py b/pagure/api/project.py
index 03ce8fe..8f2bb72 100644
--- a/pagure/api/project.py
+++ b/pagure/api/project.py
@@ -288,8 +288,8 @@ def api_project_tag_delete(repo, tag, username=None, namespace=None):
 @api_method
 def api_git_tags(repo, username=None, namespace=None):
     """
-    Project git tags
-    ----------------
+    List git tags
+    -------------
     List the tags made on the project Git repository.
 
     ::
@@ -598,8 +598,8 @@ def api_project_git_urls(repo, username=None, namespace=None):
 @api_method
 def api_git_branches(repo, username=None, namespace=None):
     """
-    List project branches
-    ---------------------
+    List git branches
+    -----------------
     List the branches associated with a Pagure git repository
 
     ::
@@ -1524,8 +1524,8 @@ def api_generate_acls(repo, username=None, namespace=None):
 @api_method
 def api_new_branch(repo, username=None, namespace=None):
     """
-    Create a new git branch on a project
-    ------------------------------------
+    Create a new git branch
+    -----------------------
     Create a new git branch on a project
 
     ::

