|
#!/usr/bin/env bash |
|
|
|
set -e |
|
cd "${BASH_SOURCE%/*}" || exit |
|
|
|
SPACE_DUMPS="." |
|
SPACE_ORG="org.jetbrains.space" |
|
SPACE_TOKEN="<personal-token>" |
|
source .env |
|
|
|
if [ -z "$1" ]; then |
|
echo "You need to specify the issue (like PROJ-T-123)" |
|
exit 1 |
|
fi |
|
|
|
ISSUE="$1" |
|
PROJECT=${ISSUE%%-*} |
|
FROM="2000-01-01T00%3A00%3A00.000Z" |
|
OUTDIR="$SPACE_DUMPS/$PROJECT/$ISSUE" |
|
COMMENTS_FILE="$OUTDIR/comments.json" |
|
ISSUE_FILE="$OUTDIR/issue.json" |
|
ATTACHMENTS="$OUTDIR/attachments" |
|
|
|
mkdir -p "$OUTDIR" |
|
|
|
# Store the issue itself |
|
curl -s "https://$SPACE_ORG/api/http/issues?issueId=key:$ISSUE&\$fields=id,assignee(username),attachmentsCount,commentsCount,createdBy(name),creationTime,deletedBy(name),deletedTime,dueDate,number,status(name,resolved,archived),tags(name),title,attachments(details(id,filename,name,deletedIdentity)),customFields,description" \ |
|
-H "Authorization: Bearer $SPACE_TOKEN" \ |
|
-H 'Accept: application/json' | jq . > "$ISSUE_FILE" |
|
echo "Got issue.json for $ISSUE" |
|
|
|
MAX_ITERATIONS=50 |
|
|
|
TEMP_FILE=$(mktemp) |
|
|
|
# Initialize an empty array for all messages |
|
echo '[]' > "$TEMP_FILE" |
|
|
|
for ((i=0; i<MAX_ITERATIONS; i++)); do |
|
RESPONSE=$(curl -s "https://$SPACE_ORG/api/http/chats/messages?channel=issue:key:$ISSUE&startFromDate=$FROM&sorting=FromOldestToNewest&batchSize=50&\$fields=nextStartFromDate,messages(id,created,edited,text,time,author(name),details(className),attachments(details(id,filename,name,unfurl(details(tag(name),strikeThrough)))),reactions(emojiReactions(emoji,meReacted,count)))" \ |
|
-H "Authorization: Bearer $SPACE_TOKEN" \ |
|
-H 'Accept: application/json') |
|
|
|
# Extract messages from the response and add to the temporary file |
|
echo "$RESPONSE" | jq '.messages' | jq -s 'add' "$TEMP_FILE" - > "$TEMP_FILE.new" && mv "$TEMP_FILE.new" "$TEMP_FILE" |
|
|
|
LENGTH=$(echo "$RESPONSE" | jq '.messages | length') |
|
echo "Got $LENGTH messages in query $((i+1))" |
|
|
|
if [[ "$LENGTH" != 50 ]]; then |
|
break |
|
fi |
|
|
|
if [[ $i -eq $((MAX_ITERATIONS-1)) ]]; then |
|
echo "NOT EXPECTED" |
|
rm "$TEMP_FILE" |
|
exit 1 |
|
fi |
|
|
|
FROM=$(echo "$RESPONSE" | jq -r '.nextStartFromDate.iso') |
|
done |
|
|
|
# Wrap the final array in an object |
|
jq '{ messages: . }' "$TEMP_FILE" > "$COMMENTS_FILE" |
|
|
|
rm "$TEMP_FILE" |
|
|
|
LENGTH=$(jq '.messages | length' < "$COMMENTS_FILE") |
|
echo "All $LENGTH messages have been concatenated into 'comments.json'" |
|
|
|
# loading the issue attachments |
|
LIST=$(jq -r 'select(.attachments | length > 0).attachments[].details | select(.className != "UnfurlAttachment") | [ .className, .id, .name+.filename ] | @csv' < "$ISSUE_FILE") |
|
|
|
echo "$LIST" | while IFS=',' read -r TYPE ID NAME |
|
do |
|
TYPE=$(echo $TYPE | tr -d '"') |
|
ID=$(echo $ID | tr -d '"') |
|
NAME=$(echo $NAME | tr -d '"') |
|
|
|
# Skip empty lines |
|
[ -z "$TYPE" ] && continue |
|
[ "$TYPE" = "DeletedAttachment" ] && continue |
|
|
|
# skip existing attachments |
|
if [ -f "$ATTACHMENTS/$ID/$NAME" ]; then |
|
echo "Skipping existing \"$NAME\" ($ID / $TYPE)" |
|
continue |
|
fi |
|
|
|
# Print the extracted values |
|
mkdir -p "$ATTACHMENTS/$ID" |
|
echo "Downloading \"$NAME\" ($ID / $TYPE)" |
|
curl -s -L "https://$SPACE_ORG/d/$ID?f=0&download=true" -H "Authorization: Bearer $SPACE_TOKEN" -o "$ATTACHMENTS/$ID/$NAME" |
|
done |
|
|
|
# loading the comment attachments |
|
LIST=$(jq -r '.messages[] | select(.attachments | length > 0).attachments[].details | select(.className != "UnfurlAttachment") | [ .className, .id, .name+.filename ] | @csv' < "$COMMENTS_FILE") |
|
|
|
echo "$LIST" | while IFS=',' read -r TYPE ID NAME |
|
do |
|
TYPE=$(echo $TYPE | tr -d '"') |
|
ID=$(echo $ID | tr -d '"') |
|
NAME=$(echo $NAME | tr -d '"') |
|
|
|
# Skip empty lines |
|
[ -z "$TYPE" ] && continue |
|
[ "$TYPE" = "DeletedAttachment" ] && continue |
|
|
|
# skip existing attachments |
|
if [ -f "$ATTACHMENTS/$ID/$NAME" ]; then |
|
echo "Skipping existing \"$NAME\" ($ID / $TYPE)" |
|
continue |
|
fi |
|
|
|
# Print the extracted values |
|
mkdir -p "$ATTACHMENTS/$ID" |
|
echo "Downloading \"$NAME\" ($ID / $TYPE)" |
|
curl -s -L "https://$SPACE_ORG/d/$ID?f=0&download=true" -H "Authorization: Bearer $SPACE_TOKEN" -o "$ATTACHMENTS/$ID/$NAME" |
|
done |
Yes. I wrote some modifications for the Gitea and extended their API and the API SDK with a "time travel" feature. This let me insert all the issues, attachments, comment into Gitea based repositories. Converting status to labels and custom fields to either labels or front matter style data in the head of the issue text. I also had all our git repositories rewritten so that the commit messages refer to the new Gitea based repositories. This came out very good, but was a lot of work. Maybe the worst thing was that I converted data before we made the last payment cycle. As I tracked all the time and invoice data in the custom fields I had to write a "diff" tool later on, to add the missing data into Gitea. I just finished that last weekend, so that we can now calculate the new invoices and know what the clients already paid for. I am so mad at JetBrains for their actions.