Last active
June 10, 2017 14:37
-
-
Save lancearlaus/9286e7035a71f29639f239acbd52ce96 to your computer and use it in GitHub Desktop.
XMind to JIRA CSV Import Mapping Utility
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"config.version" : "2.0", | |
"config.project.from.csv" : "false", | |
"config.encoding" : "UTF-8", | |
"config.file.id" : "0255121b-e22c-4833-8f8f-6cdfade1c986", | |
"config.email.suffix" : "@", | |
"config.file.name" : "XMind.csv", | |
"config.field.mappings" : { | |
"Issue Type" : { | |
"jira.field" : "issuetype", | |
"userChanged" : "true", | |
"manualMapping" : "false" | |
}, | |
"Description" : { | |
"jira.field" : "description", | |
"userChanged" : "true", | |
"manualMapping" : "false" | |
}, | |
"Related Project" : { | |
"userChanged" : "true", | |
"manualMapping" : "false", | |
"existing.custom.field" : "12109" | |
}, | |
"Summary" : { | |
"jira.field" : "summary", | |
"userChanged" : "true", | |
"manualMapping" : "false" | |
}, | |
"Component" : { | |
"jira.field" : "components", | |
"userChanged" : "true", | |
"manualMapping" : "false" | |
}, | |
"Development Team" : { | |
"userChanged" : "true", | |
"manualMapping" : "false", | |
"existing.custom.field" : "10400" | |
} | |
}, | |
"config.value.mappings" : { }, | |
"config.delimiter" : ",", | |
"config.project" : { | |
"project.type" : null, | |
"project.key" : "PLAN", | |
"project.description" : null, | |
"project.url" : null, | |
"project.name" : "Project Planning", | |
}, | |
"config.date.format" : "dd/MMM/yy h:mm a" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/zsh | |
# Pre-requisites: XMLStarlet | |
# brew install xmlstarlet | |
# See usage for required document structure | |
EXPORTMARKER=arrow-left | |
EXPORTEDMARKER=arrow-up | |
usage() { | |
cat << EOF | |
Usage: ${0##*/} [FILE] | |
Extract marked XMind topics to CSV for JIRA import | |
FILE XMind file from which to extract JIRA issues | |
To prepare topics for export: | |
1. Create a detached topic titled "JIRA" on each sheet with topics to be exported | |
2. Create sub-topics under this detached topic for the common export CSV columns | |
Columns for Issue Type, Component, etc. | |
3. Mark each topic for export with the $EXPORTMARKER marker | |
An output directory for the resulting CSV files will created, if not already present | |
A file for each sheet containing marked topic(s) will be created in the output directory | |
Each marked topic will be exported as a row in the corresponding CSV file | |
Title of the topic will be used as the issue Summary | |
Sub-topics will form headings within the issue Description | |
The original XMind file will be updated with the marker for each exported topic updated to $EXPORTEDMARKER | |
EOF | |
} | |
if [ ! -f "$1" ]; then | |
usage | |
exit 1 | |
fi | |
XMINDFILE="$1" | |
EXPORTDIR="${XMINDFILE%.*} JIRA CSV" | |
XMLSEL="xml sel -N x=urn:xmind:xmap:xmlns:content:2.0" | |
XMLED="xml ed -P -L -N x=urn:xmind:xmap:xmlns:content:2.0" | |
TMPDIR=$(mktemp -d) | |
TMPCONTENT=$TMPDIR/content.xml | |
unzip "$XMINDFILE" content.xml -d $TMPDIR | |
# Search for topics that have been marked for export | |
ISSUECOUNT=`$=XMLSEL -t -v "count(//x:topic//x:marker-ref[@marker-id=\"$EXPORTMARKER\"])" $TMPCONTENT` | |
if [[ $ISSUECOUNT -eq 0 ]]; then | |
>&2 echo No JIRA issue topics found, please mark issues to be exported with $EXPORTMARKER marker | |
exit 1 | |
else | |
ISSUESHEETS=`$=XMLSEL -T -t -m "/*/x:sheet/x:title[..//x:topic//x:marker-ref[@marker-id=\"$EXPORTMARKER\"]]" -v 'text()' -n -b $TMPCONTENT` | |
SHEETCOUNT=$(wc -l <<< "$ISSUESHEETS") | |
>&2 echo Found $ISSUECOUNT JIRA issue topics across $SHEETCOUNT sheets marked with $EXPORTMARKER marker | |
fi | |
# Start of export process | |
EXPORTTIMESTAMP=`date +%Y-%m-%d-%H%M%S` | |
[[ -d "$EXPORTDIR" ]] || mkdir -p "$EXPORTDIR" | |
# Export marked topics to sheet-specific JIRA CSV files | |
while read -r sheet; do | |
EXPORTFILE="$EXPORTDIR/$sheet $EXPORTTIMESTAMP.csv" | |
>&2 echo Exporting marked topics in sheet \"$sheet\" to \"$EXPORTFILE\"... | |
# Search for a detached topic named "JIRA" with field defaults | |
# The following extracts properties in name=value format | |
JIRATOPIC=`$=XMLSEL -T -t -m "/*/x:sheet[x:title[text()=\"$sheet\"]]//x:topics[@type=\"detached\"]/x:topic[x:title/text()=\"JIRA\"]/x:children/x:topics/x:topic" -v "concat(x:title, '=', (x:children//x:title)[1])" -n $TMPCONTENT` | |
if [[ -z "$JIRATOPIC" ]]; then | |
>&2 echo ERROR: Missing or empty detached "JIRA" topic on sheet \"$sheet\" containing topics marked for export | |
>&2 echo Skipping processing of sheet \"$sheet\" | |
continue | |
fi | |
FIELDNAMES=() | |
FIELDVALUES=() | |
# Thanks: https://unix.stackexchange.com/questions/296644/how-to-read-a-properties-file-into-an-associative-array | |
while IFS=$'=' read name value; do | |
case "$name" in | |
"" | "Summary" | "Description") | |
# Ignore empty or special fields | |
;; | |
*) | |
FIELDNAMES+=("$name") | |
FIELDVALUES+=("$value") | |
;; | |
esac | |
done <<< "$JIRATOPIC" | |
# Output direct children topics of an issue as headings in the Description field and concatenate their descendant titles as bullet points | |
COLS=($FIELDNAMES "Summary" "Description") | |
read -d '' ISSUETEMPLATE << EOF | |
-o "${(j:,:)COLS}" | |
-m "/*/x:sheet[x:title/text()='$sheet']//x:topic[x:marker-refs/x:marker-ref[@marker-id='$EXPORTMARKER']]" -n | |
-o "${(j:,:)FIELDVALUES}," | |
-v 'x:title' | |
-o ',"' | |
-m 'x:children/x:topics/x:topic' | |
-n -o 'h2.' -v 'x:title/text()' -n | |
-m 'x:children/x:topics/x:topic' | |
-n -o '* ' -v 'x:title' -m 'x:children//x:title' -o ' - ' -v 'text()' -b | |
-b -n | |
-b -n | |
-o '"' | |
-n -b | |
EOF | |
ISSUETEMPLATE=`tr '\n' ' ' <<< $ISSUETEMPLATE` | |
eval $XMLSEL -T -t $ISSUETEMPLATE $TMPCONTENT > $EXPORTFILE | |
# Update markers to exported for all affected issues | |
>&2 echo Updating markers from $EXPORTMARKER to $EXPORTEDMARKER for all exported issues on sheet \"$sheet\" | |
$=XMLED -u "/*/x:sheet[x:title/text()='$sheet']//x:topic/x:marker-refs/x:marker-ref[@marker-id='$EXPORTMARKER']/@marker-id" -v $EXPORTEDMARKER $TMPCONTENT | |
done <<< "$ISSUESHEETS" | |
# Store the updated content in the original XMind file | |
>&2 echo Storing updated content in original file | |
zip -fjT "$XMINDFILE" $TMPCONTENT | |
>&2 echo Cleaning up temporary work directory $TMPDIR | |
rm -rf $TMPDIR | |
# ========================================================================================= | |
# CODE GRAVEYARD | |
# ISSUEFIELDS=() | |
# ISSUEDEFAULTS=() | |
# # Thanks: https://unix.stackexchange.com/questions/296644/how-to-read-a-properties-file-into-an-associative-array | |
# while IFS=$'=' read field value; do | |
# case "$field" in | |
# "" | "Summary" | "Description") | |
# # Ignore empty or special fields | |
# ;; | |
# *) | |
# ISSUEFIELDS+=("$field") | |
# ISSUEDEFAULTS+=("$field" "$value") | |
# ;; | |
# esac | |
# done <<< "$JIRATOPIC" | |
# FIELDSEXPR="" | |
# for field value in ${(kv)ISSUEDEFAULTS}; do | |
# # Use the field value from the issue | |
# FIELDSEXPR+="-v '(.//x:title[text()=\"$field\"]/../x:children//x:title)[1]' " | |
# # Otherwise, fall back to default value specified on the sheet | |
# FIELDSEXPR+="-i 'count(.//x:title[text()=\"$field\"]) = 0' -o '$value' -b -o ',' " | |
# done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment