Easy create release tickets with Node.js & Trello API


Today I pushed 10 commits to the one of my pet projects and as usual created new release ticket in Trello.

But what’s the point? I like Trello, it’s very simple, it has nice API, super easy for use and super easy for day to day work.

But I hate doing same tasks twice, today’s release notes manually created by me was the latest manually created changelog.

I spent few hours and let me finally introduce: https://github.com/maratgaliev/trell.

Features

Right now it’s a very-very first alpha, and for today this tool can:

  • Ask you about your repo path
  • Ask your Trello credentials
  • Ask your Trello Board and List name
  • Get commits from your repo
  • Create ticket for your on trello, with your commits log

How it looks like on CLI side?

trell

How it looks like on Trello side?

trell

Show me the source!

It’s our index.js file, here we use Haikunator for random release names, and pass it into our run function.

Also, we are reading user’s input from interactions module and getting 5 latest git commits from provided repo.

#!/usr/bin/env node

const chalk = require('chalk');
const clear = require('clear');
const datefns = require('date-fns');
const interactions = require('../lib/interactions');
const Haikunator = require('haikunator');

const figlet = require('figlet');
const board = require('../lib/board');
const repo = require('../lib/repo');

var haikunator = new Haikunator({
  defaults: {
    tokenLength: 0
  }
})

clear();

console.log(
  chalk.yellow(
    figlet.textSync('TRELL', { horizontalLayout: 'full' })
  )
);

const run = async () => {
  const workingDir = await interactions.askGitDetails();
  repo.getCommits(workingDir.repo).then(status => {
    const descr = status.all.map((val) => { return val.message }).join('\n');
    board.createRelease(datefns.format(new Date(), 'dd.MM.yyyy') + " - " + haikunator.haikunate(), descr);
  });
};

run();

Most interesting part - board.js file, here we are using Trello API npm package to get all information what we need.

Key and Token, Board name and List name - we can get everything from user’s promt and pass into our Promise.

Some checks, and we are going step by step on resolving Promises, and pass our data through them.

Finally - we are waiting for API response, and send back new card URL.

const CLI = require('clui');
const Configstore = require('configstore');
const Spinner = CLI.Spinner;

const interactions = require('./interactions');
const Trello = require("trello");

module.exports = {
  createRelease: async (name, description) => {
    const credentials = await interactions.askTrelloCredentials();
    var apiKey = process.env.TRELLO_API_KEY || credentials.key;
    var oauthToken = process.env.TRELLO_OAUTH_TOKEN || credentials.token;
    let trello = null;

    try {
      trello = new Trello(apiKey, oauthToken);
      const status = new Spinner('Loading data, please wait...');
      status.start();
  
      try {
        var boardsPromise = trello.getBoards('me');
        
        boardsPromise.then((data) => {
          const boards = data.filter(function (el) {
            return el.name === credentials.board;
          });
          if (boards.length) {
            var listsPromise = trello.getListsOnBoard(boards[0].id);
            listsPromise.then((data) => {
              const list = data.filter(function (el) {
                return el.name === credentials.list;
              });
              if (list.length) {
                var cardPromise = trello.addCard(name, description, list[0].id);
                cardPromise.then((data) => {
                  console.log('New release created: ' + data.shortUrl)
                });
              } else {
                console.log('List not found')
              }
            });
          } else {
            console.log('Board not found')
          }
        });
      } finally {
        status.stop();
      }
    } catch(err) {
      console.log(err)
      console.log("Invalid credentials for Trello API")
    }
  }
};

Interactive module. My favourite code part, and here we are using inquirer package for reading user’s input from command line.

Code is really simple, not sure if I can add something here :)

const inquirer = require('inquirer');

module.exports = {
  askTrelloCredentials: () => {
    const questions = [
      {
        name: 'token',
        type: 'input',
        message: 'Enter your Trello token:',
        validate: function( value ) {
          if (value.length) {
            return true;
          } else {
            return 'Please enter your token';
          }
        }
      },
      {
        name: 'key',
        type: 'input',
        message: 'Enter your Trello key:',
        validate: function(value) {
          if (value.length) {
            return true;
          } else {
            return 'Please enter your key';
          }
        }
      },
      {
        name: 'board',
        type: 'input',
        message: 'Enter your Trello board name:',
        validate: function(value) {
          if (value.length) {
            return true;
          } else {
            return 'Please enter your board name';
          }
        }
      },
      {
        name: 'list',
        type: 'input',
        message: 'Enter your Trello list name:',
        validate: function(value) {
          if (value.length) {
            return true;
          } else {
            return 'Please enter your list name';
          }
        }
      }
    ];
    return inquirer.prompt(questions);
  },
  askGitDetails: () => {
    const questions = [
      {
        name: 'repo',
        type: 'input',
        message: 'Enter your project repo path:',
        validate: function(value) {
          if (value.length) {
            return true;
          } else {
            return 'Please enter your project repo path';
          }
        }
      },
    ];
    return inquirer.prompt(questions);
  },
};

Final step!

simple-git package can show us latest commits!

This package is really awesome - many thanks and sending kudos for the authors, and their FANTASTIC API!

Just run log method - and thats it!

const CLI = require('clui');
const git = require('simple-git/promise');
const Spinner = CLI.Spinner;

module.exports = {
  getCommits: async (workingDir) => {
    const status = new Spinner('Loading data, please wait...');
    status.start();
    try {
      let statusSummary = null;
      try {
        // TODO: temporary set commits count
        statusSummary = await git(workingDir).log({n: 5});
      }
      catch (e) {
        console.log('Error reading git commits history')
      }
      return statusSummary;
    } finally {
      status.stop();
    }
  },
};

What is next?

This is just a first alpha version, it’s super simple, super buggy, super MVP.

But it works.

So, let me spend some time on fixes and adding new features.

And for sure I’ll write separate post about next stable version.

Stay tuned.