mirror of https://github.com/captn3m0/outliner.git
commit
425d55e30f
|
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## 0.2.1 - 2019-08-14
|
||||
|
||||
- Adds a `push` command (See #2)
|
||||
|
||||
## 0.2.0 - 2019-08-12
|
||||
|
||||
- Adds export command (See [#1013](https://github.com/outline/outline/pull/1013) for corresponding Outline PR)
|
||||
|
|
|
@ -4,6 +4,9 @@ WORKDIR /outliner
|
|||
COPY . /outliner/
|
||||
|
||||
RUN gem install bundler && \
|
||||
bundle install
|
||||
bundle install && \
|
||||
apk add --no-cache git openssh-client && \
|
||||
echo -e "StrictHostKeyChecking no" >> /etc/ssh/ssh_config && \
|
||||
mkdir /root/.ssh
|
||||
|
||||
ENTRYPOINT ["/outliner/entrypoint.sh"]
|
||||
|
|
17
README.md
17
README.md
|
@ -81,10 +81,27 @@ docker run --env OUTLINE_BASE_URI="https://kb.example.com" \
|
|||
import "/data" "Archive"
|
||||
```
|
||||
|
||||
### Push
|
||||
|
||||
Note: Push is currently only available as a Docker Command
|
||||
|
||||
```bash
|
||||
docker run --env OUTLINE_BASE_URI="https://kb.example.com" \
|
||||
--env OUTLINE_TOKEN="PUT YOUR TOKEN HERE" \
|
||||
--env OUTLINE_TOKEN="PUT YOUR TOKEN HERE" \
|
||||
--env GIT_BRANCH=outline \
|
||||
--env GIT_REMOTE_URL=git@example.com:org/outline.backup.git
|
||||
--volume /etc/ssh/private.key:/root/.ssh/id_rsa
|
||||
captn3m0/outliner \
|
||||
push
|
||||
```
|
||||
|
||||
#### Limitations
|
||||
|
||||
- Images are currently not imported. Host them externally for this to work.
|
||||
- Only `.md` files are currently supported
|
||||
- `push` doesn't sync file-history, but is meant to push a one-time backup to Git.
|
||||
- `StrictHostKeyChecking` is currently disabled for `push`, please only run this in trusted networks.
|
||||
|
||||
## Development
|
||||
|
||||
|
|
|
@ -1,19 +1,63 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Please run with outliner [export|import] arguments"
|
||||
echo "Please run with outliner [export|import|sync] arguments"
|
||||
exit
|
||||
fi
|
||||
|
||||
setup_git() {
|
||||
if [ -f "$HOME/.ssh/id_rsa" ]; then
|
||||
# This is required because Kubernetes secret mounts can't
|
||||
# have file permissions set
|
||||
chmod 0400 "$HOME/.ssh/id_rsa"
|
||||
|
||||
if [ ! -d "$HOME/.ssh/id_rsa.pub" ]; then
|
||||
ssh-keygen -y -f "$HOME/.ssh/id_rsa" > "$HOME/.ssh/id_rsa.pub"
|
||||
fi
|
||||
echo "[+] Using SSH key for git pushes"
|
||||
else
|
||||
echo "[E] Git credentials not available, quitting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
eval $(ssh-agent)
|
||||
ssh-add "$HOME/.ssh/id_rsa"
|
||||
}
|
||||
|
||||
update_git_config() {
|
||||
EMAIL=${GIT_EMAIL:-outliner@example.invalid}
|
||||
git config --global user.email "$EMAIL"
|
||||
git config --global user.name "Outliner Backup"
|
||||
git remote add origin "$GIT_REMOTE_URL"
|
||||
}
|
||||
|
||||
case $1 in
|
||||
export)
|
||||
shift
|
||||
bundle exec outliner-export $@
|
||||
bundle exec outliner-export "$@"
|
||||
;;
|
||||
import)
|
||||
shift
|
||||
bundle exec outliner-import $@
|
||||
break
|
||||
bundle exec outliner-import "$@"
|
||||
;;
|
||||
sync)
|
||||
tmp_dir=$(mktemp -d)
|
||||
if [ -z "$GIT_REMOTE_URL" ]; then
|
||||
echo "[E] GIT_REMOTE_URL not set"
|
||||
exit 1
|
||||
else
|
||||
setup_git
|
||||
bundle exec outliner-export "$tmp_dir"
|
||||
cd "$tmp_dir"
|
||||
git init
|
||||
update_git_config
|
||||
git add .
|
||||
git commit --message "Backup: $(date)" > /dev/null
|
||||
BRANCH=${GIT_BRANCH:-master}
|
||||
git checkout -b "$BRANCH"
|
||||
git status
|
||||
git push origin --force "HEAD:$BRANCH"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Invalid command, please check README"
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "bundler/setup"
|
||||
require "outliner"
|
||||
require 'bundler/setup'
|
||||
require 'outliner'
|
||||
require 'tempfile'
|
||||
|
||||
def validate
|
||||
unless (ARGV.size == 1) and Dir.exists?(ARGV[0]) and ENV.key?('OUTLINE_BASE_URI') and ENV.key?('OUTLINE_TOKEN')
|
||||
puts "[E] Please call as `outliner-export directory`"
|
||||
puts "[E] Please export OUTLINE_BASE_URI and OUTLINE_TOKEN environment variables"
|
||||
puts "[E] OUTLINE_BASE_URI should not include /api"
|
||||
exit 1
|
||||
end
|
||||
raise 'Missing arguments' if ARGV.size != 1
|
||||
raise 'Invalid directory' unless Dir.exist?(ARGV[0])
|
||||
raise 'OUTLINE_BASE_URI not set' unless ENV.key?('OUTLINE_BASE_URI')
|
||||
raise 'OUTLINE_TOKEN not set' unless ENV.key?('OUTLINE_TOKEN')
|
||||
end
|
||||
|
||||
# Run validations
|
||||
|
@ -25,7 +24,7 @@ response = CLIENT.collections_exportAll(download: true)
|
|||
|
||||
# Extract it to a tempfle
|
||||
file = Tempfile.new('download.zip')
|
||||
File.open(file.path, 'w') { |file| file.write(response.body) }
|
||||
File.open(file.path, 'w') { |f| f.write(response.body) }
|
||||
|
||||
`unzip -o "#{file.path}" -d "#{local_directory}"`
|
||||
|
||||
|
|
|
@ -1,25 +1,28 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "bundler/setup"
|
||||
require "outliner"
|
||||
require 'bundler/setup'
|
||||
require 'outliner'
|
||||
|
||||
def validate
|
||||
unless (ARGV.size == 2) and Dir.exists?(ARGV[0]) and ARGV[1].match(/\w+/) and ENV.key?('OUTLINE_BASE_URI') and ENV.key?('OUTLINE_TOKEN')
|
||||
puts "[E] Please call as `outliner-import local_directory remote_collection_name`"
|
||||
puts "[E] Please export OUTLINE_BASE_URI and OUTLINE_TOKEN environment variables"
|
||||
puts "[E] OUTLINE_BASE_URI should not include /api"
|
||||
exit 1
|
||||
end
|
||||
raise 'Missing arguments' if ARGV.size != 2
|
||||
raise 'Invalid directory' unless Dir.exist?(ARGV[0])
|
||||
raise 'Invalid collection' unless ARGV[1].match(/\w+/)
|
||||
raise 'OUTLINE_BASE_URI not set' unless ENV.key?('OUTLINE_BASE_URI')
|
||||
raise 'OUTLINE_TOKEN not set' unless ENV.key?('OUTLINE_TOKEN')
|
||||
end
|
||||
|
||||
def create_documents_recursively(directory, collection_id, parent_document_id=nil)
|
||||
def create_documents_recursively(directory, collection_id, parent_document_id = nil)
|
||||
cwd = Dir.pwd
|
||||
Dir.chdir directory
|
||||
# Create all documents for this directory
|
||||
Dir["*.md"].each do |file|
|
||||
Dir['*.md'].each do |file|
|
||||
params = {
|
||||
title: file[0...-3],
|
||||
text: file[0...-3] + "\n" + File.read(file) + "\n\n---\nImported at #{Time.now}",
|
||||
text: file[0...-3] +
|
||||
"\n" +
|
||||
File.read(file) +
|
||||
"\n\n---\nImported at #{Time.now}",
|
||||
collectionId: collection_id,
|
||||
publish: true
|
||||
}
|
||||
|
@ -30,11 +33,11 @@ def create_documents_recursively(directory, collection_id, parent_document_id=ni
|
|||
end
|
||||
|
||||
# Create child documents for each sub-directory
|
||||
Dir.glob('*').select {|f| File.directory? f}.each do |dir|
|
||||
Dir.glob('*').select { |f| File.directory? f }.each do |dir|
|
||||
puts "[-] #{dir}"
|
||||
params = {
|
||||
title: dir,
|
||||
text: dir +"\nImported at #{Time.now}",
|
||||
text: dir + "\nImported at #{Time.now}",
|
||||
collectionId: collection_id,
|
||||
publish: true,
|
||||
parentDocumentId: parent_document_id
|
||||
|
@ -58,12 +61,11 @@ root_collection_id = CLIENT.find_or_create_collection(remote_collection_name)
|
|||
|
||||
begin
|
||||
create_documents_recursively(local_directory, root_collection_id)
|
||||
puts "[S] Import successful"
|
||||
rescue Exception => e
|
||||
puts '[S] Import successful'
|
||||
rescue StandardError? => e
|
||||
# If we fail, print an error, and delete the collection
|
||||
puts "[E] Import failed with error: #{e.message}"
|
||||
CLIENT.collections_delete(id: root_collection_id)
|
||||
puts "[E] Deleted collection, please report the issue or retry"
|
||||
puts '[E] Deleted collection, please report the issue or retry'
|
||||
exit 1
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue