Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Convert Trello JSON export files to Org-mode format
#!/usr/bin/env ruby
# trello_json_to_org.rb
# convert JSON files exported from Trello to https://orgmode.org/ format
#
# Copyright (C) 2020 Juri Linkov <juri@linkov.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Usage: ruby trello_json_to_org.rb trello_export.json > trello_export.org
# where trello_export.json is exported from a Trello board,
# and usually contains 8 hexadecimal characters in the file name.
# Post-processing: after converting to org-mode format, you might need to
# manually move TODO items that correspond to the finished state to the end
# of the "#+TODO:" line after the separator "|".
# It's useful first to export JSON to YAML with:
# ruby -rjson -ryaml -e 'puts(JSON.load(ARGF).to_yaml)' trello_export.json > trello_export.yaml
# to inspect the output, if you need to export more data to org-mode format.
require 'json'
def fix_label(label)
label.gsub(/\s+/, '_')
end
json = JSON.parse(ARGF.read, object_class: OpenStruct)
# Exit if it can't be org format file
exit unless json.prefs.canBeOrg
puts "#+TITLE: #{json.name}"
puts "#+AUTHOR: #{json.dig(:members, 0, :fullName)}"
puts "#+DATE: <#{json.dateLastActivity}>"
print "#+TODO: "
json.labelNames.each_pair do |_color, name|
print "#{fix_label(name)} " unless name.empty?
end
puts "|" # You can move some DONE labels after this "|"
puts
comments = Hash.new {|h,k| h[k]=[]}
json.actions.each do |action|
next unless action.type == 'commentCard'
comments[action.data.card.id] << action
end
json.lists.sort_by(&:pos).each do |list|
puts "* #{list.name}#{' :ARCHIVE:' if list.closed}"
puts
json.cards.sort_by(&:pos).each do |card|
next unless card.idList == list.id
print "** "
card.labels.each do |label|
print "#{fix_label(label.name)} "
end
puts "#{card.name}#{' :ARCHIVE:' if card.closed}"
puts " [#{card.dateLastActivity}]"
puts " DEADLINE: <#{card.due}>" if card.due
puts
card.idChecklists.each do |checklist_id|
json.checklists.sort_by(&:pos).each do |checklist|
next unless checklist.id == checklist_id
states = checklist.checkItems.group_by(&:state).transform_values(&:count)
puts "*** #{checklist.name} [#{states['complete'] || 0}/#{checklist.checkItems.size}]"
checklist.checkItems.sort_by(&:pos).each do |item|
puts " - [#{item.state == 'complete' ? 'X' : ' '}] #{item.name}"
end
end
puts
end
puts card.desc
puts
comments[card.id].each do |comment|
puts "*** Comment by #{comment.memberCreator.fullName}"
puts " [#{comment.date}]"
puts
puts comment.data.text
puts
end
end
end
colormap = {
green: '#61bd4f', # '#519839',
yellow: '#f2d600', # '#d9b51c',
orange: '#ff9f1a', # '#cd8313',
red: '#eb5a46', # '#b04632',
purple: '#c377e0', # '#89609e',
blue: '#0079bf', # '#055a8c',
sky: '#00c2e0',
lime: '#51e898',
pink: '#ff78cb',
black: '#344563',
}
puts
puts "* Local Variables :noexport:"
puts "\- Local Variables:"
print "- org-todo-keyword-faces: ("
json.labelNames.each_pair do |color, name|
print "\n- (\"#{fix_label(name)}\" . (:background \"#{colormap[color] || color}\" :foreground \"white\"))" unless name.empty?
end
puts ")"
puts "- End:"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.