outliner 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 965c6e37c5f452ee902a235cf5eaaa73375894dbf1244cca2065f338ab12badd
4
- data.tar.gz: 84533e4c6617795ee3a50181c6e78b178709caa356730cdcc93d26c89a99d5cc
3
+ metadata.gz: 2f21fefa59fb5ff2a67d87273bcaa82096ba5b1166a42ffa6802003b422c991f
4
+ data.tar.gz: 14f75297d7f94c001e0f7a43dde6d29f146f575f662e10b614b3e94a1f2d4339
5
5
  SHA512:
6
- metadata.gz: 29c1e5c613d50fae1337ba041c1203d4d2e5ce82987997e59a83e21875a925c5ed3c0b730513de6a5efa9254997c04c79c4ea8ba26e9925db1019987c888da16
7
- data.tar.gz: 0c08dec404bffea65a5b00647770fb761725db0a2d5445830d401a22a26abbd77768a9336635913dca195486faf1b39e9becaef2ef7865cceca6d6064079b9a9
6
+ metadata.gz: 83dae751c834a29fe279ef18fbe1d6fcc20062466b9bdfd61411dd189aadb6367c16b3fc92dade5087ecfdf86de81e2e4e8cb6db88fea0eb6a1d24f1fcbc142b
7
+ data.tar.gz: 437a5728107aa019ef6e031fde94f3078d332cc096a294d3ce563a8a6a862d0eebd29a44f3ba8fe5a97cc2ee23507c3a39c125790cf9cbd250b50dcf7da7d7b8
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## 1.0.0 - 2020-04-26
11
+
12
+ ### Changed
13
+
14
+ - Changes `push` to `sync`.
15
+
16
+ ### Added
17
+
18
+ - `sync` now actually syncs the git repository, and maintains history.
19
+
20
+
21
+ ## 0.2.2 - 2019-08-14
22
+
23
+ - Adds a `push` command (See #2)
24
+
10
25
  ## 0.2.0 - 2019-08-12
11
26
 
12
27
  - Adds export command (See [#1013](https://github.com/outline/outline/pull/1013) for corresponding Outline PR)
data/Dockerfile CHANGED
@@ -1,9 +1,12 @@
1
- FROM ruby:2.6-alpine
1
+ FROM ruby:2.7-alpine
2
2
 
3
3
  WORKDIR /outliner
4
4
  COPY . /outliner/
5
5
 
6
6
  RUN gem install bundler && \
7
- bundle install
7
+ bundle install && \
8
+ apk add --no-cache git openssh-client rsync && \
9
+ echo -e "StrictHostKeyChecking no" >> /etc/ssh/ssh_config && \
10
+ mkdir /root/.ssh
8
11
 
9
12
  ENTRYPOINT ["/outliner/entrypoint.sh"]
@@ -1,29 +1,29 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- outliner (0.1.1)
4
+ outliner (0.2.2)
5
5
  httparty (~> 0.17)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- addressable (2.6.0)
11
- public_suffix (>= 2.0.2, < 4.0)
10
+ addressable (2.7.0)
11
+ public_suffix (>= 2.0.2, < 5.0)
12
12
  crack (0.4.3)
13
13
  safe_yaml (~> 1.0.0)
14
- hashdiff (1.0.0)
15
- httparty (0.17.0)
14
+ hashdiff (1.0.1)
15
+ httparty (0.18.0)
16
16
  mime-types (~> 3.0)
17
17
  multi_xml (>= 0.5.2)
18
- mime-types (3.2.2)
18
+ mime-types (3.3.1)
19
19
  mime-types-data (~> 3.2015)
20
- mime-types-data (3.2019.0331)
20
+ mime-types-data (3.2019.1009)
21
21
  minitest (5.8.5)
22
22
  multi_xml (0.6.0)
23
- public_suffix (3.1.1)
23
+ public_suffix (4.0.4)
24
24
  rake (10.5.0)
25
25
  safe_yaml (1.0.5)
26
- webmock (3.6.0)
26
+ webmock (3.6.2)
27
27
  addressable (>= 2.3.6)
28
28
  crack (>= 0.3.2)
29
29
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -39,4 +39,4 @@ DEPENDENCIES
39
39
  webmock (~> 3.6.0)
40
40
 
41
41
  BUNDLED WITH
42
- 2.0.2
42
+ 2.1.4
data/LICENSE CHANGED
@@ -1,7 +1,7 @@
1
- Copyright 2019 Abhay Rana
1
+ Copyright 2020 Abhay Rana
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
5
5
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
6
 
7
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Outliner [![Gem Version](https://badge.fury.io/rb/outliner.svg)](https://badge.fury.io/rb/outliner) [![](https://images.microbadger.com/badges/version/captn3m0/outliner:v0.2.0.svg)](https://microbadger.com/images/captn3m0/outliner:v0.2.0 'Get your own version badge on microbadger.com') [![](https://images.microbadger.com/badges/version/captn3m0/outliner:latest.svg)](https://microbadger.com/images/captn3m0/outliner:latest 'Get your own version badge on microbadger.com')
1
+ # Outliner [![Gem Version](https://badge.fury.io/rb/outliner.svg)](https://badge.fury.io/rb/outliner) [![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/captn3m0/outliner)](https://hub.docker.com/r/captn3m0/outliner) [![Docker Image Version (latest semver)](https://img.shields.io/docker/v/captn3m0/outliner)](https://hub.docker.com/r/captn3m0/outliner) [![Docker Image Size (latest semver)](https://img.shields.io/docker/image-size/captn3m0/outliner)](https://hub.docker.com/r/captn3m0/outliner)
2
2
 
3
3
  A simple HTTParty based wrapper for the [Outline API](https://www.getoutline.com/developers). It also offers a one-line import option to let you migrate an existing set of Markdown files to Outline. For quickly running export/import commands, you can use the Docker Image as well.
4
4
 
@@ -60,11 +60,16 @@ outliner-export "$DESTINATION_DIRECTORY"
60
60
 
61
61
  You can use the pre-built docker image to run the above commands as well. See the following commands for examples:
62
62
 
63
+ ### Setup
64
+
65
+ Copy the `env.sample` file to `.env` and update the values there.
66
+
63
67
  ### Export
64
68
 
69
+ Downloads all collections from Outline, and exports them as nested markdown files inside the given directory (`/data` inside the container, mount it accordingly.)
70
+
65
71
  ```bash
66
- docker run --env OUTLINE_BASE_URI="https://kb.example.com" \
67
- --env OUTLINE_TOKEN="PUT YOUR TOKEN HERE" \
72
+ docker run --env-file .env
68
73
  --volume /tmp:/data \
69
74
  captn3m0/outliner \
70
75
  export \
@@ -73,18 +78,33 @@ docker run --env OUTLINE_BASE_URI="https://kb.example.com" \
73
78
 
74
79
  ### Import
75
80
 
81
+ Imports all markdown documents in a directory to a named Collection on outline. Creates the collection if it doesn't exist.
82
+
76
83
  ```bash
77
- docker run --env OUTLINE_BASE_URI="https://kb.example.com" \
78
- --env OUTLINE_TOKEN="PUT YOUR TOKEN HERE" \
84
+ docker run --env-file .env
79
85
  --volume /path/to/wiki:/data \
80
86
  captn3m0/outliner \
81
- import "/data" "Archive"
87
+ import /data "Archive"
88
+ ```
89
+
90
+ ### Sync
91
+
92
+ Does a export from Outline, and pushes the corresponding result to the Git repository. Currenly does a force-push to the repository. Use with care.
93
+
94
+ Note: Sync is currently only available as a Docker Command
95
+
96
+ ```bash
97
+ docker run --env-file .env
98
+ --volume /etc/ssh/private.key:/root/.ssh/id_rsa
99
+ captn3m0/outliner \
100
+ sync
82
101
  ```
83
102
 
84
103
  #### Limitations
85
104
 
86
- - Images are currently not imported. Host them externally for this to work.
87
- - Only `.md` files are currently supported
105
+ - [import] Images are currently not imported. Host them externally for this to work.
106
+ - [import] Only `.md` files are currently supported
107
+ - [docker] `StrictHostKeyChecking` is currently disabled for `push`, please only run this in trusted networks.
88
108
 
89
109
  ## Development
90
110
 
@@ -1,19 +1,77 @@
1
1
  #!/bin/sh
2
-
2
+ set -eu
3
3
  if [ $# -eq 0 ]; then
4
- echo "Please run with outliner [export|import] arguments"
4
+ echo "Please run with outliner [export|import|sync] arguments"
5
5
  exit
6
6
  fi
7
7
 
8
+ setup_git() {
9
+ if [ -f "$HOME/.ssh/id_rsa" ]; then
10
+ # This is required because Kubernetes secret mounts can't
11
+ # have file permissions set
12
+ chmod 0400 "$HOME/.ssh/id_rsa"
13
+
14
+ if [ ! -d "$HOME/.ssh/id_rsa.pub" ]; then
15
+ ssh-keygen -y -f "$HOME/.ssh/id_rsa" > "$HOME/.ssh/id_rsa.pub"
16
+ fi
17
+ echo "[+] Using SSH key for git pushes"
18
+ else
19
+ echo "[E] Git credentials not available, quitting"
20
+ exit 1
21
+ fi
22
+
23
+ eval $(ssh-agent)
24
+ ssh-add "$HOME/.ssh/id_rsa"
25
+ }
26
+
27
+ update_git_config() {
28
+ EMAIL=${GIT_EMAIL:-outliner@example.invalid}
29
+ git config --global user.email "$EMAIL"
30
+ git config --global user.name "Outliner Backup"
31
+ git remote add origin "$GIT_REMOTE_URL"
32
+ }
33
+
8
34
  case $1 in
9
35
  export)
10
36
  shift
11
- bundle exec outliner-export $@
37
+ bundle exec outliner-export "$@"
12
38
  ;;
13
39
  import)
14
40
  shift
15
- bundle exec outliner-import $@
16
- break
41
+ bundle exec outliner-import "$@"
42
+ ;;
43
+ sync)
44
+ BRANCH=${GIT_BRANCH:-master}
45
+ old_git_dir=$(mktemp -d)
46
+ fresh_export_dir=$(mktemp -d)
47
+ if [ -z "$GIT_REMOTE_URL" ]; then
48
+ echo "[E] GIT_REMOTE_URL not set"
49
+ exit 1
50
+ else
51
+ git clone --branch "$BRANCH" "$GIT_REMOTE_URL" "$old_git_dir"
52
+ setup_git
53
+ update_git_config
54
+ echo "[+] Exporting data from Outline"
55
+ bundle exec outliner-export "$fresh_export_dir"
56
+ echo "[+] Resetting git repository"
57
+ cd "$old_git_dir"
58
+ # We update so that git forgets all files
59
+ git ls-files -z |xargs -n1 -0 git rm
60
+ # Then we copy across the files from the new export
61
+ cd "$fresh_export_dir"
62
+ echo "[+] Updating git repository"
63
+ rsync -av . "$old_git_dir"
64
+ cd "$old_git_dir"
65
+ echo "[+] Committing to git"
66
+ git add .
67
+ git commit --message "Backup: $(date)" > /dev/null
68
+ git status
69
+ echo "[+] Pushing to git remote"
70
+ git push origin "HEAD:$BRANCH"
71
+ echo "[+] Cleaning up"
72
+ rm -rf "$old_git_dir"
73
+ rm -rf "$fresh_export_dir"
74
+ fi
17
75
  ;;
18
76
  *)
19
77
  echo "Invalid command, please check README"
@@ -0,0 +1,4 @@
1
+ OUTLINE_BASE_URI=https://outline.example.com
2
+ GIT_BRANCH=master
3
+ GIT_REMOTE_URL=git@example.com:org/outline.backup.git
4
+ OUTLINE_TOKEN=
@@ -1,16 +1,15 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "outliner"
4
+ require 'bundler/setup'
5
+ require 'outliner'
5
6
  require 'tempfile'
6
7
 
7
8
  def validate
8
- unless (ARGV.size == 1) and Dir.exists?(ARGV[0]) and ENV.key?('OUTLINE_BASE_URI') and ENV.key?('OUTLINE_TOKEN')
9
- puts "[E] Please call as `outliner-export directory`"
10
- puts "[E] Please export OUTLINE_BASE_URI and OUTLINE_TOKEN environment variables"
11
- puts "[E] OUTLINE_BASE_URI should not include /api"
12
- exit 1
13
- end
9
+ raise 'Missing arguments' if ARGV.size != 1
10
+ raise 'Invalid directory' unless Dir.exist?(ARGV[0])
11
+ raise 'OUTLINE_BASE_URI not set' unless ENV.key?('OUTLINE_BASE_URI')
12
+ raise 'OUTLINE_TOKEN not set' unless ENV.key?('OUTLINE_TOKEN')
14
13
  end
15
14
 
16
15
  # Run validations
@@ -25,7 +24,7 @@ response = CLIENT.collections_exportAll(download: true)
25
24
 
26
25
  # Extract it to a tempfle
27
26
  file = Tempfile.new('download.zip')
28
- File.open(file.path, 'w') { |file| file.write(response.body) }
27
+ File.open(file.path, 'w') { |f| f.write(response.body) }
29
28
 
30
29
  `unzip -o "#{file.path}" -d "#{local_directory}"`
31
30
 
@@ -1,25 +1,28 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "outliner"
4
+ require 'bundler/setup'
5
+ require 'outliner'
5
6
 
6
7
  def validate
7
- 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')
8
- puts "[E] Please call as `outliner-import local_directory remote_collection_name`"
9
- puts "[E] Please export OUTLINE_BASE_URI and OUTLINE_TOKEN environment variables"
10
- puts "[E] OUTLINE_BASE_URI should not include /api"
11
- exit 1
12
- end
8
+ raise 'Missing arguments' if ARGV.size != 2
9
+ raise 'Invalid directory' unless Dir.exist?(ARGV[0])
10
+ raise 'Invalid collection' unless ARGV[1].match(/\w+/)
11
+ raise 'OUTLINE_BASE_URI not set' unless ENV.key?('OUTLINE_BASE_URI')
12
+ raise 'OUTLINE_TOKEN not set' unless ENV.key?('OUTLINE_TOKEN')
13
13
  end
14
14
 
15
- def create_documents_recursively(directory, collection_id, parent_document_id=nil)
15
+ def create_documents_recursively(directory, collection_id, parent_document_id = nil)
16
16
  cwd = Dir.pwd
17
17
  Dir.chdir directory
18
18
  # Create all documents for this directory
19
- Dir["*.md"].each do |file|
19
+ Dir['*.md'].each do |file|
20
20
  params = {
21
21
  title: file[0...-3],
22
- text: file[0...-3] + "\n" + File.read(file) + "\n\n---\nImported at #{Time.now}",
22
+ text: file[0...-3] +
23
+ "\n" +
24
+ File.read(file) +
25
+ "\n\n---\nImported at #{Time.now}",
23
26
  collectionId: collection_id,
24
27
  publish: true
25
28
  }
@@ -30,11 +33,11 @@ def create_documents_recursively(directory, collection_id, parent_document_id=ni
30
33
  end
31
34
 
32
35
  # Create child documents for each sub-directory
33
- Dir.glob('*').select {|f| File.directory? f}.each do |dir|
36
+ Dir.glob('*').select { |f| File.directory? f }.each do |dir|
34
37
  puts "[-] #{dir}"
35
38
  params = {
36
39
  title: dir,
37
- text: dir +"\nImported at #{Time.now}",
40
+ text: dir + "\nImported at #{Time.now}",
38
41
  collectionId: collection_id,
39
42
  publish: true,
40
43
  parentDocumentId: parent_document_id
@@ -54,16 +57,15 @@ remote_collection_name = ARGV[1]
54
57
 
55
58
  # Create a root collection
56
59
  CLIENT = Outliner::Client.new ENV['OUTLINE_BASE_URI']
57
- root_collection_id = find_or_create_collection(CLIENT, remote_collection_name)
60
+ root_collection_id = CLIENT.find_or_create_collection(remote_collection_name)
58
61
 
59
62
  begin
60
63
  create_documents_recursively(local_directory, root_collection_id)
61
- puts "[S] Import successful"
62
- rescue Exception => e
64
+ puts '[S] Import successful'
65
+ rescue StandardError? => e
63
66
  # If we fail, print an error, and delete the collection
64
67
  puts "[E] Import failed with error: #{e.message}"
65
68
  CLIENT.collections_delete(id: root_collection_id)
66
- puts "[E] Deleted collection, please report the issue or retry"
69
+ puts '[E] Deleted collection, please report the issue or retry'
67
70
  exit 1
68
71
  end
69
-
@@ -10,10 +10,20 @@ module Outliner
10
10
  @token = ENV['OUTLINE_TOKEN']
11
11
  end
12
12
 
13
+ def find_or_create_collection(name)
14
+ collections = self.collections_list(limit: 100)['data']
15
+ collections.filter!{|c|c['name'] == name}
16
+ if collections.size >= 1
17
+ collections[0]['id']
18
+ else
19
+ self.collections_create(name: name, description: 'Imported Collection')['data']['id']
20
+ end
21
+ end
22
+
13
23
  def method_missing(method_name, params = {})
14
24
  method_name = '/' + method_name.to_s.sub('_', '.')
15
25
  body = {token: @token}.merge(params).to_json
16
- options = {
26
+ options = {
17
27
  body: body,
18
28
  headers: {
19
29
  'Accept'=>'application/json',
@@ -1,3 +1,3 @@
1
1
  module Outliner
2
- VERSION = "0.2.0"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
7
7
  spec.name = "outliner"
8
8
  spec.version = Outliner::VERSION
9
9
  spec.authors = ["Nemo"]
10
- spec.email = ["rubygem.outliner@captnemo.in"]
10
+ spec.email = ["outliner@captnemo.in"]
11
11
  spec.licenses = ["MIT"]
12
12
 
13
13
  spec.summary = "A simple HTTParty based client for outline knowledge base."
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: outliner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nemo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-08-12 00:00:00.000000000 Z
11
+ date: 2020-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -82,7 +82,7 @@ dependencies:
82
82
  version: 5.8.4
83
83
  description:
84
84
  email:
85
- - rubygem.outliner@captnemo.in
85
+ - outliner@captnemo.in
86
86
  executables:
87
87
  - outliner-export
88
88
  - outliner-import
@@ -100,11 +100,11 @@ files:
100
100
  - bin/console
101
101
  - bin/setup
102
102
  - entrypoint.sh
103
+ - env.sample
103
104
  - exe/outliner-export
104
105
  - exe/outliner-import
105
106
  - lib/outliner.rb
106
107
  - lib/outliner/client.rb
107
- - lib/outliner/helper.rb
108
108
  - lib/outliner/version.rb
109
109
  - outliner.gemspec
110
110
  homepage: https://github.com/captn3m0/outliner
@@ -129,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
129
  - !ruby/object:Gem::Version
130
130
  version: '0'
131
131
  requirements: []
132
- rubygems_version: 3.0.4
132
+ rubygems_version: 3.1.2
133
133
  signing_key:
134
134
  specification_version: 4
135
135
  summary: A simple HTTParty based client for outline knowledge base.
@@ -1,13 +0,0 @@
1
- module Outliner
2
- class Helper
3
- def find_or_create_collection(client, name)
4
- collections = client.collections_list(limit: 100)['data']
5
- collections.filter!{|c|c['name'] == name}
6
- if collections.size >= 1
7
- collections[0]['id']
8
- else
9
- client.collections_create(name: name, description: 'Imported Collection')['data']['id']
10
- end
11
- end
12
- end
13
- end