Showing posts with label automation. Show all posts
Showing posts with label automation. Show all posts

Thursday, April 5, 2018

Automatically Add Taxes to Invoice on New Freshbooks

I migrated to the "New Freshbooks" almost two years back, I think -- and for the most part it went fairly smooth. The design is a little cleaner, although there are a few features of the old system that aren't present.

Initially, when finding a feature gap, I assumed it was coming. Some of those features, however, still haven't come, and I'm tired of waiting. In particular, the ability to add taxes automatically to all the lines of an invoice is a real thorn in my side because for some of my clients I have very detailed timesheet invoices.

On the latest example of this, I had 87 lines. Going through 87 lines one by one and clicking "Add Taxes", then a checkbox, then save is ... repetitive, boring, and just the sort of work that computers are great at and humans are less great at. And yet I've done this on a whole ton of invoices because there wasn't an automatic way to do this on the new FreshBooks.

But no more. I gave up waiting for FreshBooks to do it and wrote a little piece of JavaScript that I can run with Tampermonkey:

// ==UserScript==
// @name         Add HST to FreshBooks Invoice
// @namespace    http://codiform.com
// @version      1.0
// @description  Go through a FreshBooks Invoice and add HST to each line
// @author       Geoffrey Wiseman
// @match        https://my.freshbooks.com/*
// @grant        none
// @run-at       context-menu
// ==/UserScript==

(function() {
    'use strict';

    let popovers = document.querySelectorAll("div.js-tax-picker-popover");
    for( var popover of popovers ) {
        let hst = popover.querySelectorAll("td.js-taxes-popover-checkbox")[1];
        hst.querySelector("input").click();

        popover.querySelector("button.button-primary").click();
    }

    alert( "Done adding HST to Invoice." );
})();

Now I just edit an invoice, right click, select "Tamper Monkey" and then "Add HST to FreshBooks Invoice" and wait for it to run. Way, way better than three clicks per line.

If you have the same problem, feel free to adopt my solution. You might need to adjust the index of the popover checkbox if you don't want to add the second-defined tax (I used to have PST and GST), now I just have HST -- but other than that it should probably work for you.

Thursday, January 25, 2018

Configuring Firewalld on CentOS 7 with Ansible

I've been working on the configuration of a new server with Ansible; this client has CentOS servers, so I'm configuring it for the current release of CentOS 7.x, which comes with Firewalld. All of the existing playbooks are set up for iptables, which was used in earlier versions of CentOS.

I thought about rolling it back to iptables, but I decided to try using firewalld first. I hit some problems:

  • Firewalld port forwarding only supports remote traffic:
    • If I want to run Tomcat and use the firewall to forward from port 80 to the Tomcat port, then accessing http://localhost will not trigger these port forwarding rules.
    • Fortunately, you can work around that with a "direct" rule.
  • The ansible firewalld module seems immature:
    • flagged as 'preview'
    • doesn't support port forwarding
    • doesn't support direct rules
    • You can work around that by invoking `firewall-cmd` using the command module.
  • Not easy to use `firewall-cmd` in an idempotent way.
    • Firewalld is configured with commands, somewhat like iptables. You can run these commands using the command module.
    • It's not that easy to invoke these commands in Ansible in a way that lets you be properly idempotent -- only run this command or mark it changed if something has changed. As a result, these will run every time, and if you have a handler to restart the firewalld service, that will also trigger every time.
What I ended up doing is configuring firewalld with commands, then looking at the configuration files that result and instead of having the ansible playbook trigger these commands, I have the playbook copy these files into place. File copying is something that is easier to do in an idempotent way than command invocation, so I can configure Ansible to copy configuration files into place (/etc/firewall/direct.xml, /etc/firewall/zones/public.xml), and then restart firewalld if the files have changed.

That seems to be reasonably happy.

Friday, January 17, 2014

Maven XML Verbosity is Amusing

Let's say you need to do something very slightly off the beaten path with Maven, like extract a single file from one of your dependencies so that it will be available to an XHR request in an offline web app as a static resource. No problem, just enter a quick 18 lines of XML.

But wait -- what if you're using Eclipse and M2E, and M2E decides that it doesn't know what to do about that dependency unpack you've just added? No problem, another 27 lines of XML oughta fix that.

Even though I know this to be true about Maven, every time I actually have to do it, it amuses me yet again.

Ah, Maven.

Sunday, August 12, 2012

Err Chatbot

Although Hubot is fun, and is already in use for gluing development chatrooms to infrastructure of all sorts at companies like GitHub, there are alternatives. I've had a couple of conversations with Guillaume BINET whose Err chatbot might be the sort of alternative you might consider.

Err (pronounced 'R2') is written in Python, is extensible through plugins which look reasonably easy to write, and has a catalog of pre-existing plugins. If you'd rather use Python than node.js to extend your chatbot, Err might be a good choice for you.

I haven't tried it yet -- there are two blocking issues for me:

  • XMPP-only: I currently use CampFire, because I like the available clients and the native support for history/searching.
  • No Web Hooks / Notifications: Err is mostly built for responding to user requests in the chatroom. I often use Hubot to respond to external services, like an SVN checkin or CI build notification. You could presumably write this into Err yourself, but it doesn't make that easy for you yet.

These may come soon so if you're interested in Err, you could star or watch the project on GitHub and keep an eye on it.

Thursday, May 24, 2012

Getting Hubot to Chat Commits to Subversion

