Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-10-20 12:40:42 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-10-20 12:40:42 +0300
commitee664acb356f8123f4f6b00b73c1e1cf0866c7fb (patch)
treef8479f94a28f66654c6a4f6fb99bad6b4e86a40e /spec/scripts
parent62f7d5c5b69180e82ae8196b7b429eeffc8e7b4f (diff)
Add latest changes from gitlab-org/gitlab@15-5-stable-eev15.5.0-rc42
Diffstat (limited to 'spec/scripts')
-rw-r--r--spec/scripts/lib/glfm/update_example_snapshots_spec.rb759
-rw-r--r--spec/scripts/lib/glfm/update_specification_spec.rb169
-rw-r--r--spec/scripts/lib/glfm/verify_all_generated_files_are_up_to_date_spec.rb62
-rw-r--r--spec/scripts/trigger-build_spec.rb2
4 files changed, 618 insertions, 374 deletions
diff --git a/spec/scripts/lib/glfm/update_example_snapshots_spec.rb b/spec/scripts/lib/glfm/update_example_snapshots_spec.rb
index f96936c0a6f..c97226c1a2d 100644
--- a/spec/scripts/lib/glfm/update_example_snapshots_spec.rb
+++ b/spec/scripts/lib/glfm/update_example_snapshots_spec.rb
@@ -2,8 +2,8 @@
require 'fast_spec_helper'
require_relative '../../../../scripts/lib/glfm/update_example_snapshots'
-# IMPORTANT NOTE: See https://docs.gitlab.com/ee/development/gitlab_flavored_markdown/specification_guide/
-# for details on the implementation and usage of the `update_example_snapshots` script being tested.
+# IMPORTANT NOTE: See https://docs.gitlab.com/ee/development/gitlab_flavored_markdown/specification_guide/#update-example-snapshotsrb-script
+# for details on the implementation and usage of the `update_example_snapshots.rb` script being tested.
# This developers guide contains diagrams and documentation of the script,
# including explanations and examples of all files it reads and writes.
#
@@ -16,17 +16,18 @@ require_relative '../../../../scripts/lib/glfm/update_example_snapshots'
# which runs a jest test environment. This results in each full run of the script
# taking between 30-60 seconds. The majority of this is spent loading the Rails environment.
#
-# However, only the `writing html.yml and prosemirror_json.yml` context is used
-# to test these slow sub-processes, and it only contains a single example.
+# However, only the `with full processing of static and WYSIWYG HTML` context is used
+# to test these slow sub-processes, and it only contains two examples.
#
# All other tests currently in the file pass the `skip_static_and_wysiwyg: true`
-# flag to `#process`, which skips the slow sub-processes. All of these tests
+# flag to `#process`, which skips the slow sub-processes. All of these other tests
# should run in sub-second time when the Spring pre-loader is used. This allows
# logic which is not directly related to the slow sub-processes to be TDD'd with a
# very rapid feedback cycle.
#
# Also, the textual content of the individual fixture file entries is also crafted to help
# indicate which scenarios which they are covering.
+# rubocop:disable RSpec/MultipleMemoizedHelpers
RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
subject { described_class.new }
@@ -34,9 +35,8 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
let(:glfm_spec_txt_path) { described_class::GLFM_SPEC_TXT_PATH }
let(:glfm_spec_txt_local_io) { StringIO.new(glfm_spec_txt_contents) }
let(:glfm_example_status_yml_path) { described_class::GLFM_EXAMPLE_STATUS_YML_PATH }
- let(:glfm_example_status_yml_io) { StringIO.new(glfm_example_status_yml_contents) }
let(:glfm_example_metadata_yml_path) { described_class::GLFM_EXAMPLE_METADATA_YML_PATH }
- let(:glfm_example_metadata_yml_io) { StringIO.new(glfm_example_metadata_yml_contents) }
+ let(:glfm_example_normalizations_yml_path) { described_class::GLFM_EXAMPLE_NORMALIZATIONS_YML_PATH }
# Example Snapshot (ES) output files
let(:es_examples_index_yml_path) { described_class::ES_EXAMPLES_INDEX_YML_PATH }
@@ -285,10 +285,25 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
YAML
end
+ let(:test1) { '\1\2URI_PREFIX\4' }
+
+ let(:glfm_example_normalizations_yml_contents) do
+ # NOTE: This heredoc identifier must be quoted because we are using control characters in the heredoc body.
+ # See https://stackoverflow.com/a/73831037/25192
+ <<~'YAML'
+ ---
+ # If a config file entry starts with `00_`, it will be skipped for validation that it exists in `examples_index.yml`
+ 00_shared:
+ 00_uri: &00_uri
+ - regex: '(href|data-src)(=")(.*?)(test-file\.(png|zip)")'
+ replacement: '\1\2URI_PREFIX\4'
+ YAML
+ end
+
let(:es_html_yml_io_existing_contents) do
<<~YAML
---
- 00_00_00__obsolete_entry_to_be_deleted__001:
+ 01_00_00__obsolete_entry_to_be_deleted__001:
canonical: |
This entry is no longer exists in the spec.txt, so it will be deleted.
static: |-
@@ -315,7 +330,7 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
let(:es_prosemirror_json_yml_io_existing_contents) do
<<~YAML
---
- 00_00_00__obsolete_entry_to_be_deleted__001: |-
+ 01_00_00__obsolete_entry_to_be_deleted__001: |-
{
"obsolete": "This entry is no longer exists in the spec.txt, and is not skipped, so it will be deleted."
}
@@ -356,9 +371,14 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
# input files
allow(File).to receive(:open).with(glfm_spec_txt_path) { glfm_spec_txt_local_io }
- allow(File).to receive(:open).with(glfm_example_status_yml_path) { glfm_example_status_yml_io }
+ allow(File).to receive(:open).with(glfm_example_status_yml_path) do
+ StringIO.new(glfm_example_status_yml_contents)
+ end
allow(File).to receive(:open).with(glfm_example_metadata_yml_path) do
- glfm_example_metadata_yml_io
+ StringIO.new(glfm_example_metadata_yml_contents)
+ end
+ allow(File).to receive(:open).with(glfm_example_normalizations_yml_path) do
+ StringIO.new(glfm_example_normalizations_yml_contents)
end
# output files
@@ -525,353 +545,404 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
end
end
- # rubocop:disable RSpec/MultipleMemoizedHelpers
- describe 'writing html.yml and prosemirror_json.yml' do
- let(:es_html_yml_contents) { reread_io(es_html_yml_io) }
- let(:es_prosemirror_json_yml_contents) { reread_io(es_prosemirror_json_yml_io) }
+ describe 'error handling when manually-curated input specification config files contain invalid example names:' do
+ let(:err_msg) do
+ /#{config_file}.*01_00_00__invalid__001.*does not have.*entry in.*#{described_class::ES_EXAMPLES_INDEX_YML_PATH}/m
+ end
- # NOTE: This example_status.yml is crafted in conjunction with expected_html_yml_contents
- # to test the behavior of the `skip_update_*` flags
- let(:glfm_example_status_yml_contents) do
+ let(:invalid_example_name_file_contents) do
<<~YAML
---
- 02_01_00__inlines__strong__002:
- # NOTE: 02_01_00__inlines__strong__002: is omitted from the existing prosemirror_json.yml file, and is also
- # skipped here, to show that an example does not need to exist in order to be skipped.
- # TODO: This should be changed to raise an error instead, to enforce that there cannot be orphaned
- # entries in glfm_example_status.yml. This task is captured in
- # https://gitlab.com/gitlab-org/gitlab/-/issues/361241#other-cleanup-tasks
- skip_update_example_snapshot_prosemirror_json: "skipping because JSON isn't cool enough"
- 03_01_00__first_gitlab_specific_section_with_examples__strong_but_with_two_asterisks__001:
- skip_update_example_snapshot_html_static: "skipping because there's too much static"
- 04_01_00__second_gitlab_specific_section_with_examples__strong_but_with_html__001:
- skip_update_example_snapshot_html_wysiwyg: 'skipping because what you see is NOT what you get'
- skip_update_example_snapshot_prosemirror_json: "skipping because JSON still isn't cool enough"
- 05_01_00__third_gitlab_specific_section_with_skipped_examples__strong_but_skipped__001:
- skip_update_example_snapshots: 'skipping this example because it is very bad'
- 05_02_00__third_gitlab_specific_section_with_skipped_examples__strong_but_manually_modified_and_skipped__001:
- skip_update_example_snapshots: 'skipping this example because we have manually modified it'
+ 01_00_00__invalid__001:
+ a: 1
YAML
end
- let(:expected_html_yml_contents) do
- <<~YAML
- ---
- 02_01_00__inlines__strong__001:
- canonical: |
- <p><strong>bold</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto"><strong>bold</strong></p>
- wysiwyg: |-
- <p><strong>bold</strong></p>
- 02_01_00__inlines__strong__002:
- canonical: |
- <p><strong>bold with more text</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:23" dir="auto"><strong>bold with more text</strong></p>
- wysiwyg: |-
- <p><strong>bold with more text</strong></p>
- 02_03_00__inlines__strikethrough_extension__001:
- canonical: |
- <p><del>Hi</del> Hello, world!</p>
- static: |-
- <p data-sourcepos="1:1-1:20" dir="auto"><del>Hi</del> Hello, world!</p>
- wysiwyg: |-
- <p><s>Hi</s> Hello, world!</p>
- 03_01_00__first_gitlab_specific_section_with_examples__strong_but_with_two_asterisks__001:
- canonical: |
- <p><strong>bold</strong></p>
- wysiwyg: |-
- <p><strong>bold</strong></p>
- 03_02_01__first_gitlab_specific_section_with_examples__h2_which_contains_an_h3__example_in_an_h3__001:
- canonical: |
- <p>Example in an H3</p>
- static: |-
- <p data-sourcepos="1:1-1:16" dir="auto">Example in an H3</p>
- wysiwyg: |-
- <p>Example in an H3</p>
- 04_01_00__second_gitlab_specific_section_with_examples__strong_but_with_html__001:
- canonical: |
- <p><strong>
- bold
- </strong></p>
- static: |-
- <strong>
- bold
- </strong>
- 05_02_00__third_gitlab_specific_section_with_skipped_examples__strong_but_manually_modified_and_skipped__001:
- canonical: |
- <p><strong>This example will have its manually modified static HTML, WYSIWYG HTML, and ProseMirror JSON preserved</strong></p>
- static: |-
- <p>This is the manually modified static HTML which will be preserved</p>
- wysiwyg: |-
- <p>This is the manually modified WYSIWYG HTML which will be preserved</p>
- 06_01_00__api_request_overrides__group_upload_link__001:
- canonical: |
- <p><a href="groups-test-file">groups-test-file</a></p>
- static: |-
- <p data-sourcepos="1:1-1:45" dir="auto"><a href="/groups/glfm_group/-/uploads/groups-test-file" data-canonical-src="/uploads/groups-test-file" data-link="true" class="gfm">groups-test-file</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uploads/groups-test-file">groups-test-file</a></p>
- 06_02_00__api_request_overrides__project_repo_link__001:
- canonical: |
- <p><a href="projects-test-file">projects-test-file</a></p>
- static: |-
- <p data-sourcepos="1:1-1:40" dir="auto"><a href="/glfm_group/glfm_project/-/blob/master/projects-test-file">projects-test-file</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="projects-test-file">projects-test-file</a></p>
- 06_03_00__api_request_overrides__project_snippet_ref__001:
- canonical: |
- <p>This project snippet ID reference IS filtered: <a href="/glfm_group/glfm_project/-/snippets/88888">$88888</a>
- static: |-
- <p data-sourcepos="1:1-1:53" dir="auto">This project snippet ID reference IS filtered: <a href="/glfm_group/glfm_project/-/snippets/88888" data-reference-type="snippet" data-original="$88888" data-link="false" data-link-reference="false" data-project="77777" data-snippet="88888" data-container="body" data-placement="top" title="glfm_project_snippet" class="gfm gfm-snippet has-tooltip">$88888</a></p>
- wysiwyg: |-
- <p>This project snippet ID reference IS filtered: $88888</p>
- 06_04_00__api_request_overrides__personal_snippet_ref__001:
- canonical: |
- <p>This personal snippet ID reference is NOT filtered: $99999</p>
- static: |-
- <p data-sourcepos="1:1-1:58" dir="auto">This personal snippet ID reference is NOT filtered: $99999</p>
- wysiwyg: |-
- <p>This personal snippet ID reference is NOT filtered: $99999</p>
- 06_05_00__api_request_overrides__project_wiki_link__001:
- canonical: |
- <p><a href="project-wikis-test-file">project-wikis-test-file</a></p>
- static: |-
- <p data-sourcepos="1:1-1:50" dir="auto"><a href="/glfm_group/glfm_project/-/wikis/project-wikis-test-file" data-canonical-src="project-wikis-test-file">project-wikis-test-file</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="project-wikis-test-file">project-wikis-test-file</a></p>
- YAML
+ context 'for glfm_example_status.yml' do
+ let(:config_file) { described_class::GLFM_EXAMPLE_STATUS_YML_PATH }
+ let(:glfm_example_status_yml_contents) { invalid_example_name_file_contents }
+
+ it 'raises error' do
+ expect { subject.process(skip_static_and_wysiwyg: true) }.to raise_error(err_msg)
+ end
end
- let(:expected_prosemirror_json_contents) do
- <<~YAML
- ---
- 02_01_00__inlines__strong__001: |-
- {
- "type": "doc",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "marks": [
- {
- "type": "bold"
- }
- ],
- "text": "bold"
- }
- ]
- }
- ]
- }
- 02_03_00__inlines__strikethrough_extension__001: |-
- {
- "type": "doc",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "marks": [
- {
- "type": "strike"
- }
- ],
- "text": "Hi"
- },
- {
- "type": "text",
- "text": " Hello, world!"
- }
- ]
- }
- ]
- }
- 03_01_00__first_gitlab_specific_section_with_examples__strong_but_with_two_asterisks__001: |-
- {
- "type": "doc",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "marks": [
- {
- "type": "bold"
- }
- ],
- "text": "bold"
- }
- ]
- }
- ]
- }
- 03_02_01__first_gitlab_specific_section_with_examples__h2_which_contains_an_h3__example_in_an_h3__001: |-
- {
- "type": "doc",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "text": "Example in an H3"
- }
- ]
- }
- ]
- }
- 04_01_00__second_gitlab_specific_section_with_examples__strong_but_with_html__001: |-
- {
- "existing": "This entry is manually modified and preserved because skip_update_example_snapshot_prosemirror_json will be truthy"
- }
- 05_02_00__third_gitlab_specific_section_with_skipped_examples__strong_but_manually_modified_and_skipped__001: |-
- {
- "existing": "This entry is manually modified and preserved because skip_update_example_snapshots will be truthy"
- }
- 06_01_00__api_request_overrides__group_upload_link__001: |-
- {
- "type": "doc",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "marks": [
- {
- "type": "link",
- "attrs": {
- "href": "/uploads/groups-test-file",
- "target": "_blank",
- "class": null,
- "title": null,
- "canonicalSrc": "/uploads/groups-test-file",
- "isReference": false
- }
- }
- ],
- "text": "groups-test-file"
- }
- ]
- }
- ]
- }
- 06_02_00__api_request_overrides__project_repo_link__001: |-
- {
- "type": "doc",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "marks": [
- {
- "type": "link",
- "attrs": {
- "href": "projects-test-file",
- "target": "_blank",
- "class": null,
- "title": null,
- "canonicalSrc": "projects-test-file",
- "isReference": false
- }
- }
- ],
- "text": "projects-test-file"
- }
- ]
- }
- ]
- }
- 06_03_00__api_request_overrides__project_snippet_ref__001: |-
- {
- "type": "doc",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "text": "This project snippet ID reference IS filtered: $88888"
- }
- ]
- }
- ]
- }
- 06_04_00__api_request_overrides__personal_snippet_ref__001: |-
- {
- "type": "doc",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "text": "This personal snippet ID reference is NOT filtered: $99999"
- }
- ]
- }
- ]
- }
- 06_05_00__api_request_overrides__project_wiki_link__001: |-
- {
- "type": "doc",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "marks": [
- {
- "type": "link",
- "attrs": {
- "href": "project-wikis-test-file",
- "target": "_blank",
- "class": null,
- "title": null,
- "canonicalSrc": "project-wikis-test-file",
- "isReference": false
- }
- }
- ],
- "text": "project-wikis-test-file"
- }
- ]
- }
- ]
- }
- YAML
+ context 'for glfm_example_metadata.yml' do
+ let(:config_file) { described_class::GLFM_EXAMPLE_METADATA_YML_PATH }
+ let(:glfm_example_metadata_yml_contents) { invalid_example_name_file_contents }
+
+ it 'raises error' do
+ expect { subject.process(skip_static_and_wysiwyg: true) }.to raise_error(err_msg)
+ end
end
- before do
- # NOTE: This is a necessary to avoid an `error Couldn't find an integrity file` error
- # when invoking `yarn jest ...` on CI from within an RSpec job. It could be solved by
- # adding `.yarn-install` to be included in the RSpec CI job, but that would be a performance
- # hit to all RSpec jobs. We could also make a dedicate job just for this spec. However,
- # since this is just a single script, those options may not be justified.
- described_class.new.run_external_cmd('yarn install') if ENV['CI']
+ context 'for glfm_example_normalizations.yml' do
+ let(:config_file) { described_class::GLFM_EXAMPLE_NORMALIZATIONS_YML_PATH }
+ let(:glfm_example_normalizations_yml_contents) { invalid_example_name_file_contents }
+
+ it 'raises error' do
+ expect { subject.process(skip_static_and_wysiwyg: true) }.to raise_error(err_msg)
+ end
end
+ end
+
+ context 'with full processing of static and WYSIWYG HTML' do
+ before(:all) do
+ # NOTE: It is a necessary to do a `yarn install` in order to ensure that
+ # `scripts/lib/glfm/render_wysiwyg_html_and_json.js` can be invoked successfully
+ # on the CI job (which will not be set up for frontend specs since this is
+ # an RSpec spec), or if the current yarn dependencies are not installed locally.
+ described_class.new.run_external_cmd('yarn install --frozen-lockfile')
+ end
+
+ describe 'manually-curated input specification config files' do
+ let(:glfm_example_status_yml_contents) { '' }
+ let(:glfm_example_metadata_yml_contents) { '' }
+ let(:glfm_example_normalizations_yml_contents) { '' }
+
+ it 'can be empty' do
+ expect { subject.process }.not_to raise_error
+ end
+ end
+
+ describe 'writing html.yml and prosemirror_json.yml' do
+ let(:es_html_yml_contents) { reread_io(es_html_yml_io) }
+ let(:es_prosemirror_json_yml_contents) { reread_io(es_prosemirror_json_yml_io) }
+
+ # NOTE: This example_status.yml is crafted in conjunction with expected_html_yml_contents
+ # to test the behavior of the `skip_update_*` flags
+ let(:glfm_example_status_yml_contents) do
+ <<~YAML
+ ---
+ 02_01_00__inlines__strong__002:
+ # NOTE: 02_01_00__inlines__strong__002: is omitted from the existing prosemirror_json.yml file, and is also
+ # skipped here, to show that an example does not need to exist in order to be skipped.
+ # TODO: This should be changed to raise an error instead, to enforce that there cannot be orphaned
+ # entries in glfm_example_status.yml. This task is captured in
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/361241#other-cleanup-tasks
+ skip_update_example_snapshot_prosemirror_json: "skipping because JSON isn't cool enough"
+ 03_01_00__first_gitlab_specific_section_with_examples__strong_but_with_two_asterisks__001:
+ skip_update_example_snapshot_html_static: "skipping because there's too much static"
+ 04_01_00__second_gitlab_specific_section_with_examples__strong_but_with_html__001:
+ skip_update_example_snapshot_html_wysiwyg: 'skipping because what you see is NOT what you get'
+ skip_update_example_snapshot_prosemirror_json: "skipping because JSON still isn't cool enough"
+ 05_01_00__third_gitlab_specific_section_with_skipped_examples__strong_but_skipped__001:
+ skip_update_example_snapshots: 'skipping this example because it is very bad'
+ 05_02_00__third_gitlab_specific_section_with_skipped_examples__strong_but_manually_modified_and_skipped__001:
+ skip_update_example_snapshots: 'skipping this example because we have manually modified it'
+ YAML
+ end
+
+ let(:expected_html_yml_contents) do
+ <<~YAML
+ ---
+ 02_01_00__inlines__strong__001:
+ canonical: |
+ <p><strong>bold</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto"><strong>bold</strong></p>
+ wysiwyg: |-
+ <p><strong>bold</strong></p>
+ 02_01_00__inlines__strong__002:
+ canonical: |
+ <p><strong>bold with more text</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:23" dir="auto"><strong>bold with more text</strong></p>
+ wysiwyg: |-
+ <p><strong>bold with more text</strong></p>
+ 02_03_00__inlines__strikethrough_extension__001:
+ canonical: |
+ <p><del>Hi</del> Hello, world!</p>
+ static: |-
+ <p data-sourcepos="1:1-1:20" dir="auto"><del>Hi</del> Hello, world!</p>
+ wysiwyg: |-
+ <p><s>Hi</s> Hello, world!</p>
+ 03_01_00__first_gitlab_specific_section_with_examples__strong_but_with_two_asterisks__001:
+ canonical: |
+ <p><strong>bold</strong></p>
+ wysiwyg: |-
+ <p><strong>bold</strong></p>
+ 03_02_01__first_gitlab_specific_section_with_examples__h2_which_contains_an_h3__example_in_an_h3__001:
+ canonical: |
+ <p>Example in an H3</p>
+ static: |-
+ <p data-sourcepos="1:1-1:16" dir="auto">Example in an H3</p>
+ wysiwyg: |-
+ <p>Example in an H3</p>
+ 04_01_00__second_gitlab_specific_section_with_examples__strong_but_with_html__001:
+ canonical: |
+ <p><strong>
+ bold
+ </strong></p>
+ static: |-
+ <strong>
+ bold
+ </strong>
+ 05_02_00__third_gitlab_specific_section_with_skipped_examples__strong_but_manually_modified_and_skipped__001:
+ canonical: |
+ <p><strong>This example will have its manually modified static HTML, WYSIWYG HTML, and ProseMirror JSON preserved</strong></p>
+ static: |-
+ <p>This is the manually modified static HTML which will be preserved</p>
+ wysiwyg: |-
+ <p>This is the manually modified WYSIWYG HTML which will be preserved</p>
+ 06_01_00__api_request_overrides__group_upload_link__001:
+ canonical: |
+ <p><a href="groups-test-file">groups-test-file</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:45" dir="auto"><a href="/groups/glfm_group/-/uploads/groups-test-file" data-canonical-src="/uploads/groups-test-file" data-link="true" class="gfm">groups-test-file</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uploads/groups-test-file">groups-test-file</a></p>
+ 06_02_00__api_request_overrides__project_repo_link__001:
+ canonical: |
+ <p><a href="projects-test-file">projects-test-file</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:40" dir="auto"><a href="/glfm_group/glfm_project/-/blob/master/projects-test-file">projects-test-file</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="projects-test-file">projects-test-file</a></p>
+ 06_03_00__api_request_overrides__project_snippet_ref__001:
+ canonical: |
+ <p>This project snippet ID reference IS filtered: <a href="/glfm_group/glfm_project/-/snippets/88888">$88888</a>
+ static: |-
+ <p data-sourcepos="1:1-1:53" dir="auto">This project snippet ID reference IS filtered: <a href="/glfm_group/glfm_project/-/snippets/88888" data-reference-type="snippet" data-original="$88888" data-link="false" data-link-reference="false" data-project="77777" data-snippet="88888" data-container="body" data-placement="top" title="glfm_project_snippet" class="gfm gfm-snippet has-tooltip">$88888</a></p>
+ wysiwyg: |-
+ <p>This project snippet ID reference IS filtered: $88888</p>
+ 06_04_00__api_request_overrides__personal_snippet_ref__001:
+ canonical: |
+ <p>This personal snippet ID reference is NOT filtered: $99999</p>
+ static: |-
+ <p data-sourcepos="1:1-1:58" dir="auto">This personal snippet ID reference is NOT filtered: $99999</p>
+ wysiwyg: |-
+ <p>This personal snippet ID reference is NOT filtered: $99999</p>
+ 06_05_00__api_request_overrides__project_wiki_link__001:
+ canonical: |
+ <p><a href="project-wikis-test-file">project-wikis-test-file</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:50" dir="auto"><a href="/glfm_group/glfm_project/-/wikis/project-wikis-test-file" data-canonical-src="project-wikis-test-file">project-wikis-test-file</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="project-wikis-test-file">project-wikis-test-file</a></p>
+ YAML
+ end
+
+ let(:expected_prosemirror_json_contents) do
+ <<~YAML
+ ---
+ 02_01_00__inlines__strong__001: |-
+ {
+ "type": "doc",
+ "content": [
+ {
+ "type": "paragraph",
+ "content": [
+ {
+ "type": "text",
+ "marks": [
+ {
+ "type": "bold"
+ }
+ ],
+ "text": "bold"
+ }
+ ]
+ }
+ ]
+ }
+ 02_03_00__inlines__strikethrough_extension__001: |-
+ {
+ "type": "doc",
+ "content": [
+ {
+ "type": "paragraph",
+ "content": [
+ {
+ "type": "text",
+ "marks": [
+ {
+ "type": "strike"
+ }
+ ],
+ "text": "Hi"
+ },
+ {
+ "type": "text",
+ "text": " Hello, world!"
+ }
+ ]
+ }
+ ]
+ }
+ 03_01_00__first_gitlab_specific_section_with_examples__strong_but_with_two_asterisks__001: |-
+ {
+ "type": "doc",
+ "content": [
+ {
+ "type": "paragraph",
+ "content": [
+ {
+ "type": "text",
+ "marks": [
+ {
+ "type": "bold"
+ }
+ ],
+ "text": "bold"
+ }
+ ]
+ }
+ ]
+ }
+ 03_02_01__first_gitlab_specific_section_with_examples__h2_which_contains_an_h3__example_in_an_h3__001: |-
+ {
+ "type": "doc",
+ "content": [
+ {
+ "type": "paragraph",
+ "content": [
+ {
+ "type": "text",
+ "text": "Example in an H3"
+ }
+ ]
+ }
+ ]
+ }
+ 04_01_00__second_gitlab_specific_section_with_examples__strong_but_with_html__001: |-
+ {
+ "existing": "This entry is manually modified and preserved because skip_update_example_snapshot_prosemirror_json will be truthy"
+ }
+ 05_02_00__third_gitlab_specific_section_with_skipped_examples__strong_but_manually_modified_and_skipped__001: |-
+ {
+ "existing": "This entry is manually modified and preserved because skip_update_example_snapshots will be truthy"
+ }
+ 06_01_00__api_request_overrides__group_upload_link__001: |-
+ {
+ "type": "doc",
+ "content": [
+ {
+ "type": "paragraph",
+ "content": [
+ {
+ "type": "text",
+ "marks": [
+ {
+ "type": "link",
+ "attrs": {
+ "href": "/uploads/groups-test-file",
+ "target": "_blank",
+ "class": null,
+ "title": null,
+ "canonicalSrc": "/uploads/groups-test-file",
+ "isReference": false
+ }
+ }
+ ],
+ "text": "groups-test-file"
+ }
+ ]
+ }
+ ]
+ }
+ 06_02_00__api_request_overrides__project_repo_link__001: |-
+ {
+ "type": "doc",
+ "content": [
+ {
+ "type": "paragraph",
+ "content": [
+ {
+ "type": "text",
+ "marks": [
+ {
+ "type": "link",
+ "attrs": {
+ "href": "projects-test-file",
+ "target": "_blank",
+ "class": null,
+ "title": null,
+ "canonicalSrc": "projects-test-file",
+ "isReference": false
+ }
+ }
+ ],
+ "text": "projects-test-file"
+ }
+ ]
+ }
+ ]
+ }
+ 06_03_00__api_request_overrides__project_snippet_ref__001: |-
+ {
+ "type": "doc",
+ "content": [
+ {
+ "type": "paragraph",
+ "content": [
+ {
+ "type": "text",
+ "text": "This project snippet ID reference IS filtered: $88888"
+ }
+ ]
+ }
+ ]
+ }
+ 06_04_00__api_request_overrides__personal_snippet_ref__001: |-
+ {
+ "type": "doc",
+ "content": [
+ {
+ "type": "paragraph",
+ "content": [
+ {
+ "type": "text",
+ "text": "This personal snippet ID reference is NOT filtered: $99999"
+ }
+ ]
+ }
+ ]
+ }
+ 06_05_00__api_request_overrides__project_wiki_link__001: |-
+ {
+ "type": "doc",
+ "content": [
+ {
+ "type": "paragraph",
+ "content": [
+ {
+ "type": "text",
+ "marks": [
+ {
+ "type": "link",
+ "attrs": {
+ "href": "project-wikis-test-file",
+ "target": "_blank",
+ "class": null,
+ "title": null,
+ "canonicalSrc": "project-wikis-test-file",
+ "isReference": false
+ }
+ }
+ ],
+ "text": "project-wikis-test-file"
+ }
+ ]
+ }
+ ]
+ }
+ YAML
+ end
- # NOTE: Both `html.yml` and `prosemirror_json.yml` generation are tested in a single example, to
- # avoid slower tests, because generating the static HTML is slow due to the need to invoke
- # the rails environment. We could have separate sections, but this would require an extra flag
- # to the `process` method to independently skip static vs. WYSIWYG, which is not worth the effort.
- it 'writes the correct content', :unlimited_max_formatted_output_length do
- # expectation that skipping message is only output once per example
- expect(subject).to receive(:output).once.with(/reason.*skipping this example because it is very bad/i)
+ # NOTE: Both `html.yml` and `prosemirror_json.yml` generation are tested in a single example, to
+ # avoid slower tests, because generating the static HTML is slow due to the need to invoke
+ # the rails environment. We could have separate sections, but this would require an extra flag
+ # to the `process` method to independently skip static vs. WYSIWYG, which is not worth the effort.
+ it 'writes the correct content', :unlimited_max_formatted_output_length do
+ # expectation that skipping message is only output once per example
+ expect(subject).to receive(:output).once.with(/reason.*skipping this example because it is very bad/i)
- subject.process
+ subject.process
- expect(es_html_yml_contents).to eq(expected_html_yml_contents)
- expect(es_prosemirror_json_yml_contents).to eq(expected_prosemirror_json_contents)
+ expect(es_html_yml_contents).to eq(expected_html_yml_contents)
+ expect(es_prosemirror_json_yml_contents).to eq(expected_prosemirror_json_contents)
+ end
end
end
# rubocop:enable RSpec/MultipleMemoizedHelpers
diff --git a/spec/scripts/lib/glfm/update_specification_spec.rb b/spec/scripts/lib/glfm/update_specification_spec.rb
index 9fb671e0016..852b2b580e6 100644
--- a/spec/scripts/lib/glfm/update_specification_spec.rb
+++ b/spec/scripts/lib/glfm/update_specification_spec.rb
@@ -1,21 +1,53 @@
# frozen_string_literal: true
+
require 'fast_spec_helper'
require_relative '../../../../scripts/lib/glfm/update_specification'
-
+require_relative '../../../support/helpers/next_instance_of'
+
+# IMPORTANT NOTE: See https://docs.gitlab.com/ee/development/gitlab_flavored_markdown/specification_guide/#update-specificationrb-script
+# for details on the implementation and usage of the `update_specification.rb` script being tested.
+# This developers guide contains diagrams and documentation of the script,
+# including explanations and examples of all files it reads and writes.
+#
+# Note that this test is not structured in a traditional way, with multiple examples
+# to cover all different scenarios. Instead, the content of the stubbed test fixture
+# files are crafted to cover multiple scenarios with in a single example run.
+#
+# This is because the invocation of the full script is slow, because it executes
+# a subshell for processing, which runs a full Rails environment.
+# This results in each full run of the script taking between 30-60 seconds.
+# The majority of this is spent loading the Rails environment.
+#
+# However, only the `with generation of spec.html` context is used
+# to test this slow sub-process, and it only contains one example.
+#
+# All other tests currently in the file pass the `skip_spec_html_generation: true`
+# flag to `#process`, which skips the slow sub-process. All of these other tests
+# should run in sub-second time when the Spring pre-loader is used. This allows
+# logic which is not directly related to the slow sub-processes to be TDD'd with a
+# very rapid feedback cycle.
RSpec.describe Glfm::UpdateSpecification, '#process' do
+ include NextInstanceOf
+
subject { described_class.new }
let(:ghfm_spec_txt_uri) { described_class::GHFM_SPEC_TXT_URI }
+ let(:ghfm_spec_txt_uri_parsed) { instance_double(URI::HTTPS, :ghfm_spec_txt_uri_parsed) }
let(:ghfm_spec_txt_uri_io) { StringIO.new(ghfm_spec_txt_contents) }
- let(:ghfm_spec_txt_path) { described_class::GHFM_SPEC_TXT_PATH }
+ let(:ghfm_spec_md_path) { described_class::GHFM_SPEC_MD_PATH }
let(:ghfm_spec_txt_local_io) { StringIO.new(ghfm_spec_txt_contents) }
- let(:glfm_intro_txt_path) { described_class::GLFM_INTRO_TXT_PATH }
- let(:glfm_intro_txt_io) { StringIO.new(glfm_intro_txt_contents) }
- let(:glfm_examples_txt_path) { described_class::GLFM_EXAMPLES_TXT_PATH }
- let(:glfm_examples_txt_io) { StringIO.new(glfm_examples_txt_contents) }
+ let(:glfm_intro_md_path) { described_class::GLFM_INTRO_MD_PATH }
+ let(:glfm_intro_md_io) { StringIO.new(glfm_intro_md_contents) }
+ let(:glfm_official_specification_examples_md_path) { described_class::GLFM_OFFICIAL_SPECIFICATION_EXAMPLES_MD_PATH }
+ let(:glfm_official_specification_examples_md_io) { StringIO.new(glfm_official_specification_examples_md_contents) }
+ let(:glfm_internal_extension_examples_md_path) { described_class::GLFM_INTERNAL_EXTENSION_EXAMPLES_MD_PATH }
+ let(:glfm_internal_extension_examples_md_io) { StringIO.new(glfm_internal_extension_examples_md_contents) }
let(:glfm_spec_txt_path) { described_class::GLFM_SPEC_TXT_PATH }
let(:glfm_spec_txt_io) { StringIO.new }
+ let(:glfm_spec_html_path) { described_class::GLFM_SPEC_HTML_PATH }
+ let(:glfm_spec_html_io) { StringIO.new }
+ let(:markdown_tempfile_io) { StringIO.new }
let(:ghfm_spec_txt_contents) do
<<~MARKDOWN
@@ -52,7 +84,7 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
MARKDOWN
end
- let(:glfm_intro_txt_contents) do
+ let(:glfm_intro_md_contents) do
# language=Markdown
<<~MARKDOWN
# Introduction
@@ -63,9 +95,17 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
MARKDOWN
end
- let(:glfm_examples_txt_contents) do
+ let(:glfm_official_specification_examples_md_contents) do
<<~MARKDOWN
- # GitLab-Specific Section with Examples
+ # Official Specification Section with Examples
+
+ Some examples.
+ MARKDOWN
+ end
+
+ let(:glfm_internal_extension_examples_md_contents) do
+ <<~MARKDOWN
+ # Internal Extension Section with Examples
Some examples.
MARKDOWN
@@ -73,44 +113,66 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
before do
# Mock default ENV var values
- allow(ENV).to receive(:[]).with('UPDATE_GHFM_SPEC_TXT').and_return(nil)
+ allow(ENV).to receive(:[]).with('UPDATE_GHFM_SPEC_MD').and_return(nil)
allow(ENV).to receive(:[]).and_call_original
# We mock out the URI and local file IO objects with real StringIO, instead of just mock
# objects. This gives better and more realistic coverage, while still avoiding
# actual network and filesystem I/O during the spec run.
- allow(URI).to receive(:open).with(ghfm_spec_txt_uri) { ghfm_spec_txt_uri_io }
- allow(File).to receive(:open).with(ghfm_spec_txt_path) { ghfm_spec_txt_local_io }
- allow(File).to receive(:open).with(glfm_intro_txt_path) { glfm_intro_txt_io }
- allow(File).to receive(:open).with(glfm_examples_txt_path) { glfm_examples_txt_io }
+
+ # input files
+ allow(URI).to receive(:parse).with(ghfm_spec_txt_uri).and_return(ghfm_spec_txt_uri_parsed)
+ allow(ghfm_spec_txt_uri_parsed).to receive(:open).and_return(ghfm_spec_txt_uri_io)
+ allow(File).to receive(:open).with(ghfm_spec_md_path) { ghfm_spec_txt_local_io }
+ allow(File).to receive(:open).with(glfm_intro_md_path) { glfm_intro_md_io }
+ allow(File).to receive(:open).with(glfm_official_specification_examples_md_path) do
+ glfm_official_specification_examples_md_io
+ end
+ allow(File).to receive(:open).with(glfm_internal_extension_examples_md_path) do
+ glfm_internal_extension_examples_md_io
+ end
+
+ # output files
allow(File).to receive(:open).with(glfm_spec_txt_path, 'w') { glfm_spec_txt_io }
+ allow(File).to receive(:open).with(glfm_spec_html_path, 'w') { glfm_spec_html_io }
+
+ # Allow normal opening of Tempfile files created during script execution.
+ tempfile_basenames = [
+ described_class::MARKDOWN_TEMPFILE_BASENAME[0],
+ described_class::STATIC_HTML_TEMPFILE_BASENAME[0]
+ ].join('|')
+ # NOTE: This approach with a single regex seems to be the only way this can work. If you
+ # attempt to have multiple `allow...and_call_original` with `any_args`, the mocked
+ # parameter matching will fail to match the second one.
+ tempfiles_regex = /(#{tempfile_basenames})/
+ allow(File).to receive(:open).with(tempfiles_regex, any_args).and_call_original
# Prevent console output when running tests
allow(subject).to receive(:output)
end
describe 'retrieving latest GHFM spec.txt' do
- context 'when UPDATE_GHFM_SPEC_TXT is not true (default)' do
+ context 'when UPDATE_GHFM_SPEC_MD is not true (default)' do
it 'does not download' do
- expect(URI).not_to receive(:open).with(ghfm_spec_txt_uri)
+ expect(URI).not_to receive(:parse).with(ghfm_spec_txt_uri)
- subject.process
+ subject.process(skip_spec_html_generation: true)
expect(reread_io(ghfm_spec_txt_local_io)).to eq(ghfm_spec_txt_contents)
end
end
- context 'when UPDATE_GHFM_SPEC_TXT is true' do
+ context 'when UPDATE_GHFM_SPEC_MD is true' do
let(:ghfm_spec_txt_local_io) { StringIO.new }
before do
- allow(ENV).to receive(:[]).with('UPDATE_GHFM_SPEC_TXT').and_return('true')
- allow(File).to receive(:open).with(ghfm_spec_txt_path, 'w') { ghfm_spec_txt_local_io }
+ allow(ENV).to receive(:[]).with('UPDATE_GHFM_SPEC_MD').and_return('true')
+ allow(File).to receive(:open).with(ghfm_spec_md_path, 'w') { ghfm_spec_txt_local_io }
end
context 'with success' do
it 'downloads and saves' do
- subject.process
+ subject.process(skip_spec_html_generation: true)
expect(reread_io(ghfm_spec_txt_local_io)).to eq(ghfm_spec_txt_contents)
end
@@ -128,7 +190,9 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
end
it 'raises an error' do
- expect { subject.process }.to raise_error /version mismatch.*expected.*29.*got.*30/i
+ expect do
+ subject.process(skip_spec_html_generation: true)
+ end.to raise_error /version mismatch.*expected.*29.*got.*30/i
end
end
@@ -136,7 +200,7 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
let(:ghfm_spec_txt_contents) { '' }
it 'raises an error if lines cannot be read' do
- expect { subject.process }.to raise_error /unable to read lines/i
+ expect { subject.process(skip_spec_html_generation: true) }.to raise_error /unable to read lines/i
end
end
@@ -146,7 +210,7 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
end
it 'raises an error if file is blank' do
- expect { subject.process }.to raise_error /unable to read string/i
+ expect { subject.process(skip_spec_html_generation: true) }.to raise_error /unable to read string/i
end
end
end
@@ -157,7 +221,7 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
let(:glfm_contents) { reread_io(glfm_spec_txt_io) }
before do
- subject.process
+ subject.process(skip_spec_html_generation: true)
end
it 'replaces the header text with the GitLab version' do
@@ -170,14 +234,18 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
it 'replaces the intro section with the GitLab version' do
expect(glfm_contents).not_to match(/What is GitHub Flavored Markdown/m)
- expect(glfm_contents).to match(/#{Regexp.escape(glfm_intro_txt_contents)}/m)
+ expect(glfm_contents).to match(/#{Regexp.escape(glfm_intro_md_contents)}/m)
end
- it 'inserts the GitLab examples sections before the appendix section' do
+ it 'inserts the GitLab official spec and internal extension examples sections before the appendix section' do
expected = <<~MARKDOWN
End of last GitHub examples section.
- # GitLab-Specific Section with Examples
+ # Official Specification Section with Examples
+
+ Some examples.
+
+ # Internal Extension Section with Examples
Some examples.
@@ -189,6 +257,51 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
end
end
+ describe 'writing GLFM spec.html' do
+ let(:glfm_contents) { reread_io(glfm_spec_html_io) }
+
+ before do
+ subject.process
+ end
+
+ it 'renders HTML from spec.txt', :unlimited_max_formatted_output_length do
+ expected = <<~HTML
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-4:3" class="code highlight js-syntax-highlight language-yaml" lang="yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="na">title</span><span class="pi">:</span> <span class="s">GitLab Flavored Markdown (GLFM) Spec</span></span>
+ <span id="LC2" class="line" lang="yaml"><span class="na">version</span><span class="pi">:</span> <span class="s">alpha</span></span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <h1 data-sourcepos="6:1-6:14" dir="auto">
+ <a id="user-content-introduction" class="anchor" href="#introduction" aria-hidden="true"></a>Introduction</h1>
+ <h2 data-sourcepos="8:1-8:36" dir="auto">
+ <a id="user-content-what-is-gitlab-flavored-markdown" class="anchor" href="#what-is-gitlab-flavored-markdown" aria-hidden="true"></a>What is GitLab Flavored Markdown?</h2>
+ <p data-sourcepos="10:1-10:42" dir="auto">Intro text about GitLab Flavored Markdown.</p>
+ <h1 data-sourcepos="12:1-12:23" dir="auto">
+ <a id="user-content-section-with-examples" class="anchor" href="#section-with-examples" aria-hidden="true"></a>Section with Examples</h1>
+ <h2 data-sourcepos="14:1-14:9" dir="auto">
+ <a id="user-content-strong" class="anchor" href="#strong" aria-hidden="true"></a>Strong</h2>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="16:1-20:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__bold__</span>
+ <span id="LC2" class="line" lang="plaintext">.</span>
+ <span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;bold&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="22:1-22:36" dir="auto">End of last GitHub examples section.</p>
+ <h1 data-sourcepos="24:1-24:46" dir="auto">
+ <a id="user-content-official-specification-section-with-examples" class="anchor" href="#official-specification-section-with-examples" aria-hidden="true"></a>Official Specification Section with Examples</h1>
+ <p data-sourcepos="26:1-26:14" dir="auto">Some examples.</p>
+ <h1 data-sourcepos="28:1-28:42" dir="auto">
+ <a id="user-content-internal-extension-section-with-examples" class="anchor" href="#internal-extension-section-with-examples" aria-hidden="true"></a>Internal Extension Section with Examples</h1>
+ <p data-sourcepos="30:1-30:14" dir="auto">Some examples.</p>
+
+ <h1 data-sourcepos="34:1-34:10" dir="auto">
+ <a id="user-content-appendix" class="anchor" href="#appendix" aria-hidden="true"></a>Appendix</h1>
+ <p data-sourcepos="36:1-36:14" dir="auto">Appendix text.</p>
+ HTML
+ expect(glfm_contents).to be == expected
+ end
+ end
+
def reread_io(io)
# Reset the io StringIO to the beginning position of the buffer
io.seek(0)
diff --git a/spec/scripts/lib/glfm/verify_all_generated_files_are_up_to_date_spec.rb b/spec/scripts/lib/glfm/verify_all_generated_files_are_up_to_date_spec.rb
new file mode 100644
index 00000000000..fca037c9ff3
--- /dev/null
+++ b/spec/scripts/lib/glfm/verify_all_generated_files_are_up_to_date_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+require 'fast_spec_helper'
+require_relative '../../../../scripts/lib/glfm/verify_all_generated_files_are_up_to_date'
+
+# IMPORTANT NOTE: See https://docs.gitlab.com/ee/development/gitlab_flavored_markdown/specification_guide/#verify-all-generated-files-are-up-to-daterb-script
+# for details on the implementation and usage of the `verify_all_generated_files_are_up_to_date.rb` script being tested.
+# This developers guide contains diagrams and documentation of the script,
+# including explanations and examples of all files it reads and writes.
+RSpec.describe Glfm::VerifyAllGeneratedFilesAreUpToDate, '#process' do
+ subject { described_class.new }
+
+ let(:output_path) { described_class::GLFM_SPEC_OUTPUT_PATH }
+ let(:snapshots_path) { described_class::EXAMPLE_SNAPSHOTS_PATH }
+ let(:verify_cmd) { "git status --porcelain #{output_path} #{snapshots_path}" }
+
+ before do
+ # Prevent console output when running tests
+ allow(subject).to receive(:output)
+ end
+
+ context 'when repo is dirty' do
+ before do
+ # Simulate a dirty repo
+ allow(subject).to receive(:run_external_cmd).with(verify_cmd).and_return(" M #{output_path}")
+ end
+
+ it 'raises an error', :unlimited_max_formatted_output_length do
+ expect { subject.process }.to raise_error(/Cannot run.*uncommitted changes.*#{output_path}/m)
+ end
+ end
+
+ context 'when repo is clean' do
+ before do
+ # Mock out all yarn install and script execution
+ allow(subject).to receive(:run_external_cmd).with('yarn install --frozen-lockfile')
+ allow(subject).to receive(:run_external_cmd).with(/update-specification.rb/)
+ allow(subject).to receive(:run_external_cmd).with(/update-example-snapshots.rb/)
+ end
+
+ context 'when all generated files are up to date' do
+ before do
+ # Simulate a clean repo, then simulate no changes to generated files
+ allow(subject).to receive(:run_external_cmd).twice.with(verify_cmd).and_return('', '')
+ end
+
+ it 'does not raise an error', :unlimited_max_formatted_output_length do
+ expect { subject.process }.not_to raise_error
+ end
+ end
+
+ context 'when generated file(s) are not up to date' do
+ before do
+ # Simulate a clean repo, then simulate changes to generated files
+ allow(subject).to receive(:run_external_cmd).twice.with(verify_cmd).and_return('', "M #{snapshots_path}")
+ end
+
+ it 'raises an error', :unlimited_max_formatted_output_length do
+ expect { subject.process }.to raise_error(/following files were modified.*#{snapshots_path}/m)
+ end
+ end
+ end
+end
diff --git a/spec/scripts/trigger-build_spec.rb b/spec/scripts/trigger-build_spec.rb
index 46023d5823d..ac8e3c7797c 100644
--- a/spec/scripts/trigger-build_spec.rb
+++ b/spec/scripts/trigger-build_spec.rb
@@ -21,8 +21,6 @@ RSpec.describe Trigger do
'GITLAB_USER_NAME' => 'gitlab_user_name',
'GITLAB_USER_LOGIN' => 'gitlab_user_login',
'QA_IMAGE' => 'qa_image',
- 'OMNIBUS_GITLAB_CACHE_UPDATE' => 'omnibus_gitlab_cache_update',
- 'OMNIBUS_GITLAB_PROJECT_ACCESS_TOKEN' => nil,
'DOCS_PROJECT_API_TOKEN' => nil
}
end