sync_readme 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,81 @@
1
+ # SyncReadme
2
+
3
+ `sync_readme` is a gem designed to help you synchronize a readme between a repository and a confluence wiki page. The idea is that on merge to master, you can run the sync to take docs FROM the readme and put them in the confluence page.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ``` ruby
10
+ gem 'sync_readme'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install sync_readme
20
+
21
+ Then set up a .sync_readme.yml file
22
+
23
+ ``` yaml
24
+ default: readme # optional if not set, default runs all configurations
25
+
26
+ readme:
27
+ url: http://confluence.url.here # required
28
+ page_id: 123456 # required
29
+ filename: Readme.md # required
30
+ username: foo # optional, generally better as an environment variable
31
+ password: bar # optional, generally better as an environment variable
32
+ notice: this file is sync'd! # optional, adds the notice (as html) to the top of the confluance docs
33
+ strip_title: false # optional, defaults false, strips the first h1 (#) tag from the file
34
+ syntax_highlighting: true # optional, defaults true, uses coderay sytax highlighting on code blocks
35
+ ```
36
+
37
+ You'll also need to set environment variables with credentials to update the page in question:
38
+
39
+ ```
40
+ CONFLUENCE_USERNAME=jsmith
41
+ CONFLUENCE_PASSWORD=$UPER $ECURE PA$$WORD
42
+ ```
43
+
44
+ ## Usage
45
+ ```
46
+ sync_readme [configuration]
47
+ ```
48
+
49
+ ## Adding to Gitlab-CI
50
+
51
+ 1. Create a confluence user specifically to sync with
52
+ 2. If you haven't already, create the pages you want to sync to on confluence and get their IDs.
53
+ 3. Create your `.sync_readme.yml` file like the one above (or see the example)
54
+ 4. Add `gem 'sync_readme'` to your apps gemfile
55
+ 5. Set `CONFLUENCE_USERNAME` and `CONFLUENCE_PASSWORD` as CI Variables.
56
+ 6. Add the following job to your .gitlab-ci.yml
57
+ ``` yaml
58
+ Sync To Confluence:
59
+ stage: update_docs # Replace that with the stage you want this to run
60
+ only: master # Only run on master branch probably after you deploy
61
+ script:
62
+ - bundle exec sync_readme --all # Alternately just the profile you want to run
63
+ ```
64
+
65
+ ## Development
66
+
67
+ Set up a copy of ruby 2.3.1 (We suggest rbenv)
68
+
69
+ `bundle install`
70
+
71
+ ## Running Tests
72
+
73
+ `bundle exec rspec`
74
+
75
+ ## Contributing
76
+
77
+ Contributions are welcome as long as they contain tests for the behaviors added or changed.
78
+
79
+ ## License
80
+
81
+ The gem is available as open source under the terms of the [BSD-3-Clause](http://opensource.org/licenses/BSD-3-Clause).
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'sync_readme'
4
+ SyncReadme.invoke(ARGV)
@@ -0,0 +1,40 @@
1
+ require 'sync_readme/config'
2
+ require 'sync_readme/confluence_sync'
3
+ require 'sync_readme/reader'
4
+ require 'sync_readme/version'
5
+ require 'optparse'
6
+ require 'dotenv'
7
+
8
+ Dotenv.load
9
+
10
+ module SyncReadme
11
+ def self.invoke(args)
12
+ options = {}
13
+ OptionParser.new do |opts|
14
+ opts.banner = "Usage: sync_readme [options] [profile]"
15
+
16
+ opts.on("-a", "--all", "Run verbosely") do
17
+ options[:all] = true
18
+ end
19
+ end.parse!(args)
20
+
21
+ default_profile = SyncReadme::Config.default
22
+
23
+ if options[:all] || (args.empty? && default_profile.nil?)
24
+ SyncReadme::Config.profiles.each do |profile|
25
+ SyncReadme.perform(profile)
26
+ end
27
+ elsif args.empty?
28
+ SyncReadme.perform(default_profile)
29
+ else
30
+ SyncReadme.perform(args.last)
31
+ end
32
+ end
33
+
34
+ def self.perform(profile)
35
+ config = SyncReadme::Config.new(profile)
36
+ content = SyncReadme::Reader.new(config).html
37
+ sync = SyncReadme::ConfluenceSync.new(config)
38
+ sync.update_page_content(content)
39
+ end
40
+ end
@@ -0,0 +1,59 @@
1
+ require 'yaml'
2
+
3
+ module SyncReadme
4
+ class Config
5
+ DEFAULT_CONFIG_FILE = File.join(Dir.pwd, '.sync_readme.yml')
6
+ NO_CONFIGURATION_ERROR = "this profile has not been configured, please add it to #{DEFAULT_CONFIG_FILE}".freeze
7
+
8
+ def self.profiles(config_file = DEFAULT_CONFIG_FILE)
9
+ YAML.load_file(config_file).keys.select { |key| key != 'default' }
10
+ end
11
+
12
+ def self.default(config_file = DEFAULT_CONFIG_FILE)
13
+ default = YAML.load_file(config_file)['default']
14
+ unless default
15
+ profiles = SyncReadme::Config.profiles(config_file)
16
+ return profiles[0] unless profiles.empty? || profiles[1]
17
+ raise NO_CONFIGURATION_ERROR if profiles.empty?
18
+ end
19
+ default
20
+ end
21
+
22
+ def initialize(profile, config_file = DEFAULT_CONFIG_FILE)
23
+ @raw_config = YAML.load_file(config_file)[profile]
24
+ raise NO_CONFIGURATION_ERROR unless @raw_config
25
+ end
26
+
27
+ def url
28
+ @raw_config['url']
29
+ end
30
+
31
+ def username
32
+ ENV['CONFLUENCE_USERNAME'] || @raw_config['username']
33
+ end
34
+
35
+ def notice
36
+ @raw_config['notice']
37
+ end
38
+
39
+ def password
40
+ ENV['CONFLUENCE_PASSWORD'] || @raw_config['password']
41
+ end
42
+
43
+ def page_id
44
+ @raw_config['page_id']
45
+ end
46
+
47
+ def filename
48
+ @raw_config['filename']
49
+ end
50
+
51
+ def strip_title?
52
+ @raw_config['strip_title'].nil? ? false : @raw_config['strip_title']
53
+ end
54
+
55
+ def syntax_highlighting?
56
+ @raw_config['syntax_highlighting'].nil? ? true : @raw_config['syntax_highlighting']
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,55 @@
1
+ require 'json'
2
+ require 'faraday'
3
+
4
+ module SyncReadme
5
+ class ConfluenceSync
6
+ def initialize(config)
7
+ @page_id = config.page_id
8
+ @client = Faraday.new(url: config.url) do |faraday|
9
+ faraday.request :url_encoded
10
+ # faraday.response :logger # log requests to STDOUT
11
+ faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
12
+ faraday.basic_auth(config.username, config.password)
13
+ end
14
+ end
15
+
16
+ def update_page_content(content)
17
+ page = get_page
18
+ update(updated_page_params(page, content))
19
+ end
20
+
21
+ def get_page
22
+ response = @client.get("/rest/api/content/#{@page_id}", expand: 'body.view,version')
23
+ JSON.parse(response.body)
24
+ end
25
+
26
+ def update(params)
27
+ @client.put do |request|
28
+ request.url "/rest/api/content/#{@page_id}"
29
+ request.headers['Content-Type'] = 'application/json'
30
+ request.body = params.to_json
31
+ end
32
+ end
33
+
34
+ def updated_page_params(page, new_content)
35
+ {
36
+ version: {
37
+ number: increment_version(page),
38
+ minorEdit: true
39
+ },
40
+ title: page['title'],
41
+ type: 'page',
42
+ body: {
43
+ storage: {
44
+ value: new_content,
45
+ representation: 'storage'
46
+ }
47
+ }
48
+ }
49
+ end
50
+
51
+ def increment_version(page)
52
+ page['version']['number'] + 1
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,28 @@
1
+ require 'kramdown'
2
+
3
+ module SyncReadme
4
+ class Reader
5
+ def initialize(config)
6
+ @file_contents = File.read(config.filename)
7
+ @notice = config.notice
8
+ @strip_title = config.strip_title?
9
+ @highlighter = config.syntax_highlighting? ? 'coderay' : nil
10
+ end
11
+
12
+ def html
13
+ markdown = @file_contents
14
+ markdown.sub!(/# .*\n/, '') if @strip_title
15
+ options = {
16
+ input: 'GFM',
17
+ syntax_highlighter: @highlighter,
18
+ syntax_highlighter_opts: {
19
+ css: 'style',
20
+ line_numbers: 'table'
21
+ }
22
+ }
23
+ value = Kramdown::Document.new(markdown, options).to_html
24
+ value = "#{@notice}#{value}" if @notice
25
+ value
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module SyncReadme
2
+ VERSION = '1.0.0'.freeze
3
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sync_readme/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'sync_readme'
8
+ spec.version = SyncReadme::VERSION
9
+ spec.authors = ['Alex Ives']
10
+ spec.email = ['alex.ives@govdelivery.com']
11
+
12
+ spec.summary = 'Syncs markdown files with confluence'
13
+ spec.description = 'Converts markdown files and synchronizes them with confluence pages'
14
+ spec.homepage = 'https://github.com/govdelivery/sync_readme'
15
+ spec.license = 'BSD-3-Clause'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = 'exe'
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'faraday', '~> 0.11'
23
+ spec.add_dependency 'kramdown', '~> 1.13'
24
+ spec.add_dependency 'dotenv', '~> 2.1.2'
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.12'
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'rspec', '~> 3.0'
29
+ spec.add_development_dependency 'rubocop', '~> 0.47'
30
+ spec.add_development_dependency 'pry', '~> 0.10.4'
31
+ end
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sync_readme
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Alex Ives
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.11'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: kramdown
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.13'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.13'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dotenv
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 2.1.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 2.1.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.47'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.47'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.10.4
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.10.4
125
+ description: Converts markdown files and synchronizes them with confluence pages
126
+ email:
127
+ - alex.ives@govdelivery.com
128
+ executables:
129
+ - sync_readme
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".gitignore"
134
+ - ".gitlab-ci.yml"
135
+ - ".rspec"
136
+ - ".rubocop.yml"
137
+ - ".ruby-version"
138
+ - ".sync_readme.example.yml"
139
+ - CODE_OF_CONDUCT.md
140
+ - Gemfile
141
+ - LICENSE
142
+ - README.md
143
+ - Rakefile
144
+ - exe/sync_readme
145
+ - lib/sync_readme.rb
146
+ - lib/sync_readme/config.rb
147
+ - lib/sync_readme/confluence_sync.rb
148
+ - lib/sync_readme/reader.rb
149
+ - lib/sync_readme/version.rb
150
+ - sync_readme.gemspec
151
+ homepage: https://github.com/govdelivery/sync_readme
152
+ licenses:
153
+ - BSD-3-Clause
154
+ metadata: {}
155
+ post_install_message:
156
+ rdoc_options: []
157
+ require_paths:
158
+ - lib
159
+ required_ruby_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ requirements: []
170
+ rubyforge_project:
171
+ rubygems_version: 2.5.1
172
+ signing_key:
173
+ specification_version: 4
174
+ summary: Syncs markdown files with confluence
175
+ test_files: []