Skip to content

Instantly share code, notes, and snippets.

@jerodsanto
Created January 10, 2015 16:51
Show Gist options
  • Save jerodsanto/98126d229549c33323ed to your computer and use it in GitHub Desktop.
Save jerodsanto/98126d229549c33323ed to your computer and use it in GitHub Desktop.
A code dump showing how we generate "The Changelog Weekly" using the Trello API
require "trello"
require "pathname"
require "fileutils"
require_relative "importer/meta"
require_relative "importer/post"
Trello.configure do |config|
config.developer_public_key = "REDACTED"
config.member_token = "REDACTED"
end
class Importer
attr_reader :root_dir
def initialize root_dir
@root_dir = root_dir
end
def issues_dir
@issues_dir ||= File.join root_dir, "source"
end
def next_issue_number
Pathname.new(issues_dir)
.children
.select { |child| child.directory? }
.map { |dir| dir.basename.to_s }
.select { |dirname| dirname.match /\A\d/ }
.map(&:to_i).sort.last.succ.to_s
end
def import issue_number
start_time = Time.now
if issue_number.nil?
issue_number = next_issue_number
puts "No issue number specified. Guessing you want ##{issue_number}..."
end
board_name = "Weekly ##{issue_number}"
board = Trello::Board.all.find { |b| b.name == board_name }
if board.nil?
abort "Unable to find board named: #{board_name}"
end
lists = board.lists
meta = Meta.new lists.shift
issue_dir = File.join issues_dir, issue_number
FileUtils.mkdir_p issue_dir
issue_file = File.join issue_dir, "index.html.erb"
template = File.open issue_file, "w"
# DISCLAIMER: we are using Ruby to generate ERB, which is then
# consumed by Middleman, which outputs HTML. This is not ideal.
# We will eventually cut out the Middleman (see what I did there?)
# and use ERB directly to generate HTML, but this got us up and
# publishing quickly. Pragmatism can be ugly, but wins the day.
template.puts <<-DOC.gsub(/^ {4}/, '')
<%
@title = "Issue ##{issue_number}"
@published_at = "#{meta.published_at}"
@preview_text = "#{meta.preview_text}"
@editors_note = "#{meta.editors_note}"
%>
<% content_for :preview_text, @preview_text %>
<% content_for :title, @title %>
DOC
lists.each do |list|
next if list.cards.empty?
template.puts "\n<% content_block do %>\n"
template.puts "\n <h3>#{list.name}</h3>\n\n"
list.cards.each do |card|
post = Post.new card
if card == list.cards.last
template.puts " <div class='list-item last-of-type'>"
else
template.puts " <div class='list-item'>"
end
if post.draft?
next
end
if post.sponsored?
template.puts " <h5>Sponsored</h5>"
end
if post.link !~ URI::regexp
puts "WARNING: #{post.title} does not have a valid link!"
template.puts " <h5 class='item--error'>Whoops</h5>"
end
template.puts " <h2><a href='#{post.link}'>#{post.title}</a></h2>"
template.puts " #{post.body}"
template.puts " </div>\n\n"
end
template.puts "<% end %>\n"
end
template.close
total_time = (Time.now - start_time).round 2
puts "Generated issue ##{issue_number} in #{total_time} seconds."
end
end
require "maruku"
class Meta
attr_reader :cards
def initialize list
@cards = list.cards
end
def editors_note
if card = find_card("editors_note")
# must not contain p tags
md_to_html(card.desc).gsub("<p>", "").gsub("</p>", "")
end
end
def preview_text
if card = find_card("preview_text")
card.desc
end
end
def published_at
cards.first.name
end
private
def find_card name
cards.find { |card| card.name == name }
end
def md_to_html text
Maruku.new(text).to_html
end
end
require "maruku"
class Post
attr_reader :card
def initialize card
@card = card
end
def body
@body ||= begin
if attached_link
description = card.desc || ""
else
description = (card.desc.lines[2..-1] || []).join
end
md_to_html description
end
end
def draft?
card.desc.empty? || card.labels.any? { |label| label.name == "Draft" }
end
def link
@link ||= if attached_link
attached_link.url
else
card.desc.lines.first.chomp
end
end
def sponsored?
card.labels.any? { |label| label.name == "Sponsored" }
end
def title
card.name
end
private
def attached_link
@attached_link ||= card.attachments.first
end
def md_to_html text
Maruku.new(text).to_html
end
end
require "rubygems"
require "bundler"
require_relative "lib/importer"
Bundler.setup
desc "Import from Trello board"
task :import do
Importer.new(File.dirname(__FILE__)).import ENV["ISSUE"]
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment