Skip to content

Commit

Permalink
Add bootcamp syncer
Browse files Browse the repository at this point in the history
  • Loading branch information
iHiD committed Jan 9, 2025
1 parent c2805f1 commit cc79ec2
Show file tree
Hide file tree
Showing 14 changed files with 305 additions and 72 deletions.
53 changes: 53 additions & 0 deletions app/commands/git/sync_bootcamp_content.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
class Git::SyncBootcampContent
include Mandate

queue_as :default

def call
repo.update!

repo.levels.each do |data|
level = Bootcamp::Level.find_or_create_by!(idx: data.idx) do |l|
l.title = data.title
l.description = data.description
l.content_markdown = data.content
end
level.update(
title: data.title,
description: data.description,
content_markdown: data.content
)
rescue StandardError => e
raise if Rails.env.development?

Bugsnag.notify(e)
end

repo.concepts.each do |data|
concept = Bootcamp::Concept.find_or_create_by!(uuid: data.uuid) do |c|
c.slug = data.slug
c.title = data.title
c.description = data.description
c.level_idx = data.level
c.apex = data.apex
end
concept.update(
slug: data.slug,
title: data.title,
description: data.description,
level_idx: data.level,
apex: data.apex
)
rescue StandardError => e
raise if Rails.env.development?

Bugsnag.notify(e)
end
end

private
delegate :head_commit, to: :repo

memoize
def repo = Git::BootcampContent.new
end
40 changes: 40 additions & 0 deletions app/models/git/bootcamp_content.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
class Git::BootcampContent
extend Mandate::Memoize

DEFAULT_REPO_URL = "[email protected]:exercism/bootcamp-content.git".freeze

attr_reader :repo

def self.update! = new.update!

def initialize(repo_url: DEFAULT_REPO_URL, repo: nil)
@repo = repo || Git::Repository.new(repo_url:)
end

def update! = repo.fetch!

memoize
def levels
Git::BootcampContent::Levels.new(repo:)
end

memoize
def projects
project_dir_entries.map do |entry|
Git::BootcampContent::Project.new(entry[:name], repo:)
end
end

memoize
def concepts
Git::BootcampContent::Concepts.new(repo:)
end

private
delegate :head_commit, to: :repo

memoize
def project_dir_entries
repo.fetch_tree(repo.head_commit, "projects").select { |entry| entry[:type] == :tree }
end
end
41 changes: 41 additions & 0 deletions app/models/git/bootcamp_content/concept.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
class Git::BootcampContent::Concept
extend Mandate::Memoize
extend Mandate::InitializerInjector
extend Git::HasGitFilepath

delegate :head_sha, :lookup_commit, :head_commit, to: :repo

attr_reader :config

def initialize(config, repo_url: Git::BootcampContent::DEFAULT_REPO_URL, repo: nil)
@repo = repo || Git::Repository.new(repo_url:)
@config = config
end

memoize
def uuid = config[:uuid]
def slug = config[:slug]
def title = config[:title]
def description = config[:description]
def level = config[:level]
def apex = !!config[:apex]
def content = read_file_blob("#{slug}.md")

private
attr_reader :repo

def absolute_filepath(filepath) = "#{dir}/#{filepath}"

memoize
def commit = repo.lookup_commit(repo.head_sha)

memoize
def absolute_filepaths = filepaths.map { |filepath| absolute_filepath(filepath) }
def filepaths = file_entries.map { |defn| defn[:full] }
def dir = "concepts"

def read_file_blob(filepath)
mapped = file_entries.map { |f| [f[:full], f[:oid]] }.to_h
mapped[filepath] ? repo.read_blob(mapped[filepath]) : nil
end
end
45 changes: 45 additions & 0 deletions app/models/git/bootcamp_content/concepts.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class Git::BootcampContent::Concepts
extend Mandate::Memoize
extend Mandate::InitializerInjector
extend Git::HasGitFilepath

delegate :head_sha, :lookup_commit, :head_commit, to: :repo

git_filepath :config, file: "config.json"

def initialize(repo_url: Git::BootcampContent::DEFAULT_REPO_URL, repo: nil)
@repo = repo || Git::Repository.new(repo_url:)
end

memoize
def concepts
concept_documents.map do |entry|
concept_config = config.find { |config| config[:slug] == File.basename(entry[:name], ".*") }
Git::BootcampContent::Concept.new(
concept_config,
repo:
)
end
end

