diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-05-03 15:07:28 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-05-03 15:07:28 +0300 |
commit | 5fabe42e23beba3fbe393e566a5a4ebde2062c61 (patch) | |
tree | 9a2dfa55656973763fcc05ac393bd2bd06125935 /scripts/lib | |
parent | 4df4a22481c3ed10e22cdb795dd6d811c4e89fde (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'scripts/lib')
-rw-r--r-- | scripts/lib/glfm/constants.rb | 30 | ||||
-rw-r--r-- | scripts/lib/glfm/shared.rb | 28 | ||||
-rw-r--r-- | scripts/lib/glfm/update_specification.rb | 105 |
3 files changed, 163 insertions, 0 deletions
diff --git a/scripts/lib/glfm/constants.rb b/scripts/lib/glfm/constants.rb new file mode 100644 index 00000000000..70f38e45cf5 --- /dev/null +++ b/scripts/lib/glfm/constants.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Glfm + module Constants + # Root dir containing all specification files + specification_path = Pathname.new(File.expand_path("../../../glfm_specification", __dir__)) + + # GitHub Flavored Markdown specification file + GHFM_SPEC_TXT_URI = 'https://raw.githubusercontent.com/github/cmark-gfm/master/test/spec.txt' + GHFM_SPEC_VERSION = '0.29' + GHFM_SPEC_TXT_FILENAME = "ghfm_spec_v_#{GHFM_SPEC_VERSION}.txt" + GHFM_SPEC_TXT_PATH = specification_path.join('input/github_flavored_markdown', GHFM_SPEC_TXT_FILENAME) + + # GitLab Flavored Markdown specification files + specification_input_glfm_path = specification_path.join('input/gitlab_flavored_markdown') + GLFM_INTRO_TXT_PATH = specification_input_glfm_path.join('glfm_intro.txt') + GLFM_EXAMPLES_TXT_PATH = specification_input_glfm_path.join('glfm_canonical_examples.txt') + GLFM_SPEC_TXT_PATH = specification_path.join('output/spec.txt') + + # Other constants used for processing files + GLFM_SPEC_TXT_HEADER = <<~GLFM_SPEC_TXT_HEADER + --- + title: GitLab Flavored Markdown (GLFM) Spec + version: alpha + ... + GLFM_SPEC_TXT_HEADER + INTRODUCTION_HEADER_LINE_TEXT = /\A# Introduction\Z/.freeze + END_TESTS_COMMENT_LINE_TEXT = /\A<!-- END TESTS -->\Z/.freeze + end +end diff --git a/scripts/lib/glfm/shared.rb b/scripts/lib/glfm/shared.rb new file mode 100644 index 00000000000..92ca067f9f8 --- /dev/null +++ b/scripts/lib/glfm/shared.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +require 'fileutils' + +module Glfm + module Shared + def write_file(file_path, file_content_string) + FileUtils.mkdir_p(File.dirname(file_path)) + # NOTE: We don't use the block form of File.open because we want to be able to easily + # mock it for testing. + io = File.open(file_path, 'w') + io.binmode + io.write(file_content_string) + # NOTE: We are using #fsync + #close_write instead of just #close`, in order to unit test + # with a real StringIO and not just a mock object. + io.fsync + io.close_write + end + + # All script output goes through this method. This makes it easy to mock in order to prevent + # output from being printed to the console during tests. We don't want to directly mock + # Kernel#puts, because that could interfere or cause spurious test failures when #puts is used + # for debugging. And for some reason RuboCop says `rubocop:disable Rails/Output` would be + # redundant here, so not including it. + def output(string) + puts string + end + end +end diff --git a/scripts/lib/glfm/update_specification.rb b/scripts/lib/glfm/update_specification.rb new file mode 100644 index 00000000000..df648f4115b --- /dev/null +++ b/scripts/lib/glfm/update_specification.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true +require 'fileutils' +require 'open-uri' +require 'pathname' +require_relative 'constants' +require_relative 'shared' + +module Glfm + class UpdateSpecification + include Constants + include Shared + + def process + output('Updating specification...') + ghfm_spec_txt_lines = download_and_write_ghfm_spec_txt + glfm_spec_txt_string = build_glfm_spec_txt(ghfm_spec_txt_lines) + write_glfm_spec_txt(glfm_spec_txt_string) + end + + private + + def download_and_write_ghfm_spec_txt + output("Downloading #{GHFM_SPEC_TXT_URI}...") + ghfm_spec_txt_uri_io = URI.open(GHFM_SPEC_TXT_URI) + + # Read IO stream into an array of lines for easy processing later + ghfm_spec_txt_lines = ghfm_spec_txt_uri_io.readlines + raise "Unable to read lines from #{GHFM_SPEC_TXT_URI}" if ghfm_spec_txt_lines.empty? + + # Make sure the GHFM spec version has not changed + validate_expected_spec_version!(ghfm_spec_txt_lines[2]) + + # Reset IO stream and re-read into a single string for easy writing + # noinspection RubyNilAnalysis + ghfm_spec_txt_uri_io.seek(0) + ghfm_spec_txt_string = ghfm_spec_txt_uri_io.read + raise "Unable to read string from #{GHFM_SPEC_TXT_URI}" unless ghfm_spec_txt_string + + output("Writing #{GHFM_SPEC_TXT_PATH}...") + GHFM_SPEC_TXT_PATH.dirname.mkpath + write_file(GHFM_SPEC_TXT_PATH, ghfm_spec_txt_string) + + ghfm_spec_txt_lines + end + + def validate_expected_spec_version!(version_line) + return if version_line =~ /\Aversion: #{GHFM_SPEC_VERSION}\Z/o + + raise "GitHub Flavored Markdown spec.txt version mismatch! " \ + "Expected 'version: #{GHFM_SPEC_VERSION}', got '#{version_line}'" + end + + def build_glfm_spec_txt(ghfm_spec_txt_lines) + glfm_spec_txt_lines = ghfm_spec_txt_lines.dup + replace_header(glfm_spec_txt_lines) + replace_intro_section(glfm_spec_txt_lines) + insert_examples_txt(glfm_spec_txt_lines) + glfm_spec_txt_lines.join('') + end + + def replace_header(spec_txt_lines) + spec_txt_lines[0, spec_txt_lines.index("...\n") + 1] = GLFM_SPEC_TXT_HEADER + end + + def replace_intro_section(spec_txt_lines) + glfm_intro_txt_lines = File.open(GLFM_INTRO_TXT_PATH).readlines + raise "Unable to read lines from #{GLFM_INTRO_TXT_PATH}" if glfm_intro_txt_lines.empty? + + ghfm_intro_header_begin_index = spec_txt_lines.index do |line| + line =~ INTRODUCTION_HEADER_LINE_TEXT + end + raise "Unable to locate introduction header line in #{GHFM_SPEC_TXT_PATH}" if ghfm_intro_header_begin_index.nil? + + # Find the index of the next header after the introduction header, starting from the index + # of the introduction header this is the length of the intro section + ghfm_intro_section_length = spec_txt_lines[ghfm_intro_header_begin_index + 1..].index do |line| + line.start_with?('# ') + end + + # Replace the intro section with the GitLab flavored Markdown intro section + spec_txt_lines[ghfm_intro_header_begin_index, ghfm_intro_section_length] = glfm_intro_txt_lines + end + + def insert_examples_txt(spec_txt_lines) + glfm_examples_txt_lines = File.open(GLFM_EXAMPLES_TXT_PATH).readlines + raise "Unable to read lines from #{GLFM_EXAMPLES_TXT_PATH}" if glfm_examples_txt_lines.empty? + + ghfm_end_tests_comment_index = spec_txt_lines.index do |line| + line =~ END_TESTS_COMMENT_LINE_TEXT + end + raise "Unable to locate 'END TESTS' comment line in #{GHFM_SPEC_TXT_PATH}" if ghfm_end_tests_comment_index.nil? + + # Insert the GLFM examples before the 'END TESTS' comment line + spec_txt_lines[ghfm_end_tests_comment_index - 1] = ["\n", glfm_examples_txt_lines, "\n"].flatten + + spec_txt_lines + end + + def write_glfm_spec_txt(glfm_spec_txt_string) + output("Writing #{GLFM_SPEC_TXT_PATH}...") + FileUtils.mkdir_p(Pathname.new(GLFM_SPEC_TXT_PATH).dirname) + write_file(GLFM_SPEC_TXT_PATH, glfm_spec_txt_string) + end + end +end |