Adding files to redmine via command line - ruby

We have an automatic build system that spits out packages, regression-tested & wrapped into a neat installer, ready for end-users to d/l & deploy.
We do tracking of end user support requests/bug reports via redmine. So far we uploaded the packages manually to the resp. 'Files' section of the redmine project, via the web interface.
What I'd like to do is to automate this step.
I imagine this would requires a few lines of Ruby to interface with redmine's db. I have zero knowledge about redmine's internals. :)
Basically I want the equivalent of a
mv package-x.y.z.tbz /usr/local/redmine/files/
as a Ruby (or whatever language suits the need) script that creates the right filename and registers the file in redmine's db so it shows up as if it had been uploaded through the Web interface, manually.
Cheers!

I've been frustrated with Redmine about things like this before. But before I go much further: is there a specific reason why you're using the Files section for this? It seems another tool (such as SSH/SFTP for uploading to someplace accessible to HTTP) might be a better fit for your needs. It would also be easily scriptable. Just point people to some constant URL like http://yourcompany.com/productname-current.zip.
If you really need to use Redmine for managing this, you might check out Mechanize: http://mechanize.rubyforge.org/. They should have a RESTful API also, but I've never used it.

I found this post, hope it can help you
Automating packaging and RedMine

I'm a bit late, but I've wrote a Redmine upload tool in Perl, using the WWW::Mechanize module.
Please find it on http://github.com/subogero/redgit

As already stated, you can use Mechanize for that.
There's a Python script written by Gert van Dijk's: https://github.com/gertvdijk/redmine-file-uploader
To use it you'll have to install Python Mechanize package first:
easy_install mechanize
If you prefer Ruby, you can use:
require 'mechanize'
# Replaces \ with / and removes "
ARGV.map!{|a|a.gsub('\\','/').gsub(/^"(.+)"$/,'\\1')}
filename = ARGV[0] || abort('Filename must be specified')
puts "File: #{filename}"
url = ARGV[1] || abort('Redmine URL must be specified')
puts "Redmine URL: #{url}"
username = ARGV[2] || abort('Redmine username must be specified')
puts "Username: #{username}"
password = ARGV[3] || abort('Redmine password must be specified')
puts "Password: #{'*' * password.length}"
project = ARGV[4] || abort('Redmine project must be specified')
puts "Project: #{project}"
login_page_path = '/login'
files_page_path = '/projects/' + project + '/files'
agent = Mechanize.new
# No certificate verification (I had to use this hack because our server is bound to custom port)
# agent.agent.http.verify_mode = OpenSSL::SSL::VERIFY_NONE
agent.get(URI.join(url, login_page_path)) do |login_page|
login_page.form_with(:action => login_page_path) do |login_form|
login_form.username = username
login_form.password = password
end.submit
end
agent.get(URI.join(url, files_page_path + '/new')) do |upload_page|
upload_page.form_with(:action => files_page_path) do |upload_form|
upload_form.file_uploads.first.file_name = filename
end.submit
end
And don't forget to install gem first:
gem install mechanize

Related

Can I programmatically interact with an "installer" (ie. ./install.sh) [duplicate]

