Created
December 8, 2023 13:01
-
-
Save ogerardin/bb69291a18b8203f0d6d796222ebc4dc to your computer and use it in GitHub Desktop.
Export Archi collaborative model to Confluence page
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/bash | |
# This script will export the views from an Archi collaborative model and upload them to a Confluence page. | |
# Usage: updateConfluence.sh [ DIR ] | |
# where DIR is base directory of the Archi model repo. If it is not specified, it defaults to the parent directory of | |
# this script (which reflects this repo's structure). | |
# | |
# Requirements: curl, yq, xmllint, git | |
# | |
# Ref: | |
# Archi CLI doc: https://github.com/archimatetool/archi/wiki/Archi-Command-Line-Interface | |
# Confluence API doc: https://docs.atlassian.com/ConfluenceServer/rest/7.19.16/ | |
# Confluence storage format: https://confluence.atlassian.com/conf719/confluence-storage-format-1157466554.html | |
# Confluence base URI | |
BASEURL=https://xxxxxx | |
# ID of target Confluence page (must exist beforehand) | |
PAGEID=xxxxxx | |
# Personal access token for Confluence API authentication, manage here: https://confluence.intramundi.com/plugins/personalaccesstokens/usertokens.action | |
TOKEN=xxxxxx | |
# Where the HTML files will go | |
HTMLDIR=output/html | |
# Where the reports will go | |
REPORTDIR=output/report | |
uploadAttachment() { | |
local -r file=$1 | |
local -r basename=$(basename "$file") | |
# query attachment | |
result=$(curl -k --no-progress-meter --location "$BASEURL/rest/api/content/$PAGEID/child/attachment?filename=$basename&expand=version" \ | |
--header "Authorization: Bearer $TOKEN") || return 1 | |
size=$(echo "$result" | jq -r ".size") | |
if [ $size -ne 0 ]; then | |
attachmentId=$(echo "$result" | jq -r ".results[0].id") | |
version=$(echo "$result" | jq ".results[0].version.number") | |
echo " attachment exists (id=$attachmentId, version=$version) - updating" | |
result=$(curl -k --no-progress-meter --location "$BASEURL/rest/api/content/$PAGEID/child/attachment/$attachmentId/data" \ | |
--header "X-Atlassian-Token: nocheck" \ | |
--header "Authorization: Bearer $TOKEN" \ | |
--form "file=@$file") || return 1 | |
version=$(echo "$result" | jq ".version.number") | |
echo " new version: $version" | |
else | |
echo " new attachment - creating" | |
result=$(curl -k --no-progress-meter --location "$BASEURL/rest/api/content/$PAGEID/child/attachment" \ | |
--header "X-Atlassian-Token: nocheck" \ | |
--header "Authorization: Bearer $TOKEN" \ | |
--form "file=@$file") || return 1 | |
attachmentId=$(echo "$result" | jq -r ".results[0].id") | |
version=$(echo "$result" | jq ".results[0].version.number") | |
echo " attachment created (id=$attachmentId, version=$version)" | |
fi | |
} | |
updateBody() { | |
echo " Querying page $PAGEID" | |
result=$(curl -k --no-progress-meter --location "$BASEURL/rest/api/content/$PAGEID?expand=body.view,version" --header "Authorization: Bearer $TOKEN") || return 1 | |
version=$(echo "$result" | jq ".version.number") | |
title=$(echo "$result" | jq -r ".title") | |
# body=$(echo "$result" | jq -r ".body.view.value") | |
echo " version=$version, title=$title" | |
echo " Updating body" | |
((version++)) | |
result=$(curl -k --no-progress-meter --location --request PUT "$BASEURL/rest/api/content/$PAGEID" \ | |
--header 'Content-Type: application/json' \ | |
--header "Authorization: Bearer $TOKEN" \ | |
--data "{ | |
\"version\": { | |
\"number\": $version, | |
\"message\": \"Generated by $0\" | |
}, | |
\"type\": \"page\", | |
\"title\": \"$title\", | |
\"body\": { | |
\"storage\": { | |
\"value\": $(echo "$BODY" | jq -Rsa .), | |
\"representation\": \"storage\" | |
} | |
} | |
}") || return 1 | |
echo " new version: $version" | |
} | |
processFolder() { | |
local -r folder=$1 | |
local -r level=$2 | |
local -r imgFolder=$3 | |
folderName=$(xmllint --xpath 'string(//@name)' "$folder/folder.xml") || return 1 | |
echo "Found folder '$folderName' (level $level)" | |
BODY="$BODY<h$level>$folderName</h$level>" | |
viewLevel=$((level + 1)) | |
shopt -s nullglob #no iteration if no file matched | |
shopt -s lastpipe #make sure assignment works in pipeline | |
# Iterate on views in folder, sorted by view name | |
for f in "$folder"/ArchimateDiagramModel_*.xml; do | |
viewName=$(xmllint --xpath 'string(//@name)' "$f") | |
id=$(xmllint --xpath 'string(//@id)' "$f") | |
echo "$id" "$viewName" | |
done | sort -k2 | while read -r id viewName; do | |
echo "[$level] Found diagram '$viewName' (id: $id)" | |
#image file name matches the view ID | |
img=$imgFolder/$id.png | |
[ -f "$img" ] || { echo "image not found $img"; continue; } | |
echo "[$level] Found image: $(file "$img")" | |
echo "[$level] Attaching image to page $PAGEID" | |
uploadAttachment "$img" || return 2 | |
BODY="$BODY<h$viewLevel>$viewName</h$viewLevel><ac:image ac:border='true'><ri:attachment ri:filename=\"$(basename "$img")\"/></ac:image><br/>" | |
# break | |
done | |
# process subfolders | |
shopt -s nullglob | |
for d in "$folder"/id-*/; do | |
[ -d "$d" ] && processFolder "$d" $((level + 1)) "$imgFolder" || return 3 | |
done | |
} | |
processModel() { | |
local folder=$1 | |
local htmlBase=$2 | |
modelId=$(xmllint --xpath 'string(//*/@id)' "$folder/folder.xml") || return 1 | |
modelName=$(xmllint --xpath 'string(//*/@name)' "$folder/folder.xml") || return 1 | |
echo "Found model '$modelName' (id: $modelId)" | |
processFolder "$folder/diagrams" 1 "$htmlBase/$modelId/images" || return 2 | |
} | |
# | |
# main | |
# | |
if [ -n "$1" ] ; then | |
cd "$1" || exit 1 | |
else | |
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) | |
cd "$SCRIPT_DIR"/.. || exit 1 | |
fi | |
echo "Started $(date -Isecond)" | |
echo "Working directory: $(pwd)" | |
if [ ! -f ./model/folder.xml ] ; then | |
echo "No Archi model found in $(pwd)" | |
exit 2 | |
fi | |
echo "Generating Archi HTML UI in $HTMLDIR..." | |
Archi -application com.archimatetool.commandline.app -consoleLog -nosplash --modelrepository.loadModel . \ | |
--html.createReport $HTMLDIR || exit 3 | |
echo "Generating Archi PDF report in $REPORTDIR..." | |
Archi -application com.archimatetool.commandline.app -consoleLog -nosplash --modelrepository.loadModel . \ | |
--jasper.filename report -jasper.format PDF --jasper.title "ArchiMate report" --jasper.createReport $REPORTDIR || exit 4 | |
#initialize page top | |
remote=$(git remote get-url origin) | |
case $remote in | |
git@*) | |
# rewrite SSH URL as HTTP | |
remote=${remote#git@} | |
remote=${remote%.git} | |
remote=${remote//:/\/} | |
remote=https://$remote | |
;; | |
http*) | |
#remove credentials | |
[[ $remote =~ (https?://)(.+@)?(.+) ]] && remote="${BASH_REMATCH[1]}${BASH_REMATCH[3]}" | |
;; | |
esac | |
BODY= | |
BODY=$BODY"<ac:structured-macro ac:name=\"info\"> | |
<ac:rich-text-body> | |
<p><b>This page was generated automatically from Archi model in repo <a href=\"$remote\">$remote</a> on $(date)</b></p> | |
<p><b>Do not edit manually!</b></p> | |
</ac:rich-text-body> | |
</ac:structured-macro>" | |
BODY=$BODY"<ac:structured-macro ac:name=\"toc\"/>" | |
echo "Attaching PDF report to page $PAGEID" | |
pdf=$REPORTDIR/report.pdf | |
uploadAttachment "$pdf" || exit 5 | |
BODY="$BODY<p>Full report: <ac:link><ri:attachment ri:filename=\"$(basename "$pdf")\"/></ac:link></p>" | |
processModel ./model $HTMLDIR || exit 6 | |
echo "Udpating page $PAGEID" | |
#echo "$BODY" > body.xhtml | |
updateBody || exit 7 | |
echo "Done $(date -Isecond)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment