How to pass the branch name of a repo in the web-item link as a parameter to servlet

bitbucket-server
atlassian-connect-dev
bitbucket

#1

Hi,

In my BitBucket plugin, I want to add an option for Cherry Picking commits.

When the Cherry Pick button is clicked I want to show the commit(s) in the branch [which is selected from the dropdown on the left] and all the branches in the repo where the commit can be applied.

One can select the commit and apply it to any other branch(es) on the new page.

I am making use of servlet(s) below

     <servlet name="Repository Commits Servlet" key="KeyRepositoryCommitsServlet" class="git.servlet.RepositoryCommitsServlet">
        <description key="KeyDescRepositoryCommitsServlet">The Repository Commits Servlet</description>
        <url-pattern>/repocommits/*</url-pattern>
    </servlet>

    <web-item key="KeyWebItemCherryPick" name="Cherry Pick" weight="50" section="bitbucket.web.repository.commits.toolbar">
        <label>Cherry pick</label>
        <link>/plugins/servlet/repocommits/${repository.project.key}/${repository.slug}/${repository.id}</link>
    </web-item>

    <client-resource key="KeyRepoCommits.soy" name="Repository Commits Soy Template">
        <directory location="/templates/"/>
        <dependency>com.atlassian.bitbucket.server.bitbucket-web:server-soy-templates</dependency>
    </client-resource>

I want to know (assuming this is fairly simple to achieve [taking care of the failure scenarios etc… when the cherry-picking fails etc…)

a. How do I fetch the selected branch i.e what do I need to pass in the web-item link that will give me the branch information?

b. Assuming that I get the branch name, is there an API available to fetch the list of commit(s) on that branch.

c. If no API is available to achieve the functionality, can this be achieved using servlets (executing git command in the background).

Regards,
Kshitij


#2

Hi
@khughes can you help?


#3

It seems that I won’t be able to pass a branch name to the web-item link as the context is not available to the Cherry Pick button location.
So getting the branches list from the REST API and then fetching ALL the commits using another REST API would be way(?)


#4

We implemented a “Cherry Pick” button in our Bit-Booster - Rebase Squash Amend plugin. But we put it on the commit drilldown page instead. In other words, you first click on the commit you want to cherry-pick using Bitbucket’s regular web UI, and once you’ve drilled-down to a single commit, you then click on our little “Cherry-Pick” button (we also provide a “Revert” button).

Clicking on our “Cherry-Pick” button fires up this dialog:

To get current branch we pluck the “?until=” parameter from the current window’s query-string. If that parameter is not present we use current repository’s default branch which we fetch using server-side API

Our overall strategy is mostly based on the servlet approach you mentioned. We have our own REST endpoint we defined with our own servlet, and it runs git commands in the background to figure out appropriate target branches for the cherry-pick (e.g., git branch --contains).

I can’t even remember how the heck our logic works anymore. It must have been complicated because I see I actually left a comment in the code!

    // Unfortunately older git versions cannot do "--contains" on "for-each-ref"
    // so we need to it awkward like this to retain the sorted order ("-committerdate")
    // but using output of "git branch --contains" to partition the sets.
    containsCommit.addAll(notContainsCommit);
    sr = new StringReader(contains);
    br = new BufferedReader(sr);
    while ((line = br.readLine()) != null) {
        line = line.trim();
        String branch = line.charAt(0) == '*' ? line.substring(1).trim() : line;
        notContainsCommit.remove(branch);
    }
    containsCommit.removeAll(notContainsCommit);

#5

Hi Sylvie, @sylvie

Thanks a ton. This hint would definitely help. Will take a look at Bit-Booster.

Cheers !!!


#6

Hi Sylvie @sylvie,

I tried similar logic that you suggested, but I am stuck with some very basic problems, when I try to make an AJAX call to my RepoCommitsServlet, I get a page not found error

Below is what the code looks like

Java Script
=====================================================================
var RepoCommitsServlet = nav.pluginServlets().build() + "/repocommits" + window.location.pathname;

server.ajax({
    method: 'GET',
    url: RepoCommitsServlet,
    contentType: "application/json; charset=UTF-8",
    success: getResult
 });

Servlet Code
=====================================================================
@Component("RepositoryCommitsServlet")
@Named("RepositoryCommitsServlet")
public class RepositoryCommitsServlet extends HttpServlet {

    private final RepositoryService repositoryService;
    private final CommitService commitService;

    public RepositoryCommitsServlet(@ComponentImport RepositoryService repositoryService,
                                    @ComponentImport CommitService commitService) {

        this.repositoryService = repositoryService;
        this.commitService = commitService;
    }   

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // Get repoSlug from path
        String pathInfo = req.getPathInfo();

        String[] components = pathInfo.split("/");

        if (components.length < 3) {
            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        Repository repository = repositoryService.getBySlug(components[1], components[2]);

        if (repository == null) {
            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        boolean isSettings = false;
        if (components.length == 4 && "settings".equalsIgnoreCase(components[3])) {
            isSettings = true;
        }

        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json; charset=UTF-8");
        resp.getWriter().write("HelloWorld");
    }
}

plugin xml file
====================================================================

    <servlet name="Repository Commits Servlet" key="KeyRepositoryCommitsServlet" class="git.RepositoryCommitsServlet">
        <description key="KeyDescRepositoryCommitsServlet">The Repository Commits Servlet</description>
        <url-pattern>/repocommits/*</url-pattern>
    </servlet>
    
    <!-- add our web resources -->
    <web-resource key="KeyWRGitcherrypick" name="Git Cherrypick Web Resources">
        <resource type="download" name="gitcherrypick.css" location="css/gitcherrypick.css"/>
        <resource type="download" name="gitcherrypick.js" location="js/gitcherrypick.js"/>
        <dependency>com.atlassian.auiplugin:ajs</dependency>
        <dependency>com.atlassian.auiplugin:aui-experimental-tooltips</dependency>
        <dependency>com.atlassian.auiplugin:aui-buttons</dependency>
        <dependency>com.atlassian.bitbucket.server.bitbucket-web:commits-table</dependency>
        <dependency>com.atlassian.bitbucket.server.bitbucket-build:build-status-commit-list</dependency>
        <context>bitbucket.page.repository.commit</context>
    </web-resource>

The servlet doesn’t get called at all and I get a Page Not Found error.

Any idea what I might be missing ?


#7

Now it works. Some typo in the xml file.