Skip to content

Commit

Permalink
Initial version (works on test data)
Browse files Browse the repository at this point in the history
  • Loading branch information
caldwell committed Jan 9, 2013
1 parent 68e7b92 commit f3cd6f4
Show file tree
Hide file tree
Showing 7 changed files with 240 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*~
work
1 change: 1 addition & 0 deletions .rbenv-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
jruby-1.7.0
9 changes: 9 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
source :rubygems

gem "jenkins-plugin-runtime", "~> 0.2.3"
gem "builder"
gem "mime-types"

group :development do
gem "jpi"
end
30 changes: 30 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
GEM
remote: http://rubygems.org/
specs:
builder (3.1.4)
jenkins-plugin-runtime (0.2.3)
json
slop (~> 3.0.2)
jenkins-war (1.475)
jpi (0.3.8)
bundler
jenkins-plugin-runtime (~> 0.2.3)
jenkins-war (> 1.427)
rubyzip
thor
json (1.7.6)
json (1.7.6-java)
mime-types (1.19)
rubyzip (0.9.9)
slop (3.0.4)
thor (0.16.0)

PLATFORMS
java
ruby

DEPENDENCIES
builder
jenkins-plugin-runtime (~> 0.2.3)
jpi
mime-types
123 changes: 123 additions & 0 deletions models/sparkle_appcast_publisher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
require 'java'
require 'builder'
require 'pathname'
require 'fileutils'
require 'time'
require 'mime/types'

# Grab the good builds and the changelogs from the bad builds (so the good
# build that follows a bad build gets the bad build's changelog appended to
# its own).
def get_builds(latest_build)
b=latest_build
builds=[]
c=[]
begin
c += b.getChangeSet.getItems.map { |c| c.getMsg }
if b.getResult.to_s == 'SUCCESS'
builds.push({ :build => b, :changes => c})
c=[]
end
end while (b=b.getPreviousBuild) #getPreviousSuccessfulBuild
builds
end

# One line per change entry right now. Consider moving to markdown.
def format_changelog(changes)
changes.map {|c| c+"\n" }.join('')
end

# The mime-types gem doesn't have x-apple-diskimage by default. Consider giving them a pull request.
MIME::Types.add(MIME::Type.from_hash('Content-Type' => 'application/x-apple-diskimage',
'Content-Transfer-Encoding' => '8bit',
'Extensions' => ['dmg']))

class Sparkle_appcastPublisher < Jenkins::Tasks::Publisher

display_name "Publish Sparkle Appcast (RSS)"

attr_reader :url_base, :output_directory, :author, :title, :description, :rss_filename

# Invoked with the form parameters when this extension point
# is created from a configuration screen.
def initialize(attrs = {})
attrs.each { |k, v| v = nil if v == ""; instance_variable_set "@#{k}", v }
@output_directory = Pathname.new(attrs["output_directory"]) if attrs["output_directory"]
end

##
# Runs before the build begins
#
# @param [Jenkins::Model::Build] build the build which will begin
# @param [Jenkins::Model::Listener] listener the listener for this build.
def prebuild(build, listener)
# do any setup that needs to be done before this build runs.
end

##
# Runs the step over the given build and reports the progress to the listener.
#
# @param [Jenkins::Model::Build] build on which to run this step
# @param [Jenkins::Launcher] launcher the launcher that can run code on the node running this build
# @param [Jenkins::Model::Listener] listener the listener for this build.
def perform(build_ruby, launcher, listener)
build = build_ruby.native
unless build.getResult.to_s == 'SUCCESS'
listener.info "Not writing Appcast file for failed build."
return
end

project_name = build.project.getDisplayName
builds = get_builds(build)

@rss_filename ||= project_name + ".rss"

# Build symlink tree and keep track of URLs and filenames
builds.each do |b|
build = b[:build]
version_dir = project_name + "-" + build.number.to_s
raise "Can't build appcast #{@rss_filename}: Too many artifacts" if build.getArtifacts.size > 1
first_artifact = build.getArtifacts.first.getFile
b[:file] = @output_directory + version_dir + first_artifact.getName
FileUtils.mkdir_p @output_directory + version_dir
FileUtils.ln_sf first_artifact.getAbsolutePath, b[:file]
b[:url] = "#{@url_base}/#{version_dir}/#{first_artifact.getName}"
end

