Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Automating Artifactory: Shipping Software At Chef

Automating Artifactory: Shipping Software At Chef

A journey through Chef Software, Inc.’s continuous delivery pipelines and the important role Artifactory plays in shipping software at scale.

Seth Chisamore

May 05, 2015
Tweet

More Decks by Seth Chisamore

Other Decks in Programming

Transcript

  1. Who is Chef Software, Inc? Creators and maintainers of many

    open-source DevOps tools including: Chef, Chef Server, Test Kitchen and Omnibus Founded in 2008 (as Opscode) Approximately 200 employees (and growing fast) Offices in Seattle, San Francisco and London
  2. Who am I? I was employee 20 at Chef Software,

    Inc. Currently I’m the Release Engineering Lead for Chef Software, Inc. Previously I worked as an engineer on the Chef Server and Push Jobs products Responsible for much of Chef’s early Windows support In the past I worked for IBM and Fox Interactive Media
  3. We ship many products… Chef ChefDK Chef Server Chef Delivery

    Chef Analytics Reporting Management Console Push Jobs Server Push Jobs Client Supermarket Chef Server HA add-on Chef Server sync/replication add-on
  4. …across many platforms… AIX Debian 6, 7, 8 Enterprise Linux

    5, 6, 7 FreeBSD 9, 10 Mac OS X 10.8, 10.9, 10.10 Solaris 10, 11 Ubuntu 10.04, 12.04, 14.04 Windows
  5. Jenkins / Delivery PackageCloud / Omnitruck Artifactory Pro BUILD PUBLISH

    TEST omnibus-current-local omnibus-stable-local chef/current chef/stable LIFECYCLE OF AN ARTIFACT THE CHEF CONTINUOUS DELIVERY PIPELINE
  6. Some other facts about Chef’s release infrastructure 100% of our

    release infrastructure is managed by Chef! Release infrastructure currently runs on EC2 (minus obvious platforms like AIX, OS X and Solaris) We’ll be moving to completely ephemeral CI nodes later this year
  7. OMNIBUS FULL-STACK AND LOVING IT Jenkins / Delivery PackageCloud Artifactory

    BUILD PUBLISH TEST omnibus-current-local omnibus-stable-local chef/current chef/stable
  8. All aboard the Omnibus A Ruby framework for creating full-stack

    installable artifacts The final artifact contains a product’s code along with ALL of its dependencies Supports all platforms we ship Chef on (Linux, FreeBSD, Mac OS X, Solaris, Windows etc.) Completely open-source and available at:
 https://github.com/chef/omnibus
  9. OMNIBUS PROJECT DEFINITION name "chef-server" maintainer "Chef Software, Inc." homepage

    "https://www.chef.io" build_version "12.0.8" build_iteration 1 # global dependency "chef" # for embedded chef-client -z runs dependency "openresty" dependency “openresty-lpeg" # lua-based routing dependency "runit" # the backend dependency "rabbitmq" dependency "redis" # dynamic routing controls dependency "opscode-solr4" dependency "opscode-expander" dependency "keepalived" dependency "bookshelf" # the front-end services dependency "oc_bifrost" dependency "oc_id" dependency "opscode-chef-mover" dependency "oc_erchef" dependency "oc-chef-pedant" dependency "private-chef-upgrades" dependency "private-chef-cookbooks" dependency "chef-ha-plugin-config" dependency "postgresql92"
  10. OMNIBUS SOFTWARE DEFINITION name "postgresql92" default_version "9.2.9" source url: "http://ftp.postgresql.org/pub/source/v9.2.9/postgresql-9.2.9.tar.bz2",

    md5: "38b0937c86d537d5044c599273066cfc" relative_path "postgresql-9.2.9" dependency "zlib" dependency "openssl" dependency "libedit" dependency "ncurses" dependency "libossp-uuid" build do env = with_standard_compiler_flags(with_embedded_path) command "./configure" \ " --prefix=#{install_dir}/embedded/postgresql/9.2" \ " --with-libedit-preferred" \ " --with-openssl" \ " --with-ossp-uuid" \ " --with-includes=#{install_dir}/embedded/include" \ " --with-libraries=#{install_dir}/embedded/lib", env: env make "world -j #{workers}", env: env make "install-world -j #{workers}", env: env block do Dir.glob("#{install_dir}/embedded/postgresql/9.2/bin/*").sort.each do |bin| link bin, "#{install_dir}/embedded/bin/#{File.basename(bin)}" end end end
  11. OMNIBUS BUILD AN ARTIFACT $ omnibus build chef-server [CLI] I

    | Using config from 'omnibus.rb' [Project] I | Loading project `chef-server' from `config/projects/chef-server.rb'. ...LOTS OF COMPILING... [HealthCheck] I | Running health check on chef-server ...LOTS OF HEALTH CHECKING... [Packager::DEB] I | Rendering `resources/deb/control.erb' to `/tmp/chef-server-core20150420-22760/DEBIAN/control' [Packager::DEB] I | Rendering `resources/deb/md5sums.erb' to `/tmp/chef-server-core20150420-22760/DEBIAN/md5sums' [Packager::DEB] I | Creating .deb file [Packager::DEB] I | $ fakeroot dpkg-deb -z9 -Zgzip -D --build /tmp/chef-server-core20150420-2276 chef-server- core_12.0.8-1_amd64.deb I | dpkg-deb: building package `chef-server-core' in `chef-server-core_12.0.8-1_amd64.deb'. [Compressor] I | No compressor defined for `debian'. [Project: chef-server] I | Building version manifest
  12. OMNIBUS METADATA.JSON $ cat pkg/chef-server-core_12.0.8-1_amd64.deb.metadata.json { "basename": "chef-server-core_12.0.8-1_amd64.deb", "md5": "535bb6662ede898a526a725417a91105",

    "sha1": "284d4c91e54df8392a4cb54f9be510bfc801efac", "sha256": “83dee4fb272ddfce8f35957576182ba0650b32816882ab93f18...”, "sha512": “ee93429e35e8a823d5ecf05b7008109158dba771cf66c7e886a10e5e...”, "platform": "ubuntu", "platform_version": "10.04", "arch": "x86_64", "name": "chef-server", "friendly_name": "Chef-server", "homepage": "https://www.chef.io", "version": "12.0.8", "iteration": 1 } $ ls -1 pkg/ chef-server-core_12.0.8-1_amd64.deb chef-server-core_12.0.8-1_amd64.deb.metadata.json
  13. CUSTOM REPO LAYOUT FOR OMNIBUS ARTIFACTS IT’S NOT JUST A

    MAVEN THANG Jenkins / Delivery PackageCloud / Omnitruck Artifactory Pro BUILD PUBLISH TEST omnibus-current-local omnibus-stable-local chef/current chef/stable
  14. CUSTOM REPO LAYOUT FOR OMNIBUS ARTIFACTS ARTIFACT PATH PATTERN /**

    * Matches paths like * * com/getchef/chef-server/12.0.8/ * ubuntu/10.04/ * chef-server-core_ * 12.0.8-1_amd64.deb * * com/getchef/chef-server/12.0.8+20150423091711/ * ubuntu/10.04/ * chef-server-core_ * 12.0.8+20150423091711-1_amd64.deb * */ [orgPath]/[module]/[baseVersion<[0-9A-Za-z._-]*>](+)([folderItegRev])/ [platform<[0-9A-Za-z._]*>]/[platformVersion<[0-9A-Za-z._]*>]/ [module](-[projectSuffix<[a-z]*>])(-|_) [baseRev](+)([fileItegRev])(-|_)[iterPlatVerArch<[0-9A-Za-z._]*>].[ext]
  15. CUSTOM REPO LAYOUT FOR OMNIBUS ARTIFACTS FOLDER/FILE INTEGRATION REVISION REGEXP

    /** * Matches integration/build versions like * * 20150424082810 * 20150424082810.git.2.9e00864 * */ (?:\d{14})?(?:\.)?(?:git\.\d+\.[a-f0-9]{7})?
  16. ARTIFACTORY RUBY CLIENT BRINGING JAVA STABILITY TO RUBY HIPSTERS Jenkins

    / Delivery PackageCloud / Omnitruck Artifactory Pro BUILD PUBLISH TEST omnibus-current-local omnibus-stable-local chef/current chef/stable
  17. Artifactory Ruby Client Exposes the Artifactory REST API in a

    pure-Ruby interface Lightweight (all deps come from the Ruby standard library) Smooths over rough edges in the Artifactory REST API and exposes resources which don’t exist in the main Artifactory REST API Used as the underpinning for all of Chef’s Ruby-based Artifactory integrations Completely open-source and available at:
 https://github.com/chef/artifactory-client
  18. ARTIFACTORY 
 RUBY CLIENT EXAMPLE USAGE >> require 'artifactory' >>

    client = Artifactory::Client.new( | endpoint: 'http://artifactory.chef.co', | ) >> latest_stable_version = client.artifact_versions( | repos: 'omnibus-stable-local', | group: 'com.getchef', | name: 'chef-server', | ).first >> artifact = client.artifact_property_search( | 'repos' => 'omnibus-stable-local', | 'omnibus.project' => 'chef-server', | 'omnibus.platform' => 'ubuntu', | 'omnibus.platform_version' => '10.04', | 'omnibus.version' => latest_stable_version['version'], | ).first >> puts artifact.uri http://artifactory.chef.co/api/storage/omnibus-stable-local/com/getchef/… >> puts artifact.checksums['md5'] 535bb6662ede898a526a725417a91105 >> pp artifact.properties {"omnibus.architecture"=>["x86_64"], "omnibus.iteration"=>["1"], "omnibus.md5"=>["535bb6662ede898a526a725417a91105"], "omnibus.platform"=>["ubuntu"], "omnibus.platform_version"=>["10.04"], "omnibus.project"=>["chef-server"], "omnibus.sha1"=>["284d4c91e54df8392a4cb54f9be510bfc801efac"], "omnibus.sha256"=> ["83dee4fb272ddfce8f35957576182ba0650b32816882ab93f181e0102a1fd6c3"], "omnibus.sha512"=> ["ee93429e35e8a823d5ecf05b7008109158dba771cf66c7e886a10e5e63ad65e4523... "omnibus.version"=>["12.0.8"]}
  19. Jenkins / Delivery PackageCloud / Omnitruck Artifactory Pro BUILD PUBLISH

    TEST omnibus-current-local omnibus-stable-local chef/current chef/stable EFFORTLESSLY PUBLISH OMNIBUS ARTIFACTS FROM CI/CD OMNIBUS ARTIFACTORY PUBLISHER
  20. Omnibus Artifactory Publisher Uploads Omnibus artifacts to Artifactory Pro instances

    Writes the artifact to a path that adheres to the Omnibus custom repo layout Converts all Omnibus metadata values to Artifactory artifact properties Can be accessed via a command line or Ruby interface Completely open-source and ships with the Omnibus framework
  21. OMNIBUS ARTIFACTORY PUBLISHER CLI INTERFACE $ ls -1 pkg/ chef-server-core_12.0.8-1_amd64.deb

    chef-server-core_12.0.8-1_amd64.deb.metadata.json $ omnibus publish artifactory omnibus-current-local pkg/chef-server-core_12.0.8-1_amd64.deb # The publisher is glob-aware so uploading multiple packages at once is easy $ omnibus publish artifactory omnibus-current-local “pkg/**/*.{bff,deb,msi,rpm,sh,solaris}” [CLI] I | Using config from 'omnibus.rb' [ArtifactoryPublisher] I | Starting artifactory publisher [ArtifactoryPublisher] I | Uploading 'chef-server-core_12.0.8-1_amd64.deb' Uploaded 'chef-server-core_12.0.8-1_amd64.deb'
  22. OMNIBUS ARTIFACTORY PUBLISHER RUBY INTERFACE require 'omnibus' Omnibus.load_configuration(File.expand_path('omnibus.rb', Dir.pwd)) publisher

    = Omnibus::ArtifactoryPublisher.new( ‘pkg/**/*.{bff,deb,msi,rpm,sh,solaris}’, repository: 'omnibus-current-local', ) publisher.publish { |package| puts "Uploaded '#{package.name}'" }
  23. OMNIBUS ARTIFACTORY PUBLISHER METADATA IS TRANSLATED INTO ARTIFACT PROPERTIES {

    "arch": "x86_64", "basename": “chef-server-core_12.0.8-1_amd64.deb”, "friendly_name": "Chef-server", "homepage": "https://www.chef.io", "iteration": 1, "md5": “535bb6662ede898a526a725417a91105", "name": "chef-server", "platform": "ubuntu", "platform_version": "10.04", "sha1": "284d4c91e54df8392a4cb54f9be510bfc801efac", "sha256": "83dee4fb272ddfce8f35957576182ba0650b32816882ab93f181e0102a1fd6c3", "sha512": “ee93429e35e8a823d5ecf05b7008109158dba771cf66c7e886a10e5e63ad65e4523ea1358dea8ed60d9ef7cfd3f2...", "version": "12.0.8" }
  24. LITA PLUGIN FOR ARTIFACTORY HUMANS AND ROBOTS LIVING IN HARMONY

    Jenkins / Delivery PackageCloud / Omnitruck Artifactory Pro BUILD PUBLISH TEST omnibus-current-local omnibus-stable-local chef/current chef/stable
  25. Meet Lita Lita is a chat bot written in Ruby

    Plugins are implemented as Ruby gems Plugins are fully testable with RSpec Works with most any chat service including: HipChat, Slack, IRC and Campfire Completely open-source and available at: 
 https://www.lita.io/
  26. THE OLD WAY: HAAS (HUMAN AS A SERVICE) MANUAL AND

    GUI-DRIVEN Hey Seth can you promote 
 Chef Server 12.0.8? Sure thing Stephen, although I’m AFK ATM. I’ll make with the clicky clicky when I get back!
  27. LITA PLUGIN FOR ARTIFACTORY COMMAND SYNTAX @lita artifactory promote \

    <PROJECT> <VERSION> \ from <FROM_REPO> to <TO_REPO>
  28. Lita Artifactory Plugin Anyone can promote a build! A promotion

    can be performed while on-the-go All promotions are recorded in chat history Completely open-source and available at:
 https://github.com/chef/lita-artifactory
  29. ARTIFACTORY USER PLUGIN FOR PACKAGECLOUD PUSHING THE BITS SO YOU

    DON’T HAVE TO Jenkins / Delivery PackageCloud / Omnitruck Artifactory Pro BUILD PUBLISH TEST omnibus-current-local omnibus-stable-local chef/current chef/stable
  30. Artifactory User Plugin for PackageCloud Simple 1:1 mapping between an

    Artifactory repo and the associated PackageCloud repo Responds to all Artifactory storage events so current state of the Artifactory repo is always reflected in the associated PackageCloud repo Takes advantage of groovyx.net.http.AsyncHTTPBuilder so package pushes occur in parallel and do not block in the Artifactory user interface The script does not live in its own repo yet but source is available at:
 https://gist.github.com/schisamo/89336bd63e2724e87f1b
  31. ARTIFACTORY USER PLUGIN FOR PACKAGECLOUD STORAGE EVENT HOOKS storage {

    // Load the plugin's config json def configFile = new File(ctx.artifactoryHome.etcDir, 'packagecloud.json') def config = new JsonSlurper().parseText(configFile.text) afterCreate { ItemInfo item -> handlePushToPackageCloud(item, item.repoKey, config) } afterCopy { ItemInfo item, RepoPath targetRepoPath, Properties properties -> handlePushToPackageCloud(item, targetRepoPath.repoKey, config) } afterMove { ItemInfo item, RepoPath targetRepoPath, Properties properties -> handlePushToPackageCloud(item, targetRepoPath.repoKey, config) } afterDelete { ItemInfo item -> handleYankFromPackageCloud(item, config) } }
  32. ARTIFACTORY USER PLUGIN FOR PACKAGECLOUD EXAMPLE CONFIG FILE { "user":"chef",

    "token":"SUPERSECRET", } "repo_mapping":{ "omnibus-current-local": "current", "omnibus-stable-local": "stable" }, "exclusion_filter": ".*/delivery/.*"
  33. ARTIFACTORY USER PLUGIN FOR PACKAGECLOUD EXAMPLE LOG OUTPUT 2015-04-20 22:07:55,018

    [http-bio-8081-exec-6] [INFO ] (packagecloud :156) - [BEGIN] push of package file 'omnibus-stable- local:com/getchef/chef-server/12.0.8/el/5/chef-server-core-12.0.8-1.el5.x86_64.rpm' to 'https://packagecloud.io/api/v1/repos/chef/stable/ packages.json' with distro_id '26'. 2015-04-20 22:07:55,060 [http-bio-8081-exec-6] [INFO ] (packagecloud :156) - [BEGIN] push of package file 'omnibus-stable- local:com/getchef/chef-server/12.0.8/el/6/chef-server-core-12.0.8-1.el6.x86_64.rpm' to 'https://packagecloud.io/api/v1/repos/chef/stable/ packages.json' with distro_id '27'. 2015-04-20 22:07:55,091 [http-bio-8081-exec-6] [INFO ] (packagecloud :156) - [BEGIN] push of package file 'omnibus-stable- local:com/getchef/chef-server/12.0.8/ubuntu/10.04/chef-server-core_12.0.8-1_amd64.deb' to 'https://packagecloud.io/api/v1/repos/chef/ stable/packages.json' with distro_id '12'. 2015-04-20 22:07:55,133 [http-bio-8081-exec-6] [INFO ] (packagecloud :156) - [BEGIN] push of package file 'omnibus-stable- local:com/getchef/chef-server/12.0.8/ubuntu/12.04/chef-server-core_12.0.8-1_amd64.deb' to 'https://packagecloud.io/api/v1/repos/chef/ stable/packages.json' with distro_id '16'. 2015-04-20 22:07:55,164 [http-bio-8081-exec-6] [INFO ] (packagecloud :156) - [BEGIN] push of package file 'omnibus-stable- local:com/getchef/chef-server/12.0.8/ubuntu/14.04/chef-server-core_12.0.8-1_amd64.deb' to 'https://packagecloud.io/api/v1/repos/chef/ stable/packages.json' with distro_id '20'. 2015-04-20 22:12:27,004 [pool-1253-thread-1] [INFO ] (packagecloud :165) - [COMPLETE] push of package file 'omnibus-stable- local:com/getchef/chef-server/12.0.8/ubuntu/10.04/chef-server-core_12.0.8-1_amd64.deb' to 'https://packagecloud.io/api/v1/repos/chef/ stable/packages.json'. 2015-04-20 22:12:47,949 [pool-1251-thread-1] [INFO ] (packagecloud :165) - [COMPLETE] push of package file 'omnibus-stable- local:com/getchef/chef-server/12.0.8/el/5/chef-server-core-12.0.8-1.el5.x86_64.rpm' to 'https://packagecloud.io/api/v1/repos/chef/stable/ packages.json'. 2015-04-20 22:12:56,886 [pool-1255-thread-1] [INFO ] (packagecloud :165) - [COMPLETE] push of package file 'omnibus-stable- local:com/getchef/chef-server/12.0.8/ubuntu/14.04/chef-server-core_12.0.8-1_amd64.deb' to 'https://packagecloud.io/api/v1/repos/chef/ stable/packages.json'. 2015-04-20 22:13:23,527 [pool-1254-thread-1] [INFO ] (packagecloud :165) - [COMPLETE] push of package file 'omnibus-stable- local:com/getchef/chef-server/12.0.8/ubuntu/12.04/chef-server-core_12.0.8-1_amd64.deb' to 'https://packagecloud.io/api/v1/repos/chef/ stable/packages.json'. 2015-04-20 22:14:51,298 [pool-1252-thread-1] [INFO ] (packagecloud :165) - [COMPLETE] push of package file 'omnibus-stable- local:com/getchef/chef-server/12.0.8/el/6/chef-server-core-12.0.8-1.el6.x86_64.rpm' to 'https://packagecloud.io/api/v1/repos/chef/stable/ packages.json'. 2015-04-20 22:07:55,183 [http-bio-8081-exec-6] [INFO ] (o.a.a.r.CopyMoveHelper:175) - copying omnibus-current-local:com/getchef/chef- server/12.0.8 to omnibus-stable-local:com/getchef/chef-server/12.0.8 completed successfully, 13 artifacts were copied
  34. MANAGING ARTIFACTORY PRO WITH CHEF CONFIGURATION AS CODE Jenkins /

    Delivery PackageCloud / Omnitruck Artifactory Pro BUILD PUBLISH TEST omnibus-current-local omnibus-stable-local chef/current chef/stable
  35. Chef Software, Inc.’s Artifactory Pro Cookbook Supports installation and upgrades

    of Artifactory Pro Includes primitive resources for managing the Artifactory Pro configuration in an idempotent way Will be open sourced *soon* at:
 https://github.com/opscode-cookbooks/artifactory
  36. ARTIFACTORY CHEF RESOURCES MANAGE GROUPS AND PERMISSIONS ######################################################################### # Create

    groups ######################################################################### artifactory_group 'deployers' do description 'A group for users who can deploy artifacts to any repo' auto_join false end ######################################################################### # Permission Targets ######################################################################### artifactory_permission_target 'Deploy' do repositories ['ANY'] groups( deployers: ['deploy', 'annotate', 'read'] ) end
  37. ARTIFACTORY CHEF RESOURCES MANAGE USERS ######################################################################### # Create admin and

    service accounts ######################################################################### artifactory_user 'alton' do email '[email protected]’ password 'SUPERSECRET' admin true profile_updatable true end artifactory_user 'jenkins' do email '[email protected]' password 'SUPERSECRET' admin false profile_updatable true groups ['deployers'] end
  38. ARTIFACTORY CHEF RESOURCES MANAGE USERS (BETTER) ######################################################################### # Create admin

    and service accounts ######################################################################### artifactory_users = encrypted_data_bag_item_for_environment('artifactory', 'users') artifactory_users.each do |user_name, user_data| artifactory_user user_name do email user_data['email'] password user_data['password_clear'] admin user_data['admin'] profile_updatable true groups user_data['groups'] if user_data['groups'] end end
  39. ARTIFACTORY CHEF RESOURCES MANAGE REPOSITORIES AND REPOSITORY LAYOUTS ######################################################################### #

    Create an Omnibus-specific repository layout ######################################################################### artifactory_layout 'omnibus-default' do artifact_path_pattern '[orgPath]/[module]/[packageBaseVersion<[0-9A-Za-z._-]*>](+)([folderIteg...' distinctive_descriptor_path_pattern false folder_integration_revision_reg_exp '(?:\d{14})?(?:\.)?(?:git\.\d+\.[a-f0-9]{7})?' file_integration_revision_reg_exp '(?:\d{14})?(?:\.)?(?:git\.\d+\.[a-f0-9]{7})?' end ######################################################################### # Create Chef’s various Omnibus repositories ######################################################################### artifactory_repository 'omnibus-current-local' do description 'Integration/nightly builds which have passed basic testing' repo_layout_ref 'omnibus-default' max_unique_snapshots 10 end artifactory_repository 'omnibus-stable-local' do description 'Promoted builds which have passed deeper UAT' repo_layout_ref 'omnibus-default' end
  40. ARTIFACTORY CHEF RESOURCES MANAGE BACKUPS ######################################################################### # Configure Artifactory's built

    in backups ######################################################################### artifactory_backup 'backup-daily' do dir '/srv/artifactory/backups/daily' cron_exp '0 0 2 ? * MON-FRI' retention_period_hours 0 # incremental create_archive false send_mail_on_error true exclude_builds false end artifactory_backup 'backup-weekly' do dir '/srv/artifactory/backups/daily' cron_exp '0 0 2 ? * SAT' retention_period_hours 336 create_archive false send_mail_on_error true exclude_builds false end
  41. ARTIFACTORY CHEF RESOURCES MANAGE SMTP CONFIG ######################################################################### # SMTP Config

    ######################################################################### smtp_creds = encrypted_data_bag_item_for_environment('accounts', 'smtp') artifactory_mailserver 'smtp.gmail.com' do username smtp_creds['username'] password smtp_creds['password'] port 25 ssl false tls true artifactory_url 'http://artifactory.chef.co' from '[email protected]' end
  42. ARTIFACTORY CHEF RESOURCES MANAGE LDAP CONFIG ######################################################################### # LDAP Config

    ######################################################################### ldap_creds = encrypted_data_bag_item_for_environment('accounts', 'ldap') artifactory_ldapsetting 'chef-ldap' do auto_create_user true email_attribute 'userPrincipalName' enabled true ldap_url ‘ldap://0.0.0.0/DC=opscodecorp,DC=com' manager_dn ldap_creds['username'] manager_password ldap_creds['password'] search_base 'OU=Domain Users' search_filter 'userPrincipalName={0}' search_sub_tree true end
  43. Roadmap Ideas Ruby Client, Omnibus Publisher, Lita Plugin: Add support

    for the /api/build resource Ruby Client: Add support for the Artifactory Query Language (AQL) Lita Plugin: Add a search command (think latest current or latest stable)