def each(&block) = concepts.each(&block)

private
delegate :head_commit, to: :repo
attr_reader :repo

memoize
def concept_documents
repo.fetch_tree(repo.head_commit, dir).select { |entry| entry[:type] == :blob && File.extname(entry[:name]) == ".md" }
end

def absolute_filepath(filepath) = "#{dir}/#{filepath}"

memoize
def commit = repo.lookup_commit(repo.head_sha)

memoize
def absolute_filepaths = filepaths.map { |filepath| absolute_filepath(filepath) }
def filepaths = file_entries.map { |defn| defn[:full] }
def dir = "concepts"
end
34 changes: 34 additions & 0 deletions app/models/git/bootcamp_content/level.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
class Git::BootcampContent::Level
extend Mandate::Memoize
extend Mandate::InitializerInjector
extend Git::HasGitFilepath

delegate :head_sha, :lookup_commit, :head_commit, to: :repo

git_filepath :content, file: "content.md"

attr_reader :idx, :config

def initialize(idx, config, repo_url: Git::BootcampContent::DEFAULT_REPO_URL, repo: nil)
@repo = repo || Git::Repository.new(repo_url:)
@idx = idx
@config = config
end

memoize
def title = config[:title]
def description = config[:description]

private
attr_reader :repo

def absolute_filepath(filepath) = "#{dir}/#{filepath}"

memoize
def commit = repo.lookup_commit(repo.head_sha)

memoize
def absolute_filepaths = filepaths.map { |filepath| absolute_filepath(filepath) }
def filepaths = file_entries.map { |defn| defn[:full] }
def dir = "levels/#{idx}"
end
46 changes: 46 additions & 0 deletions app/models/git/bootcamp_content/levels.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
class Git::BootcampContent::Levels
extend Mandate::Memoize
extend Mandate::InitializerInjector
extend Git::HasGitFilepath

delegate :head_sha, :lookup_commit, :head_commit, to: :repo

git_filepath :config, file: "config.json"

def initialize(repo_url: Git::BootcampContent::DEFAULT_REPO_URL, repo: nil)
@repo = repo || Git::Repository.new(repo_url:)
end

memoize
def levels
level_dir_entries.map do |entry|
level_config = config.find { |config| config[:idx] == entry[:name].to_i }
Git::BootcampContent::Level.new(
entry[:name],
level_config,
repo:
)
end
end

def each(&block) = levels.each(&block)

private
delegate :head_commit, to: :repo
attr_reader :repo

memoize
def level_dir_entries
repo.fetch_tree(repo.head_commit, "levels").select { |entry| entry[:type] == :tree }
end

def absolute_filepath(filepath) = "#{dir}/#{filepath}"

memoize
def commit = repo.lookup_commit(repo.head_sha)

memoize
def absolute_filepaths = filepaths.map { |filepath| absolute_filepath(filepath) }
def filepaths = file_entries.map { |defn| defn[:full] }
def dir = "levels"
end
2 changes: 1 addition & 1 deletion app/models/git/problem_specifications/exercise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def file_entries
tree.walk(:preorder).map do |root, entry|
next if entry[:type] == :tree

entry[:full] = "#{root}#{entry[:name]}"
entry[:full] = "#{root}#yentry[:name]}"
entry
end.compact
rescue Rugged::TreeError
Expand Down
34 changes: 0 additions & 34 deletions bootcamp_content/levels/1.md

This file was deleted.

7 changes: 0 additions & 7 deletions bootcamp_content/levels/2.md

This file was deleted.

Empty file removed bootcamp_content/levels/3.md
Empty file.
Empty file removed bootcamp_content/levels/4.md
Empty file.
18 changes: 0 additions & 18 deletions bootcamp_content/levels/config.json

This file was deleted.

14 changes: 14 additions & 0 deletions db/migrate/20250109171959_add_uuids_to_bootcamp.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class AddUuidsToBootcamp < ActiveRecord::Migration[7.0]
def change
return if Rails.env.production?

add_column :bootcamp_concepts, :uuid, :string, null: true
add_column :bootcamp_projects, :uuid, :string, null: true
add_column :bootcamp_exercises, :uuid, :string, null: true

# change_column_null :bootcamp_concepts, :uuid, false
# change_column_null :bootcamp_projects, :uuid, false
# change_column_null :bootcamp_exercises, :uuid, false

end
end
Loading

0 comments on commit cc79ec2

Please sign in to comment.