jekyll-github-pages-gem 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -41,7 +41,7 @@ end
41
41
 
42
42
  module Services
43
43
  ##
44
- # This class contains all operations with interacting with the kramdown engine
44
+ # This class contains operations related to the kramdown engine
45
45
  class KramdownService
46
46
  DEFAULT_HERO = 'https://source.unsplash.com/collection/145103/'
47
47
  ##
@@ -91,75 +91,8 @@ module Services
91
91
  result.compact
92
92
  end
93
93
 
94
- ##
95
- # This method takes parameters for a given post and formats them
96
- # as a valid jekyll post for a Jekyll website
97
- #
98
- # Params:
99
- # +text+:: the markdown contents of the post
100
- # +author+:: the author of the post
101
- # +title+:: the title of the post
102
- # +tags+:: tags specific to the post
103
- # +overlay+:: the overlay color of the post
104
- # +hero+:: a link to an optional background image for a post
105
- def create_jekyll_post_text(text, author, title, tags, overlay, hero)
106
- header_converted_text = fix_header_syntax(text)
107
- header_converted_text = add_line_break_to_markdown_if_necessary(header_converted_text)
108
-
109
- parsed_tags = parse_tags(tags)
110
-
111
- tag_section = %(tags:
112
- #{parsed_tags})
113
-
114
- lead_break_section = "{: .lead}\r\n<!–-break-–>"
115
-
116
- hero_to_use = hero
117
- hero_to_use = DEFAULT_HERO if hero_to_use.empty?
118
- result = %(---
119
- layout: post
120
- title: #{title}
121
- author: #{author}\r\n)
122
-
123
- result += "#{tag_section}\r\n" unless parsed_tags.empty?
124
- result += %(hero: #{hero_to_use}
125
- overlay: #{overlay.downcase}
126
- published: true
127
- ---
128
- #{lead_break_section}
129
- #{header_converted_text})
130
-
131
- result
132
- end
133
-
134
94
  private
135
95
 
136
- def parse_tags(tags)
137
- tag_array = tags.split(',')
138
- result = ''
139
- tag_array.each do |tag|
140
- result += " - #{tag.strip}"
141
- result += "\r\n" if tag != tag_array.last
142
- end
143
- result
144
- end
145
-
146
- def fix_header_syntax(text)
147
- document = Kramdown::Document.new(text)
148
- header_elements = document.root.children.select { |x| x.type == :header }
149
- lines = text.split("\n")
150
- lines = lines.map do |line|
151
- if header_elements.any? { |x| line.include? x.options[:raw_text] }
152
- # This regex matches the line into 2 groups with the first group being the repeating #
153
- # characters and the beginning of the string and the second group being the rest of the string
154
- line_match = line.match(/(#*)(.*)/)
155
- line = "#{line_match.captures.first} #{line_match.captures.last.strip}"
156
- else
157
- line.delete("\r\n")
158
- end
159
- end
160
- lines.join("\r\n")
161
- end
162
-
163
96
  def get_document_descendants(current_element, result)
164
97
  current_element.children.each do |element|
165
98
  result << element
@@ -170,17 +103,5 @@ published: true
170
103
  def get_filename_for_image_tag(image_el)
171
104
  File.basename(image_el.attr['src'])
172
105
  end
173
-
174
- def add_line_break_to_markdown_if_necessary(markdown)
175
- lines = markdown.split("\n")
176
- # The regular expression in the if statement looks for a markdown reference to a link like
177
- # [logo]: https://ieeextreme.org/wp-content/uploads/2019/05/Xtreme_colour-e1557478323964.png
178
- # If a post starts with that reference in jekyll followed by an image using that reference
179
- # the line below will be interperted as a paragraph tag instead of an image tag. To fix that
180
- # we add a line break to the start of the markdown.
181
- return "\r\n#{markdown}" if lines.first&.match?(/\[(.*)\]: (.*)/)
182
-
183
- markdown
184
- end
185
106
  end
186
107
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../factories/page_factory'
4
+
5
+ module Services
6
+ ##
7
+ # This class contains all operations related to pages on a Jekyll website
8
+ class PageService < BaseEditingService
9
+ def initialize(repo_name, access_token)
10
+ super(repo_name, access_token)
11
+ @page_factory = Factories::PageFactory.new
12
+ end
13
+
14
+ ##
15
+ # Returns a given page from a Jekyll website from the default branch unless a pull request body
16
+ # is specified. In that case then it will return the page from the source branch of the first open
17
+ # pull request matching the given body
18
+ #
19
+ # Params:
20
+ # +file_path+:: the path to the file in a GitHub repository
21
+ # +pr_body+:: an optional parameter indicating the pull request body of any updates to a given page, defaults to nil
22
+ def get_markdown_page(file_path, pr_body = nil)
23
+ if pr_body
24
+ open_prs = @github_service.get_open_pull_requests_with_body(pr_body)
25
+ unless open_prs.empty?
26
+ pr_files = @github_service.get_pr_files(open_prs[0][:number])
27
+ markdown_file = pr_files.find { |file| file[:filename].end_with?('.md') }
28
+ if markdown_file
29
+ ref = @github_service.get_ref_from_contents_url(markdown_file[:contents_url])
30
+ text_contents = @github_service.get_text_contents_from_file(file_path, ref)
31
+ return @page_factory.create_page(text_contents, ref, open_prs[0][:html_url])
32
+ end
33
+ end
34
+ end
35
+
36
+ text_contents = @github_service.get_text_contents_from_file(file_path)
37
+ @page_factory.create_page(text_contents, nil, nil)
38
+ end
39
+
40
+ ##
41
+ # Saves a given page update by updating the page contents and creating a pull request into master
42
+ # if a ref is not given. Otherwise if a ref is supplied it will update the branch matching the given ref without creating a pull request.
43
+ #
44
+ # Params:
45
+ # +file_path+:: the path to the file in a GitHub repository
46
+ # +page_title+:: the title of the page
47
+ # +ref+::an optional branch indicating the page should be updated on a branch that's not the default branch, defaults to nil
48
+ # +pr_body+::an optional pull request body when updating the page on the default branch, defaults to an empty string
49
+ # +reviewers+::an optional array of reviewers for opening a pull request when updating the page on the default branch, defaults to no reviewers
50
+ def save_page_update(file_path, page_title, file_contents, ref = nil, pr_body = '', reviewers = [])
51
+ if ref
52
+ ref_name = @github_service.get_ref_name_by_sha(ref)
53
+ sha_base_tree = @github_service.get_base_tree_for_branch(ref)
54
+
55
+ new_tree_sha = create_new_tree(file_contents, page_title, file_path, sha_base_tree)
56
+ @github_service.commit_and_push_to_repo("Edited page #{page_title}", new_tree_sha, ref, ref_name)
57
+ nil
58
+ else
59
+ branch_name = "editPage#{page_title.gsub(/\s+/, '')}"
60
+ ref_name = "heads/#{branch_name}"
61
+
62
+ master_head_sha = @github_service.get_master_head_sha
63
+ sha_base_tree = @github_service.get_base_tree_for_branch(master_head_sha)
64
+
65
+ @github_service.create_ref_if_necessary(ref_name, master_head_sha)
66
+ new_tree_sha = create_new_tree(file_contents, page_title, file_path, sha_base_tree)
67
+
68
+ ref_sha = @github_service.commit_and_push_to_repo("Edited page #{page_title}", new_tree_sha, master_head_sha, ref_name)
69
+ pull_request_url = @github_service.create_pull_request(branch_name, 'master', "Edited page #{page_title}",
70
+ pr_body,
71
+ reviewers)
72
+ create_save_page_update_result(ref_sha, pull_request_url)
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def create_save_page_update_result(ref_sha, pull_request_url)
79
+ result = Page.new
80
+ result.github_ref = ref_sha
81
+ result.pull_request_url = pull_request_url
82
+ result
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../factories/post_factory'
4
+
5
+ module Services
6
+ ##
7
+ # This class contains all operations related to posts on a Jekyll website
8
+ class PostService < BaseEditingService
9
+ def initialize(repo_name, access_token)
10
+ super(repo_name, access_token)
11
+ @post_factory = Factories::PostFactory.new
12
+ @kramdown_service = Services::KramdownService.new
13
+ end
14
+
15
+ ##
16
+ # This method fetches all the markdown contents of all the posts on a Jekyll website
17
+ # that have been written and returns a list of models representing a Post.
18
+ def get_all_posts
19
+ result = []
20
+ api_posts = @github_service.get_contents_from_path('_posts')
21
+ api_posts.each do |api_post|
22
+ post_text_contents = @github_service.get_text_contents_from_file(api_post.path)
23
+ post_model = @post_factory.create_post(post_text_contents, api_post.path, nil)
24
+ image_paths = @kramdown_service.get_all_image_paths(post_model.contents)
25
+
26
+ images = []
27
+ image_paths.each do |image_path|
28
+ image_content = @github_service.get_contents_from_path(image_path)
29
+ images << create_post_image(image_path, image_content.content)
30
+ end
31
+
32
+ post_model.images = images
33
+
34
+ result << post_model
35
+ end
36
+ result
37
+ end
38
+
39
+ ##
40
+ # This method fetches all of the posts that have been written but have not been merged into master yet
41
+ #
42
+ # Params
43
+ # +pr_body+::the pr body for the posts in PR
44
+ def get_all_posts_in_pr(pr_body)
45
+ result = []
46
+ pull_requests = @github_service.get_open_pull_requests_with_body(pr_body)
47
+ pull_requests.each do |pull_request|
48
+ pull_request_files = @github_service.get_pr_files(pull_request[:number])
49
+
50
+ post = nil
51
+ images = []
52
+ pull_request_files.each do |pull_request_file|
53
+ ref = @github_service.get_ref_from_contents_url(pull_request_file[:contents_url])
54
+ pr_file_contents = @github_service.get_contents_from_path(pull_request_file[:filename], ref)
55
+
56
+ if pull_request_file[:filename].end_with?('.md')
57
+ post_text_contents = @github_service.get_text_content_from_file(pr_file_contents.path, ref)
58
+ post = @post_factory.create_post(post_text_contents, pr_file_contents.path, ref)
59
+ result << post
60
+ else
61
+ images << create_post_image(pr_file_contents.path, pr_file_contents.content)
62
+ end
63
+ end
64
+
65
+ post.images = images
66
+ end
67
+ result
68
+ end
69
+
70
+ ##
71
+ # This method fetches a single post from a Jekyll website given a post title
72
+ # and returns a Post model
73
+ #
74
+ # Params:
75
+ # +title+:: A title of a Jekyll website post
76
+ # +ref+::a sha for a ref indicating the head of a branch a post is pushed to on the GitHub server
77
+ def get_post_by_title(title, ref)
78
+ result = nil
79
+ result = get_all_posts_in_pr.find { |x| x.title == title } if ref
80
+ result = get_all_posts.find { |x| x.title == title } unless ref
81
+ result&.images&.each { |x| PostImageManager.instance.add_downloaded_image(x) }
82
+ result
83
+ end
84
+
85
+ ##
86
+ # This method submits a new post to GitHub by checking out a new branch for the post,
87
+ # if the branch already doesn't exist. Commiting and pushing the markdown and any photos
88
+ # attached to the post to the branch. And then finally opening a pull request into master
89
+ # for the new post.
90
+ #
91
+ # Params
92
+ # +oauth_token+::a user's oauth access token
93
+ # +post_markdown+:: the markdown contents of a post
94
+ # +pull_request_body+::an optional pull request body for the post, it will be blank if nothing is provided
95
+ # +reviewers+:: an optional list of reviewers for the post PR
96
+ def create_post(post_markdown, post_title, pull_request_body = '', reviewers = [])
97
+ # This ref_name variable represents the branch name
98
+ # for creating a post. At the end we strip out all of the whitespace in
99
+ # the post_title to create a valid branch name
100
+ branch_name = "createPost#{post_title.gsub(/\s+/, '')}"
101
+ ref_name = "heads/#{branch_name}"
102
+
103
+ master_head_sha = @github_service.get_master_head_sha
104
+ sha_base_tree = @github_service.get_base_tree_for_branch(master_head_sha)
105
+
106
+ @github_service.create_ref_if_necessary(ref_name, master_head_sha)
107
+
108
+ new_post_path = create_new_filepath_for_post(post_title)
109
+ new_tree_sha = create_new_tree(post_markdown, post_title, new_post_path, sha_base_tree)
110
+
111
+ @github_service.commit_and_push_to_repo("Created post #{post_title}",
112
+ new_tree_sha, master_head_sha, ref_name)
113
+ @github_service.create_pull_request(branch_name, 'master', "Created Post #{post_title}",
114
+ pull_request_body,
115
+ reviewers)
116
+
117
+ PostImageManager.instance.clear
118
+ end
119
+
120
+ ##
121
+ # This method submits changes to an existing post to GitHub by checking out a new branch for the post,
122
+ # if the branch already doesn't exist. Commiting and pushing the markdown changes and any added photos
123
+ # for the existing post to the branch. And the finally opening a pull request into master for the new post.
124
+ #
125
+ # Params
126
+ # +post_markdown+::the modified markdown to submit
127
+ # +post_title+::the title for the existing post
128
+ # +existing_post_file_path+::the file path to the existing post on GitHub
129
+ # +pull_request_body+::an optional pull request body for the post, it will be blank if nothing is provided
130
+ # +reviewers+:: an optional list of reviewers for the post PR
131
+ def edit_post(post_markdown, post_title, existing_post_file_path, pull_request_body = '', reviewers = [])
132
+ # This ref_name variable represents the branch name
133
+ # for editing a post. At the end we strip out all of the whitespace in
134
+ # the post_title to create a valid branch name
135
+ branch_name = "editPost#{post_title.gsub(/\s+/, '')}"
136
+ ref_name = "heads/#{branch_name}"
137
+
138
+ master_head_sha = @github_service.get_master_head_sha
139
+ sha_base_tree = @github_service.get_base_tree_for_branch(master_head_sha)
140
+
141
+ @github_service.create_ref_if_necessary(ref_name, master_head_sha)
142
+ new_tree_sha = create_new_tree(post_markdown, post_title, existing_post_file_path, sha_base_tree)
143
+
144
+ @github_service.commit_and_push_to_repo("Edited post #{post_title}", new_tree_sha, master_head_sha, ref_name)
145
+ @github_service.create_pull_request(branch_name, 'master', "Edited Post #{post_title}",
146
+ pull_request_body,
147
+ reviewers)
148
+
149
+ PostImageManager.instance.clear
150
+ end
151
+
152
+ ##
153
+ # This method submits changes to a post that is already in PR, commiting and pushing the markdown changes
154
+ # and any added photos to the branch. Since the post is in PR these changes will be a PR updated to the given branch
155
+ #
156
+ # Params:
157
+ # +post_markdown+::the modified markdown to submit
158
+ # +post_title+::the title for the existing post
159
+ # +existing_post_file_path+::the file path to the existing post on GitHub
160
+ # +ref+::the ref to update
161
+ def edit_post_in_pr(post_markdown, post_title, existing_post_file_path, ref)
162
+ ref_name = @github_service.get_ref_name_by_sha(ref)
163
+ sha_base_tree = @github_service.get_base_tree_for_branch(ref)
164
+
165
+ new_tree_sha = create_new_tree(post_markdown, post_title, existing_post_file_path, sha_base_tree)
166
+ @github_service.commit_and_push_to_repo("Edited post #{post_title}", new_tree_sha, ref, ref_name)
167
+
168
+ PostImageManager.instance.clear
169
+ end
170
+
171
+ private
172
+
173
+ def create_new_filepath_for_post(post_title)
174
+ "_posts/#{DateTime.now.strftime('%Y-%m-%d')}-#{post_title.gsub(/\s+/, '')}.md"
175
+ end
176
+
177
+ def create_post_image(filename, contents)
178
+ result = PostImage.new
179
+ result.filename = filename
180
+ result.contents = contents
181
+ result
182
+ end
183
+ end
184
+ end
metadata CHANGED
@@ -1,15 +1,63 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-github-pages-gem
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - MSOE SSE Web Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-31 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2020-08-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: carrierwave
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.0.rc
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '3.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 2.0.0.rc
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: kramdown
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 2.3.0
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 2.3.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: octokit
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '4.18'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '4.18'
13
61
  description:
14
62
  email:
15
63
  executables: []
@@ -21,16 +69,18 @@ files:
21
69
  - README.md
22
70
  - Rakefile
23
71
  - jekyll_github_pages.gemspec
72
+ - lib/factories/base_factory.rb
73
+ - lib/factories/page_factory.rb
24
74
  - lib/factories/post_factory.rb
25
75
  - lib/jekyll_github_pages.rb
76
+ - lib/models/page.rb
26
77
  - lib/models/post.rb
27
78
  - lib/models/post_image_manager.rb
79
+ - lib/services/base_editing_service.rb
28
80
  - lib/services/github_service.rb
29
81
  - lib/services/kramdown_service.rb
30
- - lib/services/post_services/base_post_service.rb
31
- - lib/services/post_services/post_creation_service.rb
32
- - lib/services/post_services/post_editing_service.rb
33
- - lib/services/post_services/post_pull_request_editing_service.rb
82
+ - lib/services/page_service.rb
83
+ - lib/services/post_service.rb
34
84
  - lib/uploaders/post_image_uploader.rb
35
85
  homepage:
36
86
  licenses:
@@ -44,7 +94,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
44
94
  requirements:
45
95
  - - ">="
46
96
  - !ruby/object:Gem::Version
47
- version: '0'
97
+ version: 2.5.1
48
98
  required_rubygems_version: !ruby/object:Gem::Requirement
49
99
  requirements:
50
100
  - - ">="