github-to-canvas 0.0.9 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +46 -10
- data/bin/github-to-canvas +7 -11
- data/lib/github-to-canvas.rb +14 -3
- data/lib/github-to-canvas/canvas_dotfile.rb +93 -0
- data/lib/github-to-canvas/canvas_interface.rb +50 -0
- data/lib/github-to-canvas/create_canvas_lesson.rb +26 -0
- data/lib/github-to-canvas/github_interface.rb +42 -0
- data/lib/github-to-canvas/repository_converter.rb +55 -0
- data/lib/github-to-canvas/update_canvas_lesson.rb +24 -0
- data/lib/github-to-canvas/version.rb +2 -2
- metadata +7 -2
- data/lib/github-to-canvas/create-canvas-lesson.rb +0 -156
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98f8ae0d915a1a0812d6b4777358098785861ffd4117bdc4836e86a2a8301aad
|
4
|
+
data.tar.gz: a50127f7f2f5281e3eaf736fdc37097c8de795b4b2bfb7532cf1a97db113d816
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d067f9cfcf558b43bafc5c304ed806c7529d8de179148a84030982c39681d973e3dda04333db5dce52928a9faf13946ae63d152bf6ca8d194397d0d3ffbdfde9
|
7
|
+
data.tar.gz: f78da19c7dee06b800e78bde25bff91a582e5bbbc611b2f016b30836ada9b9dcb7ad90c5bbaaeb51335360033c06a973ce20fb5471696d79559c6524bb0be2bf
|
data/README.md
CHANGED
@@ -8,11 +8,13 @@ file, convert it to HTML, and push it to Canvas. The gem also updates the
|
|
8
8
|
repository to include a `.canvas` file containing Canvas specific information.
|
9
9
|
|
10
10
|
With the `.canvas` file in place, this gem can be used to continuously align
|
11
|
-
content between GitHub and Canvas
|
11
|
+
content between GitHub and Canvas using the GitHub repository as the single
|
12
|
+
source of truth.
|
12
13
|
|
13
14
|
This gem is built for use internally at [Flatiron School][]. Access to the
|
14
15
|
[Canvas LMS API][] and the ability to add pages and assignments to a Canvas
|
15
|
-
course are required.
|
16
|
+
course are required. Write access to the GitHub repository being converted is
|
17
|
+
also required.
|
16
18
|
|
17
19
|
## Installation
|
18
20
|
|
@@ -29,7 +31,7 @@ called `CANVAS_API_KEY`. Use the following command to add your new key to
|
|
29
31
|
`~/.zshrc`:
|
30
32
|
|
31
33
|
```sh
|
32
|
-
echo "$(
|
34
|
+
echo "$(export 'CANVAS_API_KEY=<your-new-API-key-here>' | cat - ~/.zshrc)" > ~/.zshrc
|
33
35
|
```
|
34
36
|
|
35
37
|
> **Note:** The command above assumes you are using Zsh. Change the dotfile if
|
@@ -42,7 +44,7 @@ Flatiron School's base path is `https://learning.flatironschool.com/api/v1`. Add
|
|
42
44
|
as an `ENV` variable like the API key. **Do not add a `/` at the end after `/api/v1`.**
|
43
45
|
|
44
46
|
```sh
|
45
|
-
echo "$(
|
47
|
+
echo "$(export 'CANVAS_API_PATH=<your-base-api-path>' | cat - ~/.zshrc)" > ~/.zshrc
|
46
48
|
```
|
47
49
|
|
48
50
|
After both the API key and path are added to `~/.zshrc`, run `source ~/.zshrc`
|
@@ -51,11 +53,17 @@ are present by running `ENV`.
|
|
51
53
|
|
52
54
|
## Usage
|
53
55
|
|
54
|
-
|
55
|
-
Canvas course id you are going to add to. This id can be found in the URL of the course.
|
56
|
+
### Create a Canvas Lesson
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
To create a Canvas lesson from a GitHub `README.md` file, at minimum, you will
|
59
|
+
need to know the Canvas course id you are going to add to. This id can be found
|
60
|
+
in the URL of the course.
|
61
|
+
|
62
|
+
Once you have the course id, you will need to do the following:
|
63
|
+
|
64
|
+
1. Clone down the repository you'd like to push to Canvas.
|
65
|
+
2. Change directory into the new local repository
|
66
|
+
3. Run `github-to-canvas --create <your-course-id>` from inside the local repo
|
59
67
|
|
60
68
|
If everything is set up properly, `github-to-canvas` will create a Canvas lesson
|
61
69
|
using `master` branch `README.md` and the name of the current folder. By
|
@@ -63,8 +71,30 @@ default, if the repository contains folders, an **assignment** will be created.
|
|
63
71
|
Otherwise, a **page** will be created.
|
64
72
|
|
65
73
|
After a successful lesson creation, `github-to-canvas` will use the API response
|
66
|
-
to build a `.canvas` YAML file. This file contains the course id, the newly
|
67
|
-
page id, and the Canvas URL to the lesson for future reference.
|
74
|
+
to build a `.canvas` YAML file. This file contains the course id, the newly
|
75
|
+
created page id, and the Canvas URL to the lesson for future reference. With the
|
76
|
+
newly created `.canvas` file, `github-to-canvas` will attempt to commit and push the
|
77
|
+
file up to the remote GitHub repository.
|
78
|
+
|
79
|
+
If you create multiple Canvas lessons from the same repository, each lesson's
|
80
|
+
Canvas data will be stored in the `.canvas` file.
|
81
|
+
|
82
|
+
> **Note:** If you don't have write access to the repository, the `.canvas` file
|
83
|
+
> will still be created locally.
|
84
|
+
|
85
|
+
### Update an existing Canvas Lesson
|
86
|
+
|
87
|
+
To update an existing Canvas lesson using a local repository, **a `.canvas` file
|
88
|
+
must be present in the repo**, as it contains the lesson information for the
|
89
|
+
Canvas API.
|
90
|
+
|
91
|
+
1. Clone down and/or change directory into the repository you'd like to update
|
92
|
+
2. Run `github-to-canvas --align <your-course-id>` from inside the local repo
|
93
|
+
|
94
|
+
`github-to-canvas` will get the course id and page/assignment id from the
|
95
|
+
`.canvas` file and update the associated Canvas lesson. If there are multiple
|
96
|
+
Canvas lessons included in the `.canvas` file, each lesson will be updated (i.e.
|
97
|
+
you have the same lesson in two courses created from one repository).
|
68
98
|
|
69
99
|
### Options
|
70
100
|
|
@@ -76,5 +106,11 @@ You can override the default behaviors with the following arguments:
|
|
76
106
|
appropriate Canvas lesson type instead of relying on the repository's
|
77
107
|
directory structure
|
78
108
|
|
109
|
+

|
110
|
+
|
111
|
+
<p align="center">
|
112
|
+
<img src="https://curriculum-content.s3.amazonaws.com/fewpjs/fewpjs-fetch-lab/Image_25_AsynchronousJavaScript.png" width="500">
|
113
|
+
</p>
|
114
|
+
|
79
115
|
[Canvas LMS API]: https://canvas.instructure.com/doc/api/index.html
|
80
116
|
[Flatiron School]: https://flatironschool.com/
|
data/bin/github-to-canvas
CHANGED
@@ -17,8 +17,8 @@ OptionParser.new do |opts|
|
|
17
17
|
github-to-canvas --create COURSE [--branch BRANCH]
|
18
18
|
github-to-canvas --create COURSE [--branch BRANCH] [--name NAME]
|
19
19
|
github-to-canvas --create COURSE [--branch BRANCH] [--name NAME] [--type TYPE]
|
20
|
+
github-to-canvas --create COURSE [--dry-run]
|
20
21
|
github-to-canvas --align
|
21
|
-
github-to-canvas --reverse-align
|
22
22
|
github-to-canvas --version
|
23
23
|
|
24
24
|
Run these commands from inside a local GitHub repository. This gem is built for Flatiron School's internal use.
|
@@ -59,14 +59,14 @@ OptionParser.new do |opts|
|
|
59
59
|
"Updates a canvas lesson based on the local repository's README.md") do |a|
|
60
60
|
options[:align] = true
|
61
61
|
end
|
62
|
-
opts.on("-r", "--reverse-align",
|
63
|
-
"Updates a remote repository, converting the Canvas lesson body to markdown and pushing it remotely as the README.md") do |r|
|
64
|
-
options[:reverse_align] = true
|
65
|
-
end
|
66
62
|
opts.on("-v", "--version",
|
67
63
|
"Displays current gem version") do |v|
|
68
64
|
options[:version] = true
|
69
65
|
end
|
66
|
+
opts.on("-d", "--dry-run",
|
67
|
+
"Runs through creation without pushing to Canvas or GitHub") do |v|
|
68
|
+
options[:dry] = true
|
69
|
+
end
|
70
70
|
|
71
71
|
end.parse!
|
72
72
|
|
@@ -89,13 +89,9 @@ if !options[:name]
|
|
89
89
|
end
|
90
90
|
|
91
91
|
if options[:create]
|
92
|
-
GithubToCanvas.new(mode: "create", course: options[:course], filepath: Dir.pwd, branch: options[:branch], name: options[:name], type: options[:type])
|
92
|
+
GithubToCanvas.new(mode: "create", course: options[:course], filepath: Dir.pwd, branch: options[:branch], name: options[:name], type: options[:type], dry: !!options[:dry])
|
93
93
|
end
|
94
94
|
|
95
95
|
if options[:align]
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
if options[:reverse_align]
|
100
|
-
puts 'feature not working yet'
|
96
|
+
GithubToCanvas.new(mode: "align", course: nil, filepath: Dir.pwd, branch: options[:branch], name: options[:name], type: options[:type], dry: !!options[:dry])
|
101
97
|
end
|
data/lib/github-to-canvas.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
-
require_relative './github-to-canvas/
|
1
|
+
require_relative './github-to-canvas/create_canvas_lesson'
|
2
|
+
require_relative './github-to-canvas/update_canvas_lesson'
|
3
|
+
require_relative './github-to-canvas/repository_converter'
|
4
|
+
require_relative './github-to-canvas/github_interface'
|
5
|
+
require_relative './github-to-canvas/canvas_interface'
|
6
|
+
require_relative './github-to-canvas/canvas_dotfile'
|
2
7
|
require_relative './github-to-canvas/version'
|
3
8
|
|
9
|
+
|
4
10
|
class GithubToCanvas
|
5
11
|
|
6
|
-
def initialize(mode:, course:, filepath:Dir.pwd, branch:'master', name:File.basename(Dir.getwd), type:"page")
|
12
|
+
def initialize(mode:, course:, filepath:Dir.pwd, branch:'master', name:File.basename(Dir.getwd), type:"page", dry:false)
|
7
13
|
if mode == 'version'
|
8
14
|
puts VERSION
|
9
15
|
return
|
@@ -11,7 +17,12 @@ class GithubToCanvas
|
|
11
17
|
|
12
18
|
if mode == 'create'
|
13
19
|
puts "github-to-canvas will now create a Canvas lesson based on the current repo"
|
14
|
-
CreateCanvasLesson.new(course, filepath, branch, name, type)
|
20
|
+
CreateCanvasLesson.new(course, filepath, branch, name, type, dry)
|
21
|
+
end
|
22
|
+
|
23
|
+
if mode == 'align'
|
24
|
+
puts "github-to-canvas will now align any existing Canvas lessons based on the current repo. NOTE: .canvas file must be present"
|
25
|
+
UpdateCanvasLesson.new(filepath, branch, name, type, dry)
|
15
26
|
end
|
16
27
|
end
|
17
28
|
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
class CanvasDotfile
|
4
|
+
|
5
|
+
def self.update_or_create(filepath, response, course, type)
|
6
|
+
if File.file?(".canvas")
|
7
|
+
if type == "assignment"
|
8
|
+
canvas_data = self.update_assignment_data(response, course, type)
|
9
|
+
else
|
10
|
+
canvas_data = self.update_page_data(response, course, type)
|
11
|
+
end
|
12
|
+
else
|
13
|
+
if type == "assignment"
|
14
|
+
canvas_data = self.create_assignment_data(response, course, type)
|
15
|
+
else
|
16
|
+
canvas_data = self.create_page_data(response, course, type)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
self.create_canvas_dotfile(filepath, canvas_data)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.create_canvas_dotfile(filepath, canvas_data)
|
23
|
+
File.write("#{filepath}/.canvas", canvas_data.to_yaml)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.commit_canvas_dotfile(filepath)
|
27
|
+
GithubInterface.git_add(filepath, '.canvas')
|
28
|
+
GithubInterface.git_commit(filepath, 'AUTO: add .canvas file after migration')
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.read_canvas_data
|
32
|
+
if File.file?(".canvas")
|
33
|
+
YAML.load(File.read(".canvas"))
|
34
|
+
else
|
35
|
+
puts 'ERROR: Align functionalty requires .canvas file to be present'
|
36
|
+
abort
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.update_assignment_data(response, course, type)
|
41
|
+
canvas_data = YAML.load(File.read(".canvas"))
|
42
|
+
if canvas_data[:lessons].none? { |lesson| lesson[:id] == response['id'] && lesson[:course_id] == course.to_i && lesson[:canvas_url] == response['html_url']}
|
43
|
+
lesson_data = {
|
44
|
+
id: response['id'],
|
45
|
+
course_id: course.to_i,
|
46
|
+
canvas_url: response['html_url'],
|
47
|
+
type: type
|
48
|
+
}
|
49
|
+
canvas_data[:lessons] << lesson_data
|
50
|
+
end
|
51
|
+
canvas_data
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.create_assignment_data(response, course, type)
|
55
|
+
{
|
56
|
+
lessons: [
|
57
|
+
{
|
58
|
+
id: response['id'],
|
59
|
+
course_id: course.to_i,
|
60
|
+
canvas_url: response['html_url'],
|
61
|
+
type: type
|
62
|
+
}
|
63
|
+
]
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.update_page_data(response, course, type)
|
68
|
+
canvas_data = YAML.load(File.read(".canvas"))
|
69
|
+
if canvas_data[:lessons].none? { |lesson| lesson[:page_id] == response['page_id'] && lesson[:course_id] == course.to_i && lesson[:canvas_url] == response['html_url']}
|
70
|
+
lesson_data = {
|
71
|
+
id: response['page_id'],
|
72
|
+
course_id: course.to_i,
|
73
|
+
canvas_url: response['html_url'],
|
74
|
+
type: type
|
75
|
+
}
|
76
|
+
canvas_data[:lessons] << lesson_data
|
77
|
+
end
|
78
|
+
canvas_data
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.create_page_data(response, course, type)
|
82
|
+
{
|
83
|
+
lessons: [
|
84
|
+
{
|
85
|
+
id: response['page_id'],
|
86
|
+
course_id: course.to_i,
|
87
|
+
canvas_url: response['html_url'],
|
88
|
+
type: type
|
89
|
+
}
|
90
|
+
]
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'rest-client'
|
3
|
+
|
4
|
+
class CanvasInterface
|
5
|
+
|
6
|
+
def self.submit_to_canvas(course_id, type, name, readme, dry_run = false)
|
7
|
+
if dry_run
|
8
|
+
puts 'DRY RUN: Skipping push to Canvas'
|
9
|
+
else
|
10
|
+
response = self.push_to_canvas(course_id, type, name, readme)
|
11
|
+
if ![200, 201].include? response.code
|
12
|
+
puts "Canvas push failed. #{response.code} status code returned "
|
13
|
+
abort
|
14
|
+
end
|
15
|
+
JSON.parse(response.body)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.push_to_canvas(course_id, type, name, new_readme)
|
20
|
+
url = "#{ENV['CANVAS_API_PATH']}/courses/#{course_id}/#{type}s"
|
21
|
+
payload = self.build_payload(type, name, new_readme)
|
22
|
+
|
23
|
+
RestClient.post(url, payload, headers={
|
24
|
+
"Authorization" => "Bearer #{ENV['CANVAS_API_KEY']}"
|
25
|
+
})
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.update_existing_lesson(course_id, id, type, name, new_readme, dry_run)
|
29
|
+
url = "#{ENV['CANVAS_API_PATH']}/courses/#{course_id}/#{type}s/#{id}"
|
30
|
+
payload = self.build_payload(type, name, new_readme)
|
31
|
+
RestClient.put(url, payload, headers={
|
32
|
+
"Authorization" => "Bearer #{ENV['CANVAS_API_KEY']}"
|
33
|
+
})
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.build_payload(type, name, new_readme)
|
37
|
+
if type == "assignment"
|
38
|
+
payload = {
|
39
|
+
'assignment[name]' => name,
|
40
|
+
'assignment[description]' => new_readme
|
41
|
+
}
|
42
|
+
else
|
43
|
+
payload = {
|
44
|
+
'wiki_page[title]' => name,
|
45
|
+
'wiki_page[body]' => new_readme,
|
46
|
+
'wiki_page[editing_roles]' => "teachers"
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class CreateCanvasLesson
|
2
|
+
|
3
|
+
def initialize(course, filepath, branch, name, type, dry_run)
|
4
|
+
name = name.split(/[- _]/).map(&:capitalize).join(' ')
|
5
|
+
original_readme = File.read("#{filepath}/README.md")
|
6
|
+
if !original_readme
|
7
|
+
puts 'README.md not found in current directory. Exiting...'
|
8
|
+
abort
|
9
|
+
end
|
10
|
+
create_canvas_lesson(original_readme, course, filepath, branch, name, type, dry_run)
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_canvas_lesson(readme, course, filepath, branch, name, type, dry_run)
|
14
|
+
GithubInterface.get_updated_repo(filepath, branch)
|
15
|
+
new_readme = RepositoryConverter.convert(filepath, readme, branch)
|
16
|
+
response = CanvasInterface.submit_to_canvas(course, type, name, new_readme, dry_run)
|
17
|
+
if dry_run
|
18
|
+
puts 'DRY RUN: Skipping dotfile creation and push to GitHub'
|
19
|
+
else
|
20
|
+
CanvasDotfile.update_or_create(filepath, response, course, type)
|
21
|
+
CanvasDotfile.commit_canvas_dotfile(filepath)
|
22
|
+
GithubInterface.git_push(filepath, branch)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
class GithubInterface
|
3
|
+
|
4
|
+
def self.get_updated_repo(filepath, branch)
|
5
|
+
self.git_co_branch(filepath, branch)
|
6
|
+
self.git_pull(filepath, branch)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.cd_into_and(filepath, command)
|
10
|
+
cmd = "cd #{filepath} && #{command}"
|
11
|
+
puts cmd
|
12
|
+
`#{cmd}`
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.git_co_branch(filepath, branch)
|
16
|
+
branch = self.cd_into_and(filepath, "git checkout #{branch}")
|
17
|
+
if branch.to_s.strip.empty?
|
18
|
+
puts "#{branch} branch not found. Exiting..."
|
19
|
+
abort
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.git_pull(filepath, branch)
|
24
|
+
self.cd_into_and(filepath, "git pull origin #{branch}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.git_remote(filepath)
|
28
|
+
self.cd_into_and(filepath, "git config --get remote.origin.url")
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.git_add(filepath, file)
|
32
|
+
self.cd_into_and(filepath, "git add #{file}")
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.git_commit(filepath, message)
|
36
|
+
self.cd_into_and(filepath, "git commit -m '#{message}'")
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.git_push(filepath, branch)
|
40
|
+
self.cd_into_and(filepath, "git push origin #{branch}")
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'redcarpet'
|
2
|
+
|
3
|
+
class RepositoryConverter
|
4
|
+
|
5
|
+
def self.convert(filepath, readme, branch)
|
6
|
+
self.fix_local_images(filepath, readme, branch)
|
7
|
+
self.convert_to_html(filepath, readme)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.fix_local_images(filepath, readme, branch)
|
11
|
+
raw_remote_url = self.set_raw_image_remote_url(filepath)
|
12
|
+
self.adjust_local_markdown_images(readme, raw_remote_url, branch)
|
13
|
+
self.adjust_local_html_images(readme, raw_remote_url)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.set_raw_image_remote_url(filepath)
|
17
|
+
remote = GithubInterface.git_remote(filepath)
|
18
|
+
remote.gsub!("git@github.com:","https://raw.githubusercontent.com/")
|
19
|
+
remote.gsub!(/.git$/,"")
|
20
|
+
remote.strip!
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.adjust_local_markdown_images(readme, raw_remote_url, branch)
|
24
|
+
readme.gsub!(/\!\[.+\]\(.+\)/) {|image|
|
25
|
+
if !image.match('amazonaws.com') && !image.match('https://') && !image.match('youtube')
|
26
|
+
image.gsub!(/\(.+\)/) { |path|
|
27
|
+
path.delete_prefix!("(")
|
28
|
+
path.delete_suffix!(")")
|
29
|
+
"(" + remote + "/#{branch}/" + path + ")"
|
30
|
+
}
|
31
|
+
end
|
32
|
+
image
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.adjust_local_html_images(readme, raw_remote_url)
|
37
|
+
readme.gsub!(/src=\"[\s\S]*?" /) { |img|
|
38
|
+
if !img.match('amazonaws.com') && !img.match('https://') && !img.match('youtube')
|
39
|
+
img.gsub!(/\"/, "")
|
40
|
+
img.gsub!(/src=/, '')
|
41
|
+
img.strip!
|
42
|
+
'src="' + raw_remote_url + '/master/' + img + '"'
|
43
|
+
else
|
44
|
+
img
|
45
|
+
end
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.convert_to_html(filepath, readme)
|
50
|
+
redcarpet = Redcarpet::Markdown.new(Redcarpet::Render::HTML, options={tables: true, autolink: true, fenced_code_blocks: true})
|
51
|
+
# File.write("#{filepath}/README.html", redcarpet.render(readme))
|
52
|
+
redcarpet.render(readme)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class UpdateCanvasLesson
|
2
|
+
|
3
|
+
def initialize(filepath, branch, name, type, dry_run)
|
4
|
+
name = name.split(/[- _]/).map(&:capitalize).join(' ')
|
5
|
+
readme = File.read("#{filepath}/README.md")
|
6
|
+
if !readme
|
7
|
+
puts 'README.md not found in current directory. Exiting...'
|
8
|
+
abort
|
9
|
+
end
|
10
|
+
update_canvas_lesson(readme, filepath, branch, name, type, dry_run)
|
11
|
+
end
|
12
|
+
|
13
|
+
def update_canvas_lesson(readme, filepath, branch, name, type, dry_run)
|
14
|
+
GithubInterface.get_updated_repo(filepath, branch)
|
15
|
+
new_readme = RepositoryConverter.convert(filepath, readme, branch)
|
16
|
+
canvas_data = CanvasDotfile.read_canvas_data
|
17
|
+
canvas_data[:lessons].each { |lesson|
|
18
|
+
CanvasInterface.update_existing_lesson(lesson[:course_id], lesson[:id], type, name, new_readme, dry_run)
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
end
|
@@ -1,3 +1,3 @@
|
|
1
|
-
class
|
2
|
-
VERSION = "0.0.
|
1
|
+
class GithubToCanvas
|
2
|
+
VERSION = "0.0.15"
|
3
3
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: github-to-canvas
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- maxwellbenton
|
@@ -80,7 +80,12 @@ files:
|
|
80
80
|
- Rakefile
|
81
81
|
- bin/github-to-canvas
|
82
82
|
- lib/github-to-canvas.rb
|
83
|
-
- lib/github-to-canvas/
|
83
|
+
- lib/github-to-canvas/canvas_dotfile.rb
|
84
|
+
- lib/github-to-canvas/canvas_interface.rb
|
85
|
+
- lib/github-to-canvas/create_canvas_lesson.rb
|
86
|
+
- lib/github-to-canvas/github_interface.rb
|
87
|
+
- lib/github-to-canvas/repository_converter.rb
|
88
|
+
- lib/github-to-canvas/update_canvas_lesson.rb
|
84
89
|
- lib/github-to-canvas/version.rb
|
85
90
|
homepage: https://github.com/learn-co-curriculum/github-to-canvas
|
86
91
|
licenses:
|
@@ -1,156 +0,0 @@
|
|
1
|
-
require 'redcarpet'
|
2
|
-
require 'rest-client'
|
3
|
-
require 'json'
|
4
|
-
require 'yaml'
|
5
|
-
require 'byebug'
|
6
|
-
|
7
|
-
class CreateCanvasLesson
|
8
|
-
|
9
|
-
def initialize(course, filepath, branch, name, type)
|
10
|
-
@course = course
|
11
|
-
@filepath = filepath
|
12
|
-
@branch = branch
|
13
|
-
@name = name.split(/[ -]/).map(&:capitalize).join(' ')
|
14
|
-
@type = type
|
15
|
-
@renderer = Redcarpet::Markdown.new(Redcarpet::Render::HTML, options={tables: true, autolink: true, fenced_code_blocks: true})
|
16
|
-
@original_readme = File.read("#{filepath}/README.md")
|
17
|
-
if !@original_readme
|
18
|
-
puts 'README.md not found in current directory. Exiting...'
|
19
|
-
abort
|
20
|
-
end
|
21
|
-
create_canvas_lesson
|
22
|
-
end
|
23
|
-
|
24
|
-
def create_canvas_lesson
|
25
|
-
git_co_branch
|
26
|
-
git_pull
|
27
|
-
@raw_remote_url = set_raw_image_remote_url
|
28
|
-
adjust_local_markdown_images
|
29
|
-
adjust_local_html_images
|
30
|
-
@new_readme = @renderer.render(@original_readme)
|
31
|
-
write_to_html
|
32
|
-
@response = push_to_canvas
|
33
|
-
if @response.code != 200
|
34
|
-
puts "Canvas push failed. #{@response.code} status code returned "
|
35
|
-
end
|
36
|
-
@response = JSON.parse(@response.body)
|
37
|
-
create_canvas_dotfile
|
38
|
-
commit_canvas_dotfile
|
39
|
-
git_push
|
40
|
-
end
|
41
|
-
|
42
|
-
def cd_into_and(command)
|
43
|
-
cmd = "cd #{@filepath} && #{command}"
|
44
|
-
puts cmd
|
45
|
-
`#{cmd}`
|
46
|
-
end
|
47
|
-
|
48
|
-
def git_co_branch
|
49
|
-
cmd = "git co #{@branch}"
|
50
|
-
branch = cd_into_and(cmd)
|
51
|
-
if branch.to_s.strip.empty?
|
52
|
-
puts "#{b@ranch} branch not found. Exiting..."
|
53
|
-
abort
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def git_pull
|
58
|
-
if @branch != 'master'
|
59
|
-
cmd = "git pull #{@branch}"
|
60
|
-
else
|
61
|
-
cmd = "git pull"
|
62
|
-
end
|
63
|
-
puts "git pulling latest version of #{@branch}"
|
64
|
-
cd_into_and(cmd)
|
65
|
-
end
|
66
|
-
|
67
|
-
def git_remote
|
68
|
-
cmd = "git config --get remote.origin.url"
|
69
|
-
cd_into_and(cmd)
|
70
|
-
end
|
71
|
-
|
72
|
-
def git_add(file)
|
73
|
-
cmd = "git add #{file}"
|
74
|
-
puts "git adding #{file}"
|
75
|
-
cd_into_and(cmd)
|
76
|
-
end
|
77
|
-
|
78
|
-
def git_commit(message)
|
79
|
-
cmd = "git commit -m '#{message}'"
|
80
|
-
puts "git commit: '#{message}'"
|
81
|
-
cd_into_and(cmd)
|
82
|
-
end
|
83
|
-
|
84
|
-
def git_push
|
85
|
-
cmd = "git push"
|
86
|
-
puts "git pushing #{@branch}"
|
87
|
-
cd_into_and(cmd)
|
88
|
-
end
|
89
|
-
|
90
|
-
def set_raw_image_remote_url
|
91
|
-
remote = git_remote
|
92
|
-
remote.gsub!("git@github.com:","https://raw.githubusercontent.com/")
|
93
|
-
remote.gsub!(/.git$/,"")
|
94
|
-
remote.strip!
|
95
|
-
end
|
96
|
-
|
97
|
-
def adjust_local_markdown_images
|
98
|
-
@original_readme.gsub!(/\!\[.+\]\(.+\)/) {|image|
|
99
|
-
if !image.match('amazonaws.com') && !image.match('https://')
|
100
|
-
image.gsub!(/\(.+\)/) { |path|
|
101
|
-
path.delete_prefix!("(")
|
102
|
-
path.delete_suffix!(")")
|
103
|
-
"(" + remote + "/#{@branch}/" + path + ")"
|
104
|
-
}
|
105
|
-
end
|
106
|
-
image
|
107
|
-
}
|
108
|
-
end
|
109
|
-
|
110
|
-
def adjust_local_html_images
|
111
|
-
@original_readme.gsub!(/src=\"[\s\S]*?" /) { |img|
|
112
|
-
img.gsub!(/\"/, "")
|
113
|
-
img.gsub!(/src=/, '')
|
114
|
-
img.strip!
|
115
|
-
'src="' + @raw_remote_url + '/master/' + img + '"'
|
116
|
-
}
|
117
|
-
end
|
118
|
-
|
119
|
-
def write_to_html
|
120
|
-
File.write("#{@filepath}/README.html", @new_readme)
|
121
|
-
end
|
122
|
-
|
123
|
-
def push_to_canvas
|
124
|
-
url = "#{ENV['CANVAS_API_PATH']}/courses/#{@course}/#{@type}s"
|
125
|
-
if @type == "assignment"
|
126
|
-
payload = {
|
127
|
-
'assignment[name]' => @name,
|
128
|
-
'assignment[description]' => @new_readme
|
129
|
-
}
|
130
|
-
else
|
131
|
-
payload = {
|
132
|
-
'wiki_page[title]' => @name,
|
133
|
-
'wiki_page[body]' => @new_readme,
|
134
|
-
'wiki_page[editing_roles]' => "teachers"
|
135
|
-
}
|
136
|
-
end
|
137
|
-
|
138
|
-
RestClient.post(url, payload, headers={
|
139
|
-
"Authorization" => "Bearer #{ENV['CANVAS_API_KEY']}"
|
140
|
-
})
|
141
|
-
end
|
142
|
-
|
143
|
-
def create_canvas_dotfile
|
144
|
-
canvas_data = {
|
145
|
-
page_id: @response['page_id'],
|
146
|
-
course_id: @course.to_i,
|
147
|
-
canvas_url: @response['html_url']
|
148
|
-
}
|
149
|
-
File.write("#{@filepath}/.canvas", canvas_data.to_yaml)
|
150
|
-
end
|
151
|
-
|
152
|
-
def commit_canvas_dotfile
|
153
|
-
git_add('.canvas')
|
154
|
-
git_commit('AUTO: add .canvas file after migration')
|
155
|
-
end
|
156
|
-
end
|