rss = Builder::XmlMarkup.new(:indent => 2)
rss.instruct!
rss_s = rss.rss("version" => "2.0",
"xmlns:content" => "http://purl.org/rss/1.0/modules/content/",
"xmlns:dc" => "http://purl.org/dc/elements/1.1/",
"xmlns:sparkle" => "http://www.andymatuschak.org/xml-namespaces/sparkle",
) {
rss.channel {
rss.author @author || "Jenkins"
rss.updated Time.now.to_s
rss.link "#{@url_base}/#{@rss_filename}"
rss.title @title || "#{project_name} Versions"
rss.description @description || "#{project_name} Versions"

builds.each do |b|
rss.item {
rss.link b[:url]
rss.title "#{project_name} #{b[:build].number} Released"
rss.updated File.mtime(b[:file])
rss.enclosure("url" => b[:url],
"type" => MIME::Types.type_for(b[:file].to_s).last || "application/octet-stream",
"length" => File.size(b[:file]),
"sparkle:version" => b[:build].number)
rss.pubDate File.ctime(b[:file])
rss.dc(:date, File.ctime(b[:file]).iso8601)
rss.description { rss.cdata! format_changelog(b[:changes]) }
}
end
}
}

listener.info "Writing Appcast file \"#{@output_directory + @rss_filename}\"..."
File.open(@output_directory + @rss_filename, "w") { |f| f.write(rss_s) }

end

end
26 changes: 26 additions & 0 deletions sparkle-appcast.pluginspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Jenkins::Plugin::Specification.new do |plugin|
plugin.name = "sparkle-appcast"
plugin.display_name = "Sparkle Appcast (RSS) Plugin"
plugin.version = '0.1.0'
plugin.description = 'Publishes an Appcast (RSS) Feed for use with the Sparkle auto-update library'

# You should create a wiki-page for your plugin when you publish it, see
# https://wiki.jenkins-ci.org/display/JENKINS/Hosting+Plugins#HostingPlugins-AddingaWikipage
# This line makes sure it's listed in your POM.
plugin.url = 'https://wiki.jenkins-ci.org/display/JENKINS/Sparkle+Appcast+Plugin'

# The first argument is your user name for jenkins-ci.org.
plugin.developed_by "david", "David Caldwell <[email protected]>"

# This specifies where your code is hosted.
# Alternatives include:
# :git => 'git://repo.or.cz/sparkle-appcast-plugin.git'
# :svn => 'https://svn.jenkins-ci.org/trunk/hudson/plugins/sparkle-appcast-plugin'
plugin.uses_repository :github => 'caldwell/jenkins-sparkle-appcast-plugin'

# This is a required dependency for every ruby plugin.
plugin.depends_on 'ruby-runtime', '0.10'

# This is a sample dependency for a Jenkins plugin, 'git'.
#plugin.depends_on 'git', '1.1.11'
end
49 changes: 49 additions & 0 deletions views/sparkle_appcast_publisher/config.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<%
f = taglib("/lib/form")
f.block do
%>

<table style="margin-left: 30px;">
<%
f.entry :title => 'Output Directory',
:field => :output_directory,
:description => 'Where to build the symlink tree and appcast rss file.' do
f.textbox :clazz => 'required', :default => ''
end

f.entry :title => 'URL Base',
:field => :url_base,
:description => 'Where the feed url will be (eg. "http://example.com/some_directory")' do
f.textbox :clazz => 'required', :default => 'http://example.com/some_directory'
end

f.entry :title => 'Appcast Filename',
:field => :rss_filename,
:description => 'Filename for the generated Appcast (if left blank it will use the project name plus ".rss"")' do
f.textbox :clazz => 'optional', :default => ''
end

f.entry :title => 'RSS Author',
:field => :author,
:description => 'Author field in the Appcast RSS. Not shown by Sparkle.' do
f.textbox :clazz => 'optional', :default => ''
end

f.entry :title => 'RSS Title',
:field => :title,
:description => 'Title field in the Appcast RSS. Not shown by Sparkle.' do
f.textbox :clazz => 'optional', :default => ''
end

f.entry :title => 'RSS Description',
:field => :description,
:description => 'Description field in the Appcast RSS. Not shown by Sparkle.' do
f.textbox :clazz => 'optional', :default => ''
end

%>
</table>

<%
end
%>

0 comments on commit f3cd6f4

Please sign in to comment.