Skip to content

Instantly share code, notes, and snippets.

@phillipuniverse
Created August 11, 2014 14:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save phillipuniverse/aa917db1cebca1615fb4 to your computer and use it in GitHub Desktop.
Save phillipuniverse/aa917db1cebca1615fb4 to your computer and use it in GitHub Desktop.
# Description
# Look at versions for our various modules and how they relate to framework versions
#
# Dependencies:
# "octonode": "^0.6.4"
# "xml2js": "^0.4.4"
#
# Configuration:
# HUBOT_GITHUB_TOKEN - API token from a GitHub account
#
# Commands:
# versions for <module> - Searches GitHub for a repository with the name of <module> and replies with all of the version info about that module and how it relates to the framework. This will allow for some ambiguity as it uses the GitHub search API
# versions for exactly <module> - Same as the non-exact search but works on an exact repository name to reconcile ambiguity (like between 'Enterprise' and 'CommonEnterprise')
#
#
# Author:
# Phillip Verheyden (phillipuniverse)
api = require("octonode").client(process.env.HUBOT_GITHUB_TOKEN or 'unknown')
api.requestDefaults.headers['Accept'] = 'application/vnd.github.v3+json'
search = api.search()
{parseString} = require 'xml2js'
githubOrg = 'BroadleafCommerce'
frameworkArtifacts = ['broadleaf-admin-functional-tests',
'broadleaf-admin-module',
'broadleaf-common',
'broadleaf-contentmanagement-module',
'broadleaf-framework',
'broadleaf-framework-web'
'broadleaf-open-admin-platform',
'broadleaf-profile',
'broadleaf-profile-web']
module.exports = (robot) ->
pattern = new RegExp('versions for(?: (exactly))? (.+)', 'i')
robot.hear pattern, (msg) ->
msg.send "Let me think about that for a sec"
exact = msg.match[1]
repoTerm = msg.match[2]
getRepo repoTerm, exact, robot, msg, (repo) ->
# Get all of the branches for this repository on GitHub
repo.branches (err, branches, headers) ->
for branch in branches
robot.logger.debug "Looking at pom on branch #{branch.name}"
# The do keyword is required to deal with the asynchronous execution of the subsequent callbacks
do (branch, frameworkArtifacts) ->
# get the root pom.xml and parse it
repo.contents 'pom.xml', branch.name, (err, data, headers) ->
if err
msg.reply err
else
# file data comes back from the GitHub API as a base64 encoded string, convert that into a valid UTF-8 string
xml = new Buffer(data.content, data.encoding).toString('utf8')
parseString xml, (err, result) ->
replied = false
# handle project -> dependenceyManagent version declarations
if result.project.dependencyManagement
replied = replyWithDependencies(result.project.dependencyManagement[0].dependencies, result.project, branch, msg)
# handle project -> dependencies version declarations if it wasn't in dependencyManagement
if not replied
replyWithDependencies(result.project.dependencies, result.project, branch, msg)
# For each declared dependency, figure out if this is a Broadleaf artifact dependency and reply
#
# Parameters:
# dependencies - (Single-element Array) a <dependencies> element in a pom.xml
# project - (Object) the project root of the pom.xml
# branch - (Object) the current branch that we are using
# msg - (Object) Hubot message object to send replies to
#
# Return:
# true if this method has responded via msg (indicating that version information was found), false otherwise
replyWithDependencies = (dependencies, project, branch, msg) ->
for dep in dependencies[0].dependency
if dep.artifactId.toString() in frameworkArtifacts
# the version string might actually be a variable. If so, look it up in the project
frameworkVersion = dep.version.toString()
if frameworkVersion.indexOf('$') != -1
frameworkVersion = project.properties[0][frameworkVersion.replace /[${}]/g, '']
msg.reply "Current version on the #{branch.name} branch is: #{project.version} targeting framework version #{frameworkVersion}"
return true
return false
# Executes the given 'callback' with a pre-initialized GitHub repo API object ready for querying
# Parameters:
# repoName - (String) the name of the repository to use
# exact - (boolean) whether or not we should treat repoName as the exact name of the repository or do a search for it
# robot - (Object) Hubot Robot instance for logging
# msg - (Object) Hubot message object used for sending replies
# callback - (function(repo)) callback to execute with a single parameter representing the GitHub repo API
getRepo = (repoName, exact, robot, msg, callback) ->
do (repoName) ->
if exact
# Assuming this is the exact repo name so try to look it UP
repo = api.repo("#{githubOrg}/#{repoName}")
do (repo) ->
repo.info (err, data, headers) ->
if err
msg.reply "Yeah... couldn't find a repository that exactly matches #{repoName} {Error code ID10T}"
else
callback(repo)
else
robot.logger.debug "Searching for #{repoName}"
# Search GitHub for repo names matching
search.repos {
q: "#{repoName}+in:name+user:#{githubOrg}",
sort: 'created',
order: 'asc'
}, (err, data, headers) ->
if err
robot.logger.debug JSON.stringify(err, null, 2)
msg.reply "There was an internal error searching for #{repoName} :("
else
repos = data.items
robot.logger.debug "Successful results for #{repoName}, found #{repos.length} matches"
if repos.length == 0
msg.reply "Couldn't find a repository for #{repoName} after searching for it on GitHub. Possible ID10T error."
else if repos.length > 1
# deal with ambiguity
potentialNames = ''
for repo in repos
potentialNames += repo.name + ', '
msg.reply "Too ambigous, retry with one of these: [#{potentialNames.substring(0, potentialNames.length - 2)}] or prefix the repo with 'exactly' in your message (like 'versions for exactly #{repoName}')"
else
# got a single result, instantiate a repo object and invoke the callback
path = repos[0].full_name
robot.logger.debug "Found a repo at #{path}"
msg.reply "Ok, gimme a sec to check the version info for #{path}"
callback(api.repo(path))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment