From faf2d2c216273b7eed29eac641f7fec030cb90c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 22:24:38 +0000 Subject: [PATCH 01/17] Bump actions/checkout from 4.1.0 to 4.1.1 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.0 to 4.1.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.1.0...v4.1.1) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/build-docker.yml | 4 ++-- .github/workflows/test.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 1512058..292c239 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 - name: Run tests run: | @@ -62,7 +62,7 @@ jobs: status: STARTING color: warning - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 - name: Set up QEMU uses: docker/setup-qemu-action@v3.0.0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8dd8b06..463d085 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 - name: Run tests run: | From 8bc8bb2c8ac5117e8699ff43aea69d8118b3c108 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 22:44:48 +0000 Subject: [PATCH 02/17] Bump docker/build-push-action from 5.0.0 to 5.1.0 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.0.0 to 5.1.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v5.0.0...v5.1.0) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 1512058..c6d2997 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -108,7 +108,7 @@ jobs: echo "::set-output name=tag_list::${TAG_LIST}" - name: Build and push - uses: docker/build-push-action@v5.0.0 + uses: docker/build-push-action@v5.1.0 with: context: . platforms: linux/amd64,linux/arm64 From 0097f7a21f48f1424be6b4c3ec9043c0225c9f5a Mon Sep 17 00:00:00 2001 From: Kapil Sachdev Date: Thu, 28 Dec 2023 14:12:13 +0530 Subject: [PATCH 03/17] WEB-6625: Add free attribute to Lesson --- app/lib/parser/lesson_metadata.rb | 2 +- app/models/lesson.rb | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/lib/parser/lesson_metadata.rb b/app/lib/parser/lesson_metadata.rb index 76f8550..190bd23 100644 --- a/app/lib/parser/lesson_metadata.rb +++ b/app/lib/parser/lesson_metadata.rb @@ -5,7 +5,7 @@ module Parser class LessonMetadata include SimpleAttributes - VALID_SIMPLE_ATTRIBUTES = %i[title description_md learning_objectives_md ordinal ref].freeze + VALID_SIMPLE_ATTRIBUTES = %i[title description_md learning_objectives_md ordinal ref free].freeze attr_accessor :lesson, :metadata diff --git a/app/models/lesson.rb b/app/models/lesson.rb index 323838c..7f5499d 100644 --- a/app/models/lesson.rb +++ b/app/models/lesson.rb @@ -7,7 +7,7 @@ class Lesson include Concerns::ImageAttachable include Concerns::MarkdownRenderable - attr_accessor :title, :description_md, :ordinal, :ref, :segments, :learning_objectives_md + attr_accessor :title, :description_md, :ordinal, :ref, :segments, :learning_objectives_md, :free attr_markdown :description, source: :description_md, file: false attr_markdown :learning_objectives, source: :learning_objectives_md, file: false @@ -15,6 +15,7 @@ class Lesson def initialize(attributes = {}) super + @free ||= false @segments ||= [] end @@ -24,7 +25,7 @@ def slug # Used for serialisation def attributes - { title: nil, description: nil, learning_objectives: nil, ordinal: nil, segments: [], ref: nil }.stringify_keys + { title: nil, description: nil, learning_objectives: nil, ordinal: nil, segments: [], ref: nil, free: false }.stringify_keys end # Used for linting From 44eef2964ba34b07959a65e7845ea5ff7f9075a5 Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Mon, 8 Jan 2024 20:49:37 +0700 Subject: [PATCH 04/17] WEB-6754: Fixing images in local preview --- app/server/local_image_provider.rb | 12 ++++++++---- app/server/robles_book_server.rb | 2 +- app/server/robles_content_module_server.rb | 9 +++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/app/server/local_image_provider.rb b/app/server/local_image_provider.rb index 79e8e50..46f26b8 100644 --- a/app/server/local_image_provider.rb +++ b/app/server/local_image_provider.rb @@ -2,14 +2,14 @@ # An implementation of an image provider suitable for use in the server class LocalImageProvider - attr_reader :chapter + attr_reader :container - def initialize(chapter:) - @chapter = chapter + def initialize(container:) + @container = container end def process - image_paths = extract_images_from_markdown(chapter.markdown_file) + image_paths = extract_images_from_markdown(container.markdown_file) @images = extract(image_paths) end @@ -29,4 +29,8 @@ def extract(image_paths) def extract_images_from_markdown(file) ImageProvider::MarkdownImageExtractor.images_from(file) end + + def width_required + false + end end diff --git a/app/server/robles_book_server.rb b/app/server/robles_book_server.rb index 1a95c4b..f0758d0 100644 --- a/app/server/robles_book_server.rb +++ b/app/server/robles_book_server.rb @@ -89,7 +89,7 @@ def chapter_for_slug(slug) end def render_chapter(chapter) - image_provider = LocalImageProvider.new(chapter:) + image_provider = LocalImageProvider.new(container: chapter) image_provider.process renderer = Renderer::Chapter.new(chapter, image_provider:) renderer.render diff --git a/app/server/robles_content_module_server.rb b/app/server/robles_content_module_server.rb index df9c8e3..7183d2e 100644 --- a/app/server/robles_content_module_server.rb +++ b/app/server/robles_content_module_server.rb @@ -95,6 +95,8 @@ def scss(template, options = {}, locals = {}) segment = segment_for_slug(lesson, params[:slug]) raise Sinatra::NotFound unless segment.present? + render_text(segment) + erb :'content_modules/text.html', locals: { segment:, @@ -126,6 +128,13 @@ def content_module(with_transcript: true) content_module end + def render_text(text) + image_provider = LocalImageProvider.new(container: text) + image_provider.process + renderer = Renderer::Segment.create(text, image_provider:) + renderer.render + end + def render_string(content) Renderer::MarkdownStringRenderer.new(content:).render end From e52f375a128bede00179de7505c958ca37d108c0 Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Tue, 9 Jan 2024 08:38:01 +0700 Subject: [PATCH 05/17] WEB-6755: Upgrading to ruby 3.3 --- .rubocop.yml | 2 +- .ruby-version | 2 +- Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 0432ca9..453a8af 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,5 @@ AllCops: - TargetRubyVersion: 3.2 + TargetRubyVersion: 3.3 NewCops: enable Exclude: - tmp/**/* diff --git a/.ruby-version b/.ruby-version index 944880f..15a2799 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.2.0 +3.3.0 diff --git a/Dockerfile b/Dockerfile index 8467a7f..5d5f8e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.2-alpine +FROM ruby:3.3-alpine LABEL maintainer=engineering@kodeco.com LABEL com.github.actions.name="robles" From dcb39bdd9e7b037465ed85619c4b518fa5ca3712 Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Tue, 9 Jan 2024 08:38:19 +0700 Subject: [PATCH 06/17] WEB-6755: Upgrading gems --- Gemfile.lock | 86 +++++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ad4060b..38c4005 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -14,9 +14,9 @@ GIT GEM remote: https://rubygems.org/ specs: - activemodel (7.1.1) - activesupport (= 7.1.1) - activesupport (7.1.1) + activemodel (7.1.2) + activesupport (= 7.1.2) + activesupport (7.1.2) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -26,44 +26,45 @@ GEM minitest (>= 5.1) mutex_m tzinfo (~> 2.0) - addressable (2.8.5) + addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) ast (2.4.2) - aws-eventstream (1.2.0) - aws-partitions (1.835.0) - aws-sdk-core (3.185.1) - aws-eventstream (~> 1, >= 1.0.2) + aws-eventstream (1.3.0) + aws-partitions (1.877.0) + aws-sdk-core (3.190.1) + aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.5) + aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.72.0) - aws-sdk-core (~> 3, >= 3.184.0) + aws-sdk-kms (1.76.0) + aws-sdk-core (~> 3, >= 3.188.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.136.0) - aws-sdk-core (~> 3, >= 3.181.0) + aws-sdk-s3 (1.142.0) + aws-sdk-core (~> 3, >= 3.189.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.6) - aws-sigv4 (1.6.0) + aws-sigv4 (~> 1.8) + aws-sigv4 (1.8.0) aws-eventstream (~> 1, >= 1.0.2) backport (1.2.0) - base64 (0.1.1) - benchmark (0.2.1) - bigdecimal (3.1.4) + base64 (0.2.0) + benchmark (0.3.0) + bigdecimal (3.1.5) cli-ui (2.2.3) coderay (1.1.3) - commonmarker (0.23.10) + commonmarker (1.0.4) + rb_sys (~> 0.9) concurrent-ruby (1.2.2) connection_pool (2.4.1) daemons (1.4.1) diff-lcs (1.5.0) - drb (2.1.1) + drb (2.2.0) ruby2_keywords e2mmap (0.1.0) em-websocket (0.5.3) eventmachine (>= 0.12.9) http_parser.rb (~> 0) eventmachine (1.2.7) - faraday (2.7.11) + faraday (2.8.1) base64 faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) @@ -77,7 +78,7 @@ GEM websocket-driver (>= 0.6, < 0.8) ffi (1.16.3) formatador (1.1.0) - git (1.18.0) + git (1.19.0) addressable (~> 2.8) rchardet (~> 1.8) google-protobuf (3.22.0) @@ -101,7 +102,7 @@ GEM concurrent-ruby (~> 1.0) jaro_winkler (1.5.6) jmespath (1.6.2) - json (2.6.3) + json (2.7.1) kramdown (2.4.0) rexml kramdown-parser-gfm (1.1.0) @@ -110,17 +111,17 @@ GEM listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - lumberjack (1.2.9) + lumberjack (1.2.10) method_source (1.0.0) mini_magick (4.12.0) - mini_portile2 (2.8.4) + mini_portile2 (2.8.5) minitest (5.20.0) multi_json (1.15.0) mustermann (3.0.0) ruby2_keywords (~> 0.0.1) - mutex_m (0.1.2) + mutex_m (0.2.0) nenv (0.3.0) - nokogiri (1.15.4) + nokogiri (1.16.0) mini_portile2 (~> 2.8.2) racc (~> 1.4) notiffany (0.1.3) @@ -129,37 +130,38 @@ GEM octokit (7.2.0) faraday (>= 1, < 3) sawyer (~> 0.9) - parallel (1.23.0) - parser (3.2.2.4) + parallel (1.24.0) + parser (3.3.0.2) ast (~> 2.4.1) racc pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) - public_suffix (5.0.3) - racc (1.7.1) + public_suffix (5.0.4) + racc (1.7.3) rack (2.2.8) rack-livereload (0.5.1) rack - rack-protection (3.1.0) + rack-protection (3.2.0) + base64 (>= 0.1.0) rack (~> 2.2, >= 2.2.4) rack-test (2.1.0) rack (>= 1.3) rainbow (3.1.1) - rake (13.0.6) + rake (13.1.0) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) + rb_sys (0.9.86) rbnacl (7.1.1) ffi rbs (2.8.4) rchardet (1.8.0) - regexp_parser (2.8.2) + regexp_parser (2.9.0) reverse_markdown (2.1.1) nokogiri rexml (3.2.6) - rubocop (1.57.1) - base64 (~> 0.1.1) + rubocop (1.59.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -167,10 +169,10 @@ GEM rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.28.1, < 2.0) + rubocop-ast (>= 1.30.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.29.0) + rubocop-ast (1.30.0) parser (>= 3.2.1.0) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) @@ -181,13 +183,13 @@ GEM addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) shellany (0.0.1) - sinatra (3.1.0) + sinatra (3.2.0) mustermann (~> 3.0) rack (~> 2.2, >= 2.2.4) - rack-protection (= 3.1.0) + rack-protection (= 3.2.0) tilt (~> 2.0) slack-notifier (2.4.0) - solargraph (0.49.0) + solargraph (0.50.0) backport (~> 1.2) benchmark bundler (~> 2.0) @@ -207,7 +209,7 @@ GEM daemons (~> 1.0, >= 1.0.9) eventmachine (~> 1.0, >= 1.0.4) rack (>= 1, < 3) - thor (1.2.2) + thor (1.3.0) tilt (2.3.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) From 91c362fade033bb71711629aa0e2dada727be67e Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Tue, 9 Jan 2024 08:38:36 +0700 Subject: [PATCH 07/17] WEB-6755: Upgrading bundler --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 38c4005..1aacdf3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -255,4 +255,4 @@ DEPENDENCIES zeitwerk (~> 2.3) BUNDLED WITH - 2.4.20 + 2.5.4 From b6447f6e4b360dc6e7cf6120e1ff1927fcb78090 Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Tue, 9 Jan 2024 08:43:45 +0700 Subject: [PATCH 08/17] WEB-6755: Rubocop fixes --- app/commands/content_module_cli.rb | 14 -------------- app/commands/video_cli.rb | 2 +- app/lib/linting/book_linter.rb | 2 +- app/lib/linting/content_module_linter.rb | 2 +- app/lib/linting/metadata/captions_file.rb | 15 ++++++++------- app/lib/linting/vend_linter.rb | 2 +- app/lib/linting/video_course_linter.rb | 2 +- app/lib/parser/content_module.rb | 2 +- app/lib/renderer/rw_markdown_renderer.rb | 2 +- app/lib/sinatra/pablo.rb | 2 +- app/models/concerns/image_attachable.rb | 2 +- app/models/concerns/markdown_renderable.rb | 2 +- app/server/robles_content_module_server.rb | 2 +- app/server/robles_video_server.rb | 4 ++-- 14 files changed, 21 insertions(+), 34 deletions(-) diff --git a/app/commands/content_module_cli.rb b/app/commands/content_module_cli.rb index 75926e8..46f6fe3 100644 --- a/app/commands/content_module_cli.rb +++ b/app/commands/content_module_cli.rb @@ -55,20 +55,6 @@ def slides snapshotter.generate end - - desc 'serve', 'starts local preview server' - option :dev, type: :boolean, desc: 'Run in development mode (watch robles files, not module files)' - def serve - fork do - if options[:dev] - Guard.start(no_interactions: true) - else - Guard.start(guardfile_contents: content_module_guardfile, watchdir: './', no_interactions: true) - end - end - RoblesContentModuleServer.run! - end - desc 'secrets [REPO]', 'configures a module repo with the necessary secrets' long_desc <<-LONGDESC `robles module secrets [REPO]` will upload the secrets requires to run robles on a diff --git a/app/commands/video_cli.rb b/app/commands/video_cli.rb index 495e6d1..7352ed8 100644 --- a/app/commands/video_cli.rb +++ b/app/commands/video_cli.rb @@ -6,7 +6,7 @@ class VideoCli < Thor option :'release-file', type: :string, desc: 'Location of the release.yaml file' option :local, type: :boolean def render - video_course = runner.render_video_course(release_file: options['release_file'], local: options['local']) + runner.render_video_course(release_file: options['release_file'], local: options['local']) end desc 'serve', 'starts local preview server' diff --git a/app/lib/linting/book_linter.rb b/app/lib/linting/book_linter.rb index 87cba65..96bfed9 100644 --- a/app/lib/linting/book_linter.rb +++ b/app/lib/linting/book_linter.rb @@ -117,7 +117,7 @@ def book parser.parse end rescue Parser::Error => e - line_number = (e.message.match(/at line (\d+)/)&.captures&.first&.to_i || 0) + 1 + line_number = e.message.match(/at line (\d+)/)&.captures&.first.to_i + 1 annotations.push( Annotation.new( absolute_path: e.file, diff --git a/app/lib/linting/content_module_linter.rb b/app/lib/linting/content_module_linter.rb index 8c96176..ec6e411 100644 --- a/app/lib/linting/content_module_linter.rb +++ b/app/lib/linting/content_module_linter.rb @@ -109,7 +109,7 @@ def content_module parser.parse end rescue Parser::Error => e - line_number = (e.message.match(/at line (\d+)/)&.captures&.first&.to_i || 0) + 1 + line_number = e.message.match(/at line (\d+)/)&.captures&.first.to_i + 1 annotations.push( Annotation.new( absolute_path: e.file, diff --git a/app/lib/linting/metadata/captions_file.rb b/app/lib/linting/metadata/captions_file.rb index a527aa2..7e05fed 100644 --- a/app/lib/linting/metadata/captions_file.rb +++ b/app/lib/linting/metadata/captions_file.rb @@ -40,13 +40,14 @@ def video_course_captions def module_captions caption_files = ModuleFile.new(file:, attributes:).file_path_list caption_files.map do |file| - captions_file = if yaml?(file) - load_yaml(File.read(file)).deep_symbolize_keys[:captions_file] - else - @markdown_metadata = nil - @path = file - markdown_metadata[:captions_file] - end + captions_file = + if yaml?(file) + load_yaml(File.read(file)).deep_symbolize_keys[:captions_file] + else + @markdown_metadata = nil + @path = file + markdown_metadata[:captions_file] + end next unless captions_file.present? [captions_file, file] diff --git a/app/lib/linting/vend_linter.rb b/app/lib/linting/vend_linter.rb index 531eb44..5615945 100644 --- a/app/lib/linting/vend_linter.rb +++ b/app/lib/linting/vend_linter.rb @@ -104,7 +104,7 @@ def load_file parser.parse end rescue Parser::Error => e - line_number = (e.message.match(/at line (\d+)/)&.captures&.first&.to_i || 0) + 1 + line_number = e.message.match(/at line (\d+)/)&.captures&.first.to_i + 1 @annotations.push( Annotation.new( absolute_path: e.file, diff --git a/app/lib/linting/video_course_linter.rb b/app/lib/linting/video_course_linter.rb index 37a7503..5b46b17 100644 --- a/app/lib/linting/video_course_linter.rb +++ b/app/lib/linting/video_course_linter.rb @@ -109,7 +109,7 @@ def video_course parser.parse end rescue Parser::Error => e - line_number = (e.message.match(/at line (\d+)/)&.captures&.first&.to_i || 0) + 1 + line_number = e.message.match(/at line (\d+)/)&.captures&.first.to_i + 1 annotations.push( Annotation.new( absolute_path: e.file, diff --git a/app/lib/parser/content_module.rb b/app/lib/parser/content_module.rb index c9166df..a9ecb9c 100644 --- a/app/lib/parser/content_module.rb +++ b/app/lib/parser/content_module.rb @@ -47,7 +47,7 @@ def parse_segments(segment_yaml_file) lesson[:segments].map do |segment| segment_path = "#{lesson_path}/#{segment[:path]}" - send("parse_#{segment[:type]}".to_sym, segment_path) + send(:"parse_#{segment[:type]}", segment_path) end end diff --git a/app/lib/renderer/rw_markdown_renderer.rb b/app/lib/renderer/rw_markdown_renderer.rb index 9e147a0..71807d7 100644 --- a/app/lib/renderer/rw_markdown_renderer.rb +++ b/app/lib/renderer/rw_markdown_renderer.rb @@ -15,7 +15,7 @@ def initialize(image_provider:, root_path:, options: :DEFAULT, extensions: []) @root_path = root_path end - def image(node) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity + def image(node) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity return super(node) if image_provider.blank? title = node.title.present? ? escape_html(node.title) : '' diff --git a/app/lib/sinatra/pablo.rb b/app/lib/sinatra/pablo.rb index 3224b70..3f9c372 100644 --- a/app/lib/sinatra/pablo.rb +++ b/app/lib/sinatra/pablo.rb @@ -58,7 +58,7 @@ def save_path(path:, dir:, response:) [^/.]+ \. ( - #{app.settings.export_extensions.join("|")} + #{app.settings.export_extensions.join('|')} ) $}x file_path = Pathname(File.join(dir, path)) diff --git a/app/models/concerns/image_attachable.rb b/app/models/concerns/image_attachable.rb index 338822a..76141ec 100644 --- a/app/models/concerns/image_attachable.rb +++ b/app/models/concerns/image_attachable.rb @@ -48,7 +48,7 @@ def image_attachment_loop(&block) representations = block.call(local_url) .filter { |r| attribute[:variants].include?(r.variant) } .uniq(&:variant) - send("#{attribute[:destination]}=".to_sym, representations) + send(:"#{attribute[:destination]}=", representations) end end end diff --git a/app/models/concerns/markdown_renderable.rb b/app/models/concerns/markdown_renderable.rb index 3c31f50..dd92611 100644 --- a/app/models/concerns/markdown_renderable.rb +++ b/app/models/concerns/markdown_renderable.rb @@ -32,7 +32,7 @@ def markdown_render_loop(&block) rendered = block.call(content, attribute[:file], vtt_file) rendered = wrap_render(rendered, attribute[:wrapper_class]) - send("#{attribute[:destination]}=".to_sym, rendered) + send(:"#{attribute[:destination]}=", rendered) end end diff --git a/app/server/robles_content_module_server.rb b/app/server/robles_content_module_server.rb index 7183d2e..60459e3 100644 --- a/app/server/robles_content_module_server.rb +++ b/app/server/robles_content_module_server.rb @@ -3,7 +3,7 @@ require 'rack-livereload' # A local preview server for robles -class RoblesContentModuleServer < Sinatra::Application +class RoblesContentModuleServer < Sinatra::Application # rubocop:disable Metrics/ClassLength set :bind, '0.0.0.0' set :views, "#{__dir__}/views" set :public_folder, "#{__dir__}/public" diff --git a/app/server/robles_video_server.rb b/app/server/robles_video_server.rb index 76a6d49..f5e9e59 100644 --- a/app/server/robles_video_server.rb +++ b/app/server/robles_video_server.rb @@ -3,7 +3,7 @@ require 'rack-livereload' # A local preview server for robles -class RoblesVideoServer < Sinatra::Application # rubocop:disable Metrics/ClassLength +class RoblesVideoServer < Sinatra::Application set :bind, '0.0.0.0' set :views, "#{__dir__}/views" set :public_folder, "#{__dir__}/public" @@ -11,7 +11,7 @@ class RoblesVideoServer < Sinatra::Application # rubocop:disable Metrics/ClassLe use Rack::LiveReload, host: 'localhost', source: :vendored - helpers do # rubocop:disable Metrics/BlockLength + helpers do def slide_path(episode) "/slides/#{episode.slug}" end From f575ea6deec5f23501cfadad9a172b76878cfc8f Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Tue, 9 Jan 2024 10:03:02 +0700 Subject: [PATCH 09/17] WEB-6755: Making it multi-stage build docker file --- Dockerfile | 59 ++++++++++++++++++++++++++++++++++++++++------ docker-compose.yml | 7 +++++- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5d5f8e1..dea4631 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,7 @@ -FROM ruby:3.3-alpine -LABEL maintainer=engineering@kodeco.com +ARG RUBY_ENV -LABEL com.github.actions.name="robles" -LABEL com.github.actions.author="Kodeco " -LABEL com.github.actions.description="Content publication for kodeco.com" -LABEL com.github.actions.color="purple" -LABEL com.github.actions.icon="book" +FROM ruby:3.2-alpine AS builder +LABEL maintainer=engineering@kodeco.com ARG APP_ROOT=/app/robles ARG BUILD_PACKAGES="build-base git" @@ -41,3 +37,52 @@ RUN bundle install --jobs 20 --retry 5 # Copy the main application. COPY . ./ + +# Remove extra files +RUN rm -rf /usr/local/bundle/cache/* + + +############################## +# PACKAGE STAGE # +############################## +FROM ruby:3.2-alpine +LABEL maintainer=engineering@kodeco.com +LABEL com.github.actions.name="robles" +LABEL com.github.actions.author="Kodeco " +LABEL com.github.actions.description="Content publication for kodeco.com" +LABEL com.github.actions.color="purple" +LABEL com.github.actions.icon="book" + +ARG APP_ROOT=/app/robles +ARG RUBY_ENV=${RUBY_ENV:-production} + +ENV RUBY_ENV=${RUBY_ENV} + +ARG RUNTIME_PACKAGES="imagemagick git tzdata" +ARG TEST_AND_DEV_PACKAGES="bash build-base libsodium-dev" + +# SYSLOG TO STDOUT +RUN \ + touch /var/log/syslog && \ + ln -sf /proc/1/fd/1 /var/log/syslog + +# libsodium +COPY --from=builder /usr/lib/libsodium.so* /usr/lib/ +# Copy the app from builder +COPY --from=builder $APP_ROOT $APP_ROOT +COPY --from=builder /usr/local/bundle /usr/local/bundle + +# Set the working directory +WORKDIR $APP_ROOT + +# For runtime +RUN apk update \ + && apk upgrade \ + && apk add --update --no-cache $RUNTIME_PACKAGES \ + && rm -rf /var/cache/apk/* + +# Test and dev packages +RUN if [ "$RUBY_ENV" == "test" -o "$RUBY_ENV" == "development" ]; then \ + apk add --update --no-cache $TEST_AND_DEV_PACKAGES \ + && rm -rf /var/cache/apk/*; \ + fi diff --git a/docker-compose.yml b/docker-compose.yml index eddded9..f265bf1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,11 @@ version: '3.7' services: app: - build: . + build: + context: . + dockerfile: Dockerfile + args: + - RUBY_ENV=development volumes: - .:/app/robles # When working on videos @@ -16,6 +20,7 @@ services: env_file: .env environment: - IMAGES_CDN_HOST=assets.robles.kodeco.com + - RUBY_ENV=development ports: - "4567:4567" - "35729:35729" From 516d081268d2010955aa9dc2ab71ca9c3f78c04c Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Tue, 9 Jan 2024 10:03:16 +0700 Subject: [PATCH 10/17] WEB-6755: Have to lock commonmarker to get it to work on musl --- Gemfile | 2 +- Gemfile.lock | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 272f28c..4a7641c 100644 --- a/Gemfile +++ b/Gemfile @@ -13,7 +13,7 @@ gem 'cli-ui', '~> 2' gem 'thor', '~> 1.0', '>= 1.0.1' # Markdown processing -gem 'commonmarker' +gem 'commonmarker', '< 1' # HTTP Client gem 'faraday', '~> 2' diff --git a/Gemfile.lock b/Gemfile.lock index 1aacdf3..34f7fbf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -51,8 +51,7 @@ GEM bigdecimal (3.1.5) cli-ui (2.2.3) coderay (1.1.3) - commonmarker (1.0.4) - rb_sys (~> 0.9) + commonmarker (0.23.10) concurrent-ruby (1.2.2) connection_pool (2.4.1) daemons (1.4.1) @@ -152,7 +151,6 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - rb_sys (0.9.86) rbnacl (7.1.1) ffi rbs (2.8.4) @@ -229,7 +227,7 @@ DEPENDENCIES activesupport (< 7.2) aws-sdk-s3 (~> 1.64) cli-ui (~> 2) - commonmarker + commonmarker (< 1) concurrent-ruby (~> 1.1) faraday (~> 2) faraday-retry From 62d55f3f93c10e12e9b9750cb1872acf390dbe7d Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Tue, 9 Jan 2024 10:03:33 +0700 Subject: [PATCH 11/17] WEB-6755: There is better checking now... --- app/commands/video_cli.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/commands/video_cli.rb b/app/commands/video_cli.rb index 7352ed8..ae3b991 100644 --- a/app/commands/video_cli.rb +++ b/app/commands/video_cli.rb @@ -39,8 +39,8 @@ def upload desc 'lint [RELEASE_FILE]', 'runs a selection of linters on the video course' option :'release-file', type: :string, desc: 'Location of the release.yaml file' - method_option 'without-version': :boolean, aliases: '-e', default: false, desc: 'Run linting without git branch naming check' - method_option silent: :boolean, aliases: '-s', default: false, desc: 'Hide all output' + method_option :'without-version', type: :boolean, aliases: '-e', default: false, desc: 'Run linting without git branch naming check' + method_option :silent, type: :boolean, aliases: '-s', default: false, desc: 'Hide all output' def lint output = runner.lint_video_course(release_file: options['publish_file'], options:) exit 1 unless output.validated || ENVIRONMENT == 'staging' From db591df4b25520ece19455f69ac9ca967a6704ad Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Tue, 9 Jan 2024 10:06:03 +0700 Subject: [PATCH 12/17] WEB-6755: Adding a comment explaining the pinning --- Gemfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Gemfile b/Gemfile index 4a7641c..63f86cb 100644 --- a/Gemfile +++ b/Gemfile @@ -13,6 +13,8 @@ gem 'cli-ui', '~> 2' gem 'thor', '~> 1.0', '>= 1.0.1' # Markdown processing +# >= 1 switches out the underlying library to one that does not support musl +# Currently, there are no plans to support it, so let's lock to < 1 gem 'commonmarker', '< 1' # HTTP Client From 1dfca5aa672b1e2a4d9b67dd049b394418aaddaa Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Tue, 9 Jan 2024 15:10:35 +0700 Subject: [PATCH 13/17] WEB-6755: Missed dropping some places back to ruby 3.2 --- .rubocop.yml | 2 +- .ruby-version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 453a8af..0432ca9 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,5 @@ AllCops: - TargetRubyVersion: 3.3 + TargetRubyVersion: 3.2 NewCops: enable Exclude: - tmp/**/* diff --git a/.ruby-version b/.ruby-version index 15a2799..944880f 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.3.0 +3.2.0 From 5bb4d43a4c347f4bcad390b171690eae1364572e Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Wed, 10 Jan 2024 11:19:06 +0700 Subject: [PATCH 14/17] WEB-6757: Checking for image existence in content modules --- app/lib/linting/content_module_linter.rb | 4 +++ app/lib/linting/image/content_module.rb | 23 ++++++++++++++ app/lib/linting/image/lesson.rb | 23 ++++++++++++++ app/lib/linting/image/markdown.rb | 7 +++-- app/lib/linting/image/segment.rb | 38 ++++++++++++++++++++++++ app/lib/linting/image_linter.rb | 11 ++++--- 6 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 app/lib/linting/image/content_module.rb create mode 100644 app/lib/linting/image/lesson.rb create mode 100644 app/lib/linting/image/segment.rb diff --git a/app/lib/linting/content_module_linter.rb b/app/lib/linting/content_module_linter.rb index ec6e411..6f14a67 100644 --- a/app/lib/linting/content_module_linter.rb +++ b/app/lib/linting/content_module_linter.rb @@ -42,6 +42,10 @@ def lint_with_ui(options:, show_ui: true) # rubocop:disable Metrics/AbcSize end return unless annotations.blank? + with_spinner(title: 'Validating image references', show: show_ui) do + annotations.concat(Linting::ImageLinter.new(content_module:).lint) + end + with_spinner(title: 'Validating data models', show: show_ui) do annotations.concat(Linting::Validations::ContentModule.new(content_module:, file:).lint) end diff --git a/app/lib/linting/image/content_module.rb b/app/lib/linting/image/content_module.rb new file mode 100644 index 0000000..1654531 --- /dev/null +++ b/app/lib/linting/image/content_module.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Linting + module Image + # Lint the images associated with a content module + class ContentModule + include Linting::Image::Attachable + + def self.lint(content_module) + new(content_module).lint + end + + def lint + [].tap do |annotations| + annotations.concat(lint_attachments) + object.lessons.each do |lesson| + annotations.concat(Linting::Image::Lesson.lint(lesson)) + end + end + end + end + end +end diff --git a/app/lib/linting/image/lesson.rb b/app/lib/linting/image/lesson.rb new file mode 100644 index 0000000..b5ee585 --- /dev/null +++ b/app/lib/linting/image/lesson.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Linting + module Image + # Lint the image associated with a lesson + class Lesson + include Linting::Image::Attachable + + def self.lint(lesson) + new(lesson).lint + end + + def lint + [].tap do |annotations| + annotations.concat(lint_attachments) + object.segments.each do |segment| + annotations.concat(Linting::Image::Segment.lint(segment)) + end + end + end + end + end +end diff --git a/app/lib/linting/image/markdown.rb b/app/lib/linting/image/markdown.rb index aee9541..7cfd5a2 100644 --- a/app/lib/linting/image/markdown.rb +++ b/app/lib/linting/image/markdown.rb @@ -8,8 +8,11 @@ module Markdown attr_reader :markdown_file - def lint_markdown_images - _md_generate_annotations(_md_non_existent_images, :non_existent) + _md_generate_annotations(_md_images_missing_width, :missing_width) + def lint_markdown_images(check_width: true) + annotations = _md_generate_annotations(_md_non_existent_images, :non_existent) + return annotations unless check_width + + annotations + _md_generate_annotations(_md_images_missing_width, :missing_width) end private diff --git a/app/lib/linting/image/segment.rb b/app/lib/linting/image/segment.rb new file mode 100644 index 0000000..eb21016 --- /dev/null +++ b/app/lib/linting/image/segment.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Linting + module Image + # Lint the images associated with a segment + class Segment + include Linting::Image::Attachable + include Linting::Image::Markdown + + def self.lint(segment) + new(segment).lint + end + + def lint + [].tap do |annotations| + annotations.concat(lint_attachments) if object.class < Concerns::ImageAttachable + annotations.concat(lint_markdown_images(check_width: false)) if markdown_file.present? + end + end + + def markdown_file + case segment_type + when 'video' + object.script_file + when 'text' + object.markdown_file + else + nil + end + end + + # What is the segment type + def segment_type + object.class.name.demodulize.underscore + end + end + end +end diff --git a/app/lib/linting/image_linter.rb b/app/lib/linting/image_linter.rb index 0db6875..7577f9b 100644 --- a/app/lib/linting/image_linter.rb +++ b/app/lib/linting/image_linter.rb @@ -1,16 +1,19 @@ # frozen_string_literal: true module Linting - # Lints the images in a book + # Lints the images in a book or a content_module class ImageLinter - attr_reader :book + attr_reader :book, :content_module - def initialize(book:) + def initialize(book: nil, content_module: nil) @book = book + @content_module = content_module end def lint - Linting::Image::Book.lint(book) + return Linting::Image::Book.lint(book) if book.present? + + Linting::Image::ContentModule.lint(content_module) if content_module.present? end end end From a0d7ed2078518cf03d56a4cd2c66b2bcdb9d653f Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Wed, 10 Jan 2024 15:41:30 +0700 Subject: [PATCH 15/17] WEB-6757: Improving lesson and segment validation --- app/models/lesson.rb | 1 + app/models/lessons_validator.rb | 20 +++++++--------- app/models/segments_validator.rb | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 app/models/segments_validator.rb diff --git a/app/models/lesson.rb b/app/models/lesson.rb index 7f5499d..ce70093 100644 --- a/app/models/lesson.rb +++ b/app/models/lesson.rb @@ -12,6 +12,7 @@ class Lesson attr_markdown :description, source: :description_md, file: false attr_markdown :learning_objectives, source: :learning_objectives_md, file: false validates :title, :ordinal, :ref, presence: true + validates :segments, length: { minimum: 1 }, allow_blank: false, segments: true def initialize(attributes = {}) super diff --git a/app/models/lessons_validator.rb b/app/models/lessons_validator.rb index aca3586..cbeb196 100644 --- a/app/models/lessons_validator.rb +++ b/app/models/lessons_validator.rb @@ -19,24 +19,20 @@ def check_correct_class(record, attribute, value) def check_unique_refs(record, attribute, value) return unless value.is_a?(Array) - value.each do |lesson| - ref_counts = Hash.new(0) - lesson.segments.each { |segment| ref_counts[segment.ref] += 1 } - non_unique_refs = ref_counts.select { |_, count| count > 1 }.keys + ref_counts = Hash.new(0) + value.each { |lesson| ref_counts[lesson.ref] += 1 } + non_unique_refs = ref_counts.select { |_, count| count > 1 }.keys - non_unique_refs.each { |ref| record.errors.add(attribute, "(#{lesson.title}) segment ref #{ref} is not unique") } - end + non_unique_refs.each { |ref| record.errors.add(attribute, "=> ref '#{ref}' is not unique") } end def check_unique_title(record, attribute, value) return unless value.is_a?(Array) - value.each do |lesson| - title_counts = Hash.new(0) - lesson.segments.each { |segment| title_counts[segment.title] += 1 } - non_unique_titles = title_counts.select { |_, count| count > 1 }.keys + title_counts = Hash.new(0) + value.each { |lesson| title_counts[lesson.title] += 1 } + non_unique_titles = title_counts.select { |_, count| count > 1 }.keys - non_unique_titles.each { |title| record.errors.add(attribute, "(#{lesson.title}) segment title #{title} is not unique") } - end + non_unique_titles.each { |title| record.errors.add(attribute, "=> Title '#{title}' is not unique") } end end diff --git a/app/models/segments_validator.rb b/app/models/segments_validator.rb new file mode 100644 index 0000000..02fabfc --- /dev/null +++ b/app/models/segments_validator.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# A validator that will check an array of choices for uniqueness of ref +class SegmentsValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + return unless value.is_a?(Array) + + check_correct_class(record, attribute, value) + check_unique_refs(record, attribute, value) + check_unique_title(record, attribute, value) + end + + def check_correct_class(record, attribute, value) + value.each do |segment| + record.errors.add(attribute, "segment #{segment} needs to be a quiz, video or text") unless [Assessment::Quiz, Video, Text].any? { |klass| segment.is_a?(klass) } + end + end + + def check_unique_refs(record, attribute, value) + return unless value.is_a?(Array) + + ref_counts = Hash.new(0) + value.each { |segment| ref_counts[segment.ref] += 1 } + non_unique_refs = ref_counts.select { |_, count| count > 1 }.keys + + non_unique_refs.each { |ref| record.errors.add(attribute, "(#{record.title}) => Segment ref '#{ref}' is not unique") } + end + + def check_unique_title(record, attribute, value) + return unless value.is_a?(Array) + + title_counts = Hash.new(0) + + value.each { |segment| title_counts[segment.title] += 1 } + non_unique_titles = title_counts.select { |_, count| count > 1 }.keys + + non_unique_titles.each { |title| record.errors.add(attribute, "(#{record.title}) => Segment title '#{title}' is not unique") } + end +end From a44d6aaf5809916285363dc2d3e0dbd2a13202e7 Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Mon, 15 Jan 2024 14:36:12 +0700 Subject: [PATCH 16/17] WEB-6568: Updating slack images in robles --- app/lib/util/slack_notifiable.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/lib/util/slack_notifiable.rb b/app/lib/util/slack_notifiable.rb index 88b8f87..d1dc1d4 100644 --- a/app/lib/util/slack_notifiable.rb +++ b/app/lib/util/slack_notifiable.rb @@ -5,12 +5,13 @@ module Util module SlackNotifiable # rubocop:disable Metrics/ModuleLength extend ActiveSupport::Concern - BOOK_SUCCESS_IMAGE_URL = 'https://wolverine.raywenderlich.com/v3-resources/razebot/images/object_textkit-book.png' - VIDEO_COURSE_SUCCESS_IMAGE_URL = 'https://wolverine.raywenderlich.com/v3-resources/razebot/images/device-device_ui-flow-chart.png' - FAILURE_IMAGE_URL = 'https://wolverine.raywenderlich.com/v3-resources/razebot/images/object_errors.png' - BOOK_ROBLES_CONTEXT_IMAGE_URL = 'https://wolverine.raywenderlich.com/v3-resources/razebot/images/object_box-of-books.png' - VIDEO_COURSE_ROBLES_CONTEXT_IMAGE_URL = 'https://wolverine.raywenderlich.com/v3-resources/razebot/images/object-box-videos.png' - CONTENT_MODULE_ROBLES_CONTEXT_IMAGE_URL = 'https://wolverine.raywenderlich.com/v3-resources/razebot/images/object-box-content-module.png' + BOOK_SUCCESS_IMAGE_URL = 'https://cdn.kodeco.com/v3-resources/razebot/images/media-article-multi-platform.png' + VIDEO_COURSE_SUCCESS_IMAGE_URL = 'https://cdn.kodeco.com/v3-resources/razebot/images/media-course-multi-platform.png' + CONTENT_MODULE_SUCCESS_IMAGE_URL = 'https://cdn.kodeco.com/v3-resources/razebot/images/media-multi-multi-platform.png' + FAILURE_IMAGE_URL = 'https://cdn.kodeco.com/v3-resources/razebot/images/cross.png' + BOOK_ROBLES_CONTEXT_IMAGE_URL = 'https://cdn.kodeco.com/v3-resources/razebot/images/media-path-multi-platform.png' + VIDEO_COURSE_ROBLES_CONTEXT_IMAGE_URL = 'https://cdn.kodeco.com/v3-resources/razebot/images/media-path-multi-platform.png' + CONTENT_MODULE_ROBLES_CONTEXT_IMAGE_URL = 'https://cdn.kodeco.com/v3-resources/razebot/images/media-path-multi-platform.png' def notify_book_success(book:) return unless notifiable? @@ -126,7 +127,7 @@ def content_module_success_blocks(content_module:) [ intro_section(fields: standard_content_module_fields(content_module:), message: ':white_check_mark: Content module upload successful!', - image_url: CONTENT_MODULE_ROBLES_CONTEXT_IMAGE_URL, + image_url: CONTENT_MODULE_SUCCESS_IMAGE_URL, alt_text: 'Upload successful'), { type: 'divider' From c7fb8cb2a120cec5ed922571ee3e38523633b0ce Mon Sep 17 00:00:00 2001 From: Sam Davies Date: Tue, 16 Jan 2024 11:03:38 +0700 Subject: [PATCH 17/17] Need to mark github directory as safe if we're inside CI Otherwise git doesn't work --- bin/robles | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/robles b/bin/robles index 87cd143..ab1068e 100755 --- a/bin/robles +++ b/bin/robles @@ -4,6 +4,11 @@ APP_PATH = File.expand_path('../config/application', __dir__) require_relative '../config/application' +if GITHUB_WORKSPACE.present? + # Add the workspace as a safe directory to global git if we're inside a GitHub Action + Git.global_config('safe.directory', GITHUB_WORKSPACE) +end + begin RoblesCli.start(ARGV) rescue Exception => e # rubocop:disable Lint/RescueException