Is there an Expect equivalent gem for Ruby?
I tried searching on code.google and rubygems.org, but sadly it did not show up.
FYI: Expect is a Unix automation and testing tool, written by Don Libes as an extension to the Tcl scripting language, for interactive applications such as telnet, ftp, passwd, fsck, rlogin, tip, ssh, and others.
Ruby comes with the PTY module for setting up pseudoterminals to drive interactive command line applications. With it comes an expect method that allows you to interact with an application kinda like Expect. For learning how to use expect, I found "What to expect from the Ruby expect library?" helpful.
As far as gems go, maybe checkout greenletters which is supposed to improve upon PTY + expect (although I haven't tried it myself).
I recently spent quite a bit of time struggling with this issue (I am stuck with 1.8.7). I found this question, this blog post and this forum thread really useful.
At the end this is my application code if anyone is interested in a little example (pass the password to rpm when signing packages):
def run_interactive command, password, promt
output = ''
begin
r, w, pid = PTY.spawn(command)
puts r.expect(promt)
sleep(0.5)
w.puts(password)
begin
r.each { |l| output += l }
rescue Errno::EIO
end
$?.exitstatus
Process.wait(pid)
rescue PTY::ChildExited => e
$stderr.puts "The child process #{e} exited! #{$!.status.exitstatus}"
end
output
end
password = "mypassword"
command = "rpm --define '_signature gpg' --define '_gpg_name #{key_id}' --addsign #{package}"
promt = %r{.*: }
expected = %r{good}
output = run_interactive(command, password, promt)
if output.match(expected)
puts output
else
abort "Error: expected: '#{expected}' got '#{output}'"
end
It has little error checking but it was all I needed.
Edit: Update the code with Process.wait(pid) to make sure it finishes before continuing and add comment about this being for 1.8.7.
checkout this rubygem: https://github.com/abates/ruby_expect. It could handle some small task for you. from its official example, it's enough to 'enter password' and login and interactive with local script.
here is an example that update the git code (which is authenticated with password):
require 'rubygems'
require 'ruby_expect'
def update_code
password = 'your password here'
exp = RubyExpect::Expect.spawn('git pull', :debug => true)
exp.procedure do
each do
expect /password: / do
send password
end
end
end
end
update_code
just run the code above, and your will see like this:
$ ruby update_code.rb
shensiwei#gforge.1ver??.net's password:
remote: Counting objects: 133, done.
remote: Compressing objects: 100% (84/84), done.
remote: Total 85 (delta 62), reused 0 (delta 0)
Unpacking objects: 100% (85/85), done.
for more example and details, please dive into its source code.
expect4r seems to do what you are asking for, though it is made specific for connections to Cisco and Juniper devices.
Perhaps even better is yax as this is "yet another expect".
RExpect
From the project's website:
RExpect is a drop in replacement for the expect.rb module in the
standard library that is faster and more robust, cabable of driving
many devices simultaneously.
parley is another one you can try, (written by me). It is inspired by Perl expect.

How do you open a zip file using watir-webdriver?

My test suite has a cucumber front end with a ruby backend, running the latest version of watir-webdriver and its dependencies atop the latest version of OSX. My cucumber environment is setup to execute in Firefox.
The export feature of our app creates a zip file but to test the import feature, I need the contents of the zip file.
My actual test needs to unpack that zip file and select the individual files in it for use in testing the import feature of our web application.
Can anyone point me to a reference that can help me figure out how to write that?
Based off my experience, you download this file the same way that a normal user might. So first off, you just click the download button or whatever and then can access the file wherever it is and check out its contents.
Assuming the downloads just go to your Downloads folder by default, there is some simple code you can use to select the most recently downloaded item:
fn = Dir.glob("~/Downloads/*.zip").max { |a,b| File.ctime(a) <=> File.ctime(b)}
Then just use the unzip shell command to unzip the file. No reason to add another gem into the mix when you can just use generic shell commands.
`unzip #{fn}`
Then, you'd use Dir.glob again to get the filenames of everything inside the unzipped files folder. Assuming the file was named "thing.zip", you do this:
files = Dir.glob("~/Downloads/thing/*")
If you want to files to be downloaded directly to your project folder, you can try this. This also prevents the popup from asking you if you really want to save the file which is handy. I think this still works but haven't used it in some time. The above stuff works for sure though.
profile = Selenium::WebDriver::Firefox::Profile.new
download_dir = Dir.pwd + "/test_downloads"
profile['browser.download.dir'] = download_dir
profile['browser.helperApps.neverAsk.saveToDisk'] = "application/zip"
b = Watir::Browser.new. :firefox, :profile => profile
I ended up adding the rubyzip gem at https://github.com/rubyzip/rubyzip
the solution is on that link but i modified mine a little bit. I added the following to my common.rb file. see below:
require 'Zip'
def unpack_zip
test_home='/Users/yournamegoeshere/SRC/watir_testing/project files'
sleep(5) #<--manually making time to hit the save download dialog
zip_file_paths = []
Find.find(test_home) do |path|
zip_file_paths << path if path =~ /.*\.zip$/
end
file_name=zip_file_paths[0]
Zip::File.open(file_name) do |zip_file|
# Handle entries one by one
zip_file.each do |entry|
# Extract to file/directory/symlink
puts "Extracting #{entry.name}"
entry.extract(test_home + "/" + entry.name)
# Read into memory
content = entry.get_input_stream.read
end
# Find specific entry
entry = zip_file.glob('*.csv').first
puts entry.get_input_stream.read
end
end
This solution works great!

How to get Dropbox directory by using ruby?

I want to get Dropbox directory like "c:\Users\foo\Dropbox" or "/Users/foo/Dropbox" by using ruby.
Is there a simple way to do it?
Newer versions of the Dropbox client write a file that contains the path(s) to the Dropbox folder(s) that you can read for this purpose. You can find more information here:
https://www.dropbox.com/help/4584
In short, you can read that info.json file and parse the contents as JSON to retrieve the Dropbox folder path(s).
From the dropbox API page:
# Install this the SDK with "gem install dropbox-sdk"
require 'dropbox_sdk'
# Get your app key and secret from the Dropbox developer website
APP_KEY = 'INSERT_APP_KEY'
APP_SECRET = 'INSERT_APP_SECRET'
flow = DropboxOAuth2FlowNoRedirect.new(APP_KEY, APP_SECRET)
authorize_url = flow.start()
# Have the user sign in and authorize this app
puts '1. Go to: ' + authorize_url
puts '2. Click "Allow" (you might have to log in first)'
puts '3. Copy the authorization code'
print 'Enter the authorization code here: '
code = gets.strip
# This will fail if the user gave us an invalid authorization code
access_token, user_id = flow.finish(code)
client = DropboxClient.new(access_token)
puts "linked account:", client.account_info().inspect
file = open('working-draft.txt')
response = client.put_file('/magnum-opus.txt', file)
puts "uploaded:", response.inspect
root_metadata = client.metadata('/')
puts "metadata:", root_metadata.inspect
At this stage, you could do worse than invoke client.get_file for every root_metadata['contents'] where root_metadata['contents']['is_dir'] is false. How best to do this, is left as an exercise for OP.

how to code web/application server in ruby?

I need to
run ant remotelly
create/modify xml files for ant
pass back results from ant's execution
so I thought I am going to write a web/application server in ruby. But I do not know where to start.
The computer that will run ant is Win XP SP3 and there is no web server or anything else running.
I found this code but not sure which part to modify so I does what I want. Let's say I want to run "dir" command and send back to the browser result of that command.
require 'socket'
webserver = TCPServer.new('127.0.0.1', 7125)
while (session = webserver.accept)
session.print "HTTP/1.1 200/OK\r\nContent-type:text/html\r\n\r\n"
request = session.gets
trimmedrequest = request.gsub(/GET\ \//, '').gsub(/\ HTTP.*/, '')
filename = trimmedrequest.chomp
if filename == ""
filename = "index.html"
end
begin
displayfile = File.open(filename, 'r')
content = displayfile.read()
session.print content
rescue Errno::ENOENT
session.print "File not found"
end
session.close
end
Ruby includes a Web server (WEBrick) so you don't actually need to use the code that you posted. Sinatra is designed specifically for writing very small Web applications - it lets you write a Web application in a few lines of code and automatically uses the provided Web server.
You can use ruby web server such as Rack, Webrick, mongrel, also you can use Ruby on Rails, Sinatra what else you want.
Of course you can write code from scratch, but it's not good idea to write whole by your own.

Equivalent of cURL for Ruby?

Is there a cURL library for Ruby?
Curb and Curl::Multi provide cURL bindings for Ruby.
If you like it less low-level, there is also Typhoeus, which is built on top of Curl::Multi.
Use OpenURI and
open("http://...", :http_basic_authentication=>[user, password])
accessing sites/pages/resources that require HTTP authentication.
Curb-fu is a wrapper around Curb which in turn uses libcurl. What does Curb-fu offer over Curb? Just a lot of syntactic sugar - but that can be often what you need.
HTTP clients is a good page to help you make decisions about the various clients.
You might also have a look at Rest-Client
If you know how to write your request as a curl command, there is an online tool that can turn it into ruby (2.0+) code: curl-to-ruby
Currently, it knows the following options: -d/--data, -H/--header, -I/--head, -u/--user, --url, and -X/--request. It is open to contributions.
the eat gem is a "replacement" for OpenURI, so you need to install the gem eat in the first place
$ gem install eat
Now you can use it
require 'eat'
eat('http://yahoo.com') #=> String
eat('/home/seamus/foo.txt') #=> String
eat('file:///home/seamus/foo.txt') #=> String
It uses HTTPClient under the hood. It also has some options:
eat('http://yahoo.com', :timeout => 10) # timeout after 10 seconds
eat('http://yahoo.com', :limit => 1024) # only read the first 1024 chars
eat('https://yahoo.com', :openssl_verify_mode => 'none') # don't bother verifying SSL certificate
Here's a little program I wrote to get some files with.
base = "http://media.pragprog.com/titles/ruby3/code/samples/tutthreads_"
for i in 1..50
url = "#{ base }#{ i }.rb"
file = "tutthreads_#{i}.rb"
File.open(file, 'w') do |f|
system "curl -o #{f.path} #{url}"
end
end
I know it could be a little more eloquent but it serves it purpose. Check it out. I just cobbled it together today because I got tired of going to each URL to get the code for the book that was not included in the source download.
There's also Mechanize, which is a very high-level web scraping client that uses Nokogiri for HTML parsing.
Adding a more recent answer, HTTPClient is another Ruby library that uses libcurl, supports parallel threads and lots of the curl goodies. I use HTTPClient and Typhoeus for any non-trivial apps.
To state the maybe-too-obvious, tick marks execute shell code in Ruby as well. Provided your Ruby code is running in a shell that has curl:
puts `curl http://www.google.com?q=hello`
or
result = `
curl -X POST https://www.myurl.com/users \
-d "name=pat" \
-d "age=21"
`
puts result
A nice minimal reproducible example to copy/paste into your rails console:
require 'open-uri'
require 'nokogiri'
url = "https://www.example.com"
html_file = URI.open(url)
doc = Nokogiri::HTML(html_file)
doc.css("h1").text
# => "Example Domain"

Resources