Skip to content

Instantly share code, notes, and snippets.

@francois
Created October 10, 2008 00:40
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 francois/15953 to your computer and use it in GitHub Desktop.
Save francois/15953 to your computer and use it in GitHub Desktop.
# Released to the public domain.
# Original implementation by François Beausoleil <francois@teksol.info>
# Use at your own risks.
# This script will close ALL cases that match a certain criteria.
# Look below for CUSTOMIZE to see what needs changing.
# If you didn't know, this is Ruby, and was written when 1.8.6/1.8.7 was current.
# This script uses curl to do it's requesting, because Ruby cannot validate FogBugz's certificate.
require "uri"
require "cgi"
require "rexml/document"
require "rexml/xpath"
def get(uri)
$last_url = " > #{uri}"
xml = `curl -s '#{uri}'`
$last_doc = REXML::Document.new(xml)
end
def first(*args)
REXML::XPath.first(*args)
end
def each(*args, &block)
REXML::XPath.each(*args, &block)
end
def match(*args)
REXML::XPath.match(*args)
end
class Hash
def to_params
inject([]) do |memo, (k, v)|
memo << "#{CGI::escape(k.to_s)}=#{CGI::escape(v.to_s)}"
end.join("&")
end
end
def request(cmd, params)
uri = $uri.dup
uri.query = params.merge("cmd" => cmd).to_params
get(uri)
end
# CUSTOMIZE: Set your base URL here.
$uri = URI.parse("https://fogbugz.com/api.xml")
doc = get($uri)
$uri = $uri.merge(first(doc.root, "//url").text)
puts "Real API URI: #{$uri}"
# CUSTOMIZE: Set your username/password here
token = first(request(:logon, :email => "me@example.com", :password => "BigMac").root, "//token").text
puts "Logon Token: #{token}"
begin
loop do
requested = 200
count = closed = skipped = 0
# CUSTOMIZE: Make a search in the UI to find exactly the cases you want, then paste the search as the :q parameter.
puts "\nRequesting #{requested} new cases to examine..."
each(request(:search, :q => "NoMethodError status:active", :max => requested, :cols => "sTitle", :token => token).root, "//case") do |bug|
count += 1
id = bug.attribute("ixBug")
# CUSTOMIZE: Some of the cases that matched the first criteria were not supposed to be closed.
# So I filter them out here.
if first(bug, "//sTitle").text[/v:\d+$/] then
skipped += 1
puts "Skipping case #{id}: #{first(bug, "//sTitle").text}"
else
# CUSTOMIZE: ixStatus 2 is "Resolved (Fixed)"
doc = request(:resolve, :ixBug => id, :ixStatus => "2", :token => token)
if first(doc.root, "//case").attribute("operations").value["close"] then
doc = request(:close, :ixBug => id, :sEvent => "Auto-closing case", :cols => "fOpen,sStatus", :token => token)
if first(doc.root, "//fOpen").text == "false" then
closed += 1
puts "Closed case #{id}"
else
puts "Could not close case #{id}:\n#{doc}"
end
else
puts "Could not resolve case #{id}:\n#{doc}"
end
end
end
if skipped == count then
raise "Cannot continue: I had to skip all the cases before I hit a case I could close"
elsif closed == 0 then
raise "Cannot continue: I could not close any cases this time around"
end
end
rescue
$stderr.puts
$stderr.puts $!.message
$stderr.puts $!.backtrace
$stderr.puts "> #{$last_url}"
$stderr.puts $last_doc
ensure
request(:logoff, :token => token)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment