Advanced - Rest Plugin

Introduction

This tutorial provides instructions to create a Rest Plugin called SampleGithubREST that has 2 functional procedures as described below. These are implemented using GitHub Rest APIs.
  • getUser which takes a username and returns user information.

  • Create Release which creates a Release and uploads an artifact associated with that Release, to a Repository.

Prerequisites

These are assumptions for this Tutorial.

  1. Introdutory Tutorial has been completed.

  2. flowdpk is installed and setup.

  3. An active CloudBees Flow instance.

  4. Internet connection.

  5. A GitHub account.

  6. Write Access to a Git Repository.

  7. An asset (for example a zip file) that can be uploaded to this Repository.

Step 1 : Generate a plugin using sample spec from Github

After making sure flowpdk is available in your PATH, create a plugin workspace, typing the name SampleGithubREST for the plugin. Copy pluginspec.yaml from the cloned repository to the config directory of your plugin and generate the plugin.

cd ~/work
git clone https://github.com/electric-cloud-community/flowpdf ~/temp
flowpdk generate workspace
cp ~/temp/flowpdf/perl/SampleGithubREST/config/pluginspec.yaml SampleGithubREST/config
flowpdk generate plugin

Once done, it should look like this.

INFO: Working in /vagrant/flowpdk/SampleGithubREST
INFO: Fetching repository from https://github.com/electric-cloud/flowpdf-plugin-layout.git
INFO: Switching to the ref origin/master
INFO: Loaded version 1.1.0 from the manifest
INFO: Inflated plugin metafile (plugin.xml)
INFO: Generated promote.groovy
INFO: Inflated demote.groovy
INFO: Wrote ec_setup.pl
INFO: Wrote initial README.md
INFO: Wrote BasePlugin.groovy
INFO: Saved generic check connection step
INFO: Generated procedure.dsl for the CreateConfiguration procedure
INFO: Wrote createConfiguration.pl step
INFO: Created DeleteConfiguration/procedure.dsl
INFO: Inflated form for DeleteConfiguration
INFO: Created step for DeleteConfiguration
INFO: Saved procedure.dsl for the EditConfiguration procedure
INFO: Configuration has been inflated
INFO: Saved procedure.dsl for the procedure Get User
INFO: Saved form.xml for the procedure Get User
INFO: Fetching repository from https://github.com/electric-cloud/flowpdf-perl-lib.git
INFO: Switching to the ref origin/master
INFO: Loaded version 1.2.0 from the manifest
INFO: Updated Flow Logic class
INFO: Wrote step code for step Get User: Get User
INFO: Copied Perl core library files
INFO: Generated editable boilerplate: dsl/properties/perl/lib/FlowPlugin/SampleGithubREST.pm
INFO: Generated editable boilerplate: dsl/properties/perl/lib/FlowPlugin/SampleGithubRESTRESTClient.pm
INFO: Inflating REST Client SampleGithubRESTRESTClient
INFO: Saved procedure.dsl for the procedure Create Release
INFO: Saved form.xml for the procedure Create Release
INFO: Updated Flow Logic class
INFO: Wrote step code for step Create Release: Create Release
INFO: Copied Perl core library files
INFO: Generated editable boilerplate: dsl/properties/perl/lib/FlowPlugin/SampleGithubREST.pm
INFO: Generated editable boilerplate: dsl/properties/perl/lib/FlowPlugin/SampleGithubRESTRESTClient.pm
INFO: Inflating REST Client SampleGithubRESTRESTClient
INFO: Icon placeholder is placed into /vagrant/flowpdk/SampleGithubREST/htdocs/images/icon-plugin.svg
INFO: Copied Perl core library files
INFO: Generated editable boilerplate: dsl/properties/perl/lib/FlowPlugin/SampleGithubREST.pm
INFO: Generated editable boilerplate: dsl/properties/perl/lib/FlowPlugin/SampleGithubRESTRESTClient.pm
INFO: Inflating REST Client SampleGithubRESTRESTClient
INFO: Inflated core library perl
INFO: Setting perl core repository version to 1.2.0 in the flowpdf pluginspec

Step 2 : Build a Plugin

Build the plugin as follows.

vagrant@commander5:/vagrant/flowpdk/SampleGithubREST$ flowpdk build
Plugin Key: SampleGithubREST
Plugin Version: 1.0.0.0
INFO: Added fallback code to the ec_setup.pl
Adding plugin icon images/icon-plugin.svg
Adding folder /vagrant/flowpdk/SampleGithubREST/config to the archive
Adding folder /vagrant/flowpdk/SampleGithubREST/htdocs to the archive
Adding folder /vagrant/flowpdk/SampleGithubREST/pages to the archive
Archive /vagrant/flowpdk/SampleGithubREST/build/SampleGithubREST.zip has been created

Step 3 : Apply and Test the Plugin for Checkconnection

Using CloudBees Flow Plugin Manager upload the zip from the previous step and create a plugin configuration. If this step is successful you should be able to add the Plugin in a pipeline task as in the picture below. Note that the procedures may still not be fully functional. The purpose of this step is to verify that the built plugin from the previous step can successfully connect to Github.

../_images/gitrestpluginsnap1.png

Step 4 : Modify the Plugin

While the plugin has generated code for Create Release and Get User from the previous steps, what is missing is that the Create Release would require an Artifact to be uploaded. This is implemented using the following approach.

In SampleGithubRESTRESTClient.pm define a new method called _uploadReleaseAsset in the Rest Client module, which can upload to Github based on an asset path provided.

sub _uploadReleaseAsset {
    my ($self, $request, $params) = @_;
    my $assetPath = $params->{assetPath} or die "No asset path was provided";
    my $length = -s $assetPath;

    open my $fh, $assetPath or die "Cannot open $assetPath: $!";
    binmode $fh;
    my $content = join '' => <$fh>;
    close $fh;
    $request->content($content);
    $request->header('Content-Length', $length);
    my $uri = $request->uri;
    $uri->host('uploads.github.com');
    if ($params->{assetName}) {
        $uri->query_form(name => $params->{assetName});
    }
    $request->uri($uri);
    return $request;
    }

Then extend augmentRequest to trigger _uploadReleaseAsset. In essence this would make sure that when uploadReleaseAsset gets called, the augmentRequest which kicks in would call _uploadReleaseAsset.

sub augmentRequest {
    my ($self, $r, $params) = @_;
    # empty, for user to fill
    if ($self->method eq 'uploadReleaseAsset') {
        $r = $self->_uploadReleaseAsset($r, $params);
    }
    return $r;
}
In SampleGithubREST.pm extend createRelease in the following ways.
  • Get the parameters from the Step

  • Invoke the Rest API to get the Release by tag name

  • Invoke the createRelease Rest API if a Release does not exist

  • Call uploadReleaseAsset

sub createRelease {
    my ($pluginObject, $r) = @_;

    my $context = $pluginObject->getContext();
    my $params = $context->getStepParameters();

    my $client = $pluginObject->getSampleGithubRESTRESTClient;
    # If you have changed your parameters in the procedure declaration, add/remove them here
    my %restParams = (
        repositoryOwner => $params->getParameter('repositoryOwner')->getValue,
        repositoryName => $params->getParameter('repositoryName')->getValue,
        tag_name => $params->getParameter('tagName')->getValue,
        name => $r->{name},
    );
    my $release = eval {
        $client->getReleaseByTagName(%restParams, tag => $params->getParameter('tagName')->getValue);
    };

    if (!$release) {
        $release = $client->createRelease(%restParams);
    }
    logInfo "Release: ", $release;

    my $releaseId = $release->{id};
    my $asset = eval {
        $client->uploadReleaseAsset(
        %restParams,
        releaseId => $releaseId,
        assetPath => $params->getParameter('assetPath')->getValue,
        assetName => $r->{assetName},
        );
    };
    logInfo "Asset", $asset;
    logInfo("Got response from the server: ", $release);

    my $stepResult = $context->newStepResult;

    $stepResult->apply();
    }

Step 5 : Apply and Test the Plugin for CreateRelease

Run the Create Release as in the picture below. Note the following:
  • The repositoryOwner is the name of the organization

  • If the Release Name is blank the Release Name will default to the name of the Tag.

../_images/gitrestpluginsnap2.png

Running the above would create the following

../_images/gitrestpluginsnap3.png

Step 6: Summary

This Summary is provided in order to help a Developer conceptualize the steps involved in the creation of this plugin.

Specification
  • pluginspec.yaml provides the declarative interface for the plugin procedures (Create Release, Get User) as well as their dependencies viz., the Rest methods getReleaseTagByName and uploadReleaseAsset.

  • The interface specification in pluginspec.yaml for the Create Release and Get User procedures, include Rest end points that help implement their functionality.

Generated Code
  • flowpdk generates boiler plate code for procedures in SampleGithubREST.pm as well as SampleGithubRESTRESTClient.pm. The former consists of boiler plate code for collecting step parameters and the later for making Rest calls.

  • flowpdk generates boiler plate code for all Rest Methods uploadReleaseAsset, getReleaseByTagName, createRelease and getUser all in the Rest Client Module.

User Modifications
  • Implement a new method called _uploadReleaseAsset to upload the asset.

  • Extend uploadReleaseAsset by using augmentRequest to call _uploadReleaseAsset.