If you happen to be using Hubot and Subversion together, you might want Hubot to chat subversion commit messages. (Of course, you might also want to switch to git or mercurial, but that's another conversation).  I wanted to do that, so I explored the option briefly.

Listening with Hubot
Hubot listens for HTTP requests on a port (depending on your configuration). Making a new hubot script to respond to certain requests is easy. You might start with something like this:
module.exports = (robot) ->
  robot.router.post "/hubot/svn", (req, res) ->

    revision = req.body.revision
    username = req.body.username
    log = req.body.log

    robot.logger.info "Subversion revision #{revision} committed."

    room = <room id>
    message = "Subversion revision #{revision} committed."

    robot.messageRoom room, message

    res.writeHead 200, {'Content-Type': 'text/plain'}
    res.end "Thanks; subversion commit written to chat.\n"

Reacting to a Subversion Commit
Now that you've got a listener, you'll want to send an HTTP request when a commit has been made. You can read more about svn post-commit hooks, but basically you add a script under your repo path as hooks/post-commit (or you modify an existing one, if you already have some post-commit hooks).

You might add something like this:
curl <server>:<port>/hubot/svn --data "revision=$2"

The SVN post-commit hook only has access to the repo path and the revision number. That's a decent starting point, but you're likely going to want to add more information.

Getting More Information
Assuming you want more information, you can either get that information before making the HTTP request or after (assuming Hubot can get access to your subversion repository).

If you want to get the information before making the HTTP request, you might revise your post-commit hook to do something like this:
revision=$2
log=$(svnlook log /opt/svn/repo -r $revision)
author=$(svnlook author /opt/svn/repo -r $revision)
curl <server>:<port>/hubot/svn --data "revision=$revision" --data "log=$log" --data "username=$author"

You could put that in an external script if you prefer to keep your post-commit hook clean. You would need to modify your Hubot script as well:
module.exports = (robot) ->
  robot.router.post "/hubot/svn", (req, res) ->

    revision = req.body.revision
    username = req.body.username
    log = req.body.log

    robot.logger.info "Subversion revision #{revision} committed."

    room = <room id>
    message = "Subversion revision #{revision} committed by #{username}:\n#{log}"

    robot.messageRoom room, message

    res.writeHead 200, {'Content-Type': 'text/plain'}
    res.end "Thanks; subversion commit written to chat.\n"

Alternately, you could simply pass the revision number to Hubot and then have Hubot retrieve the author's username and log message.

Et Voila
Now you have Hubot relaying information about subversion commits to your chatroom. Nice. Next stop, your continuous integration server.

Friday, May 4, 2012

Hubot Project Automation

I'd been curious to try Hubot, a GitHub chatbot written in node.js that can interact with users in IRC, Campfire and other chat systems and do any number of tasks which are defined in CoffeeScript. I was interested in the project automation scripts that others had written and contributed to the hubot-scripts repository, such as the teamcity and jira integrations. I was also interested in discovering if having a hubot in our chatroom would encourage the adoption of chat within the project team.

Installation
It took a couple of hours to get set up and working with Campfire. There were a few gotchas and pieces of unclear documentation along the way, but soon enough I had my hubot installed and working, and I tried a few of the contributed scripts.  It didn't help that the server on which I wanted to run Hubot didn't have node.js installed, so some of that time was the node setup.

Hubot Scripts
It's easy to find yourself staring at the github folder of contributed scripts, wondering what they all do. I encourage you to go look at the script catalog instead, which is a little more amenable to skim-reading. A lot of them are simple humor things which weren't really my area of interest for hubot -- I was more interested in fuctional integrations.

The scripts that are there tend to be pretty limited; if you wanted to do anything sophisticated, you're probably going to have to do it yourself. I was hoping for a little more, to be honest.

That said, the scripts look fairly easy to write, and if you're already familiar with CoffeeScript or you're interested in picking it up, I don't think it's going to be a big barrier to entry.  It would be nice to have more sophisticated well-documented examples showing how to do a few things like respond to externally-triggered events.

In any case, much of the things I might want a hubot to do are going to be specific to the projects and environments of a particular project and company, and those things aren't going to be things that others will write.

Automating with Hubot vs. Other Tools
I haven't personally written any Hubot scripts, so I can only speculate at what Hubot would be good at and where other tools would be a better fit.

Looking at the technology and the kinds of integrations that have already been written, I feel like Hubot's basis in CoffeeScript and Node.js give it a lot of affinity with web technologies. That means that integrating with other systems using REST and JSON is pretty easy in a way that wouldn't be for shell scripts. If you're doing a lot of these kinds of integrations, you'd probably find that Hubot's a good fit. If what you really want to do is interact with the filesystem on a server, I suspect you'd find it easier to do that with shell scripts and build tools.

Encouraging Chat Usage
After trying out Hubot briefly, I'm going to have to say that I don't think it's sufficient to really encourage the use of chat. If you're already using a chat room, then being able to invoke those things from the chat room you're already in and in a way that's visible to the rest of the team is potentially worth the trouble.

If you're not in a chat room already, then everything you might have a hubot do is probably simpler to do with shell scripts, build tools (e.g. maven, ant, rake, make), and custom command-line programs (e.g. awesome-cli-ruby) than loading a chat room and using a chat robot.

Thoughts
Hubot is a neat bit of technology. If you're already using team chat, and particularly if you're distributed I'd definitely suggest checking it out. But if you're not using team chat, then I don't think that Hubot will be the driver that will make that happen.