summaryrefslogtreecommitdiff
path: root/tooling/bin/find_changes
blob: 8ad5011459bb8fe1d207f8612038829d2b0845b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env ruby
# frozen_string_literal: true

require 'gitlab'

class FindChanges # rubocop:disable Gitlab/NamespacedClass
  def initialize(output_file:, matched_tests_file: nil, frontend_fixtures_mapping_path: nil)
    @gitlab_token = ENV.fetch('PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE', '')
    @gitlab_endpoint = ENV.fetch('CI_API_V4_URL')
    @mr_project_path = ENV.fetch('CI_MERGE_REQUEST_PROJECT_PATH')
    @mr_iid = ENV.fetch('CI_MERGE_REQUEST_IID')
    @output_file = output_file
    @matched_tests_file = matched_tests_file
    @frontend_fixtures_mapping_path = frontend_fixtures_mapping_path
  end

  def execute
    add_frontend_fixture_files!

    File.write(output_file, file_changes.join(' '))
  end

  private

  def add_frontend_fixture_files?
    matched_tests_file && frontend_fixtures_mapping_path
  end

  def add_frontend_fixture_files!
    return unless add_frontend_fixture_files?

    # If we have a `test file -> JSON frontend fixture` mapping file, we add the files JSON frontend fixtures
    # files to the list of changed files so that Jest can automatically run the dependent tests thanks to --findRelatedTests
    test_files.each do |test_file|
      file_changes.concat(frontend_fixtures_mapping[test_file]) if frontend_fixtures_mapping.key?(test_file)
    end
  end

  def file_changes
    @file_changes ||=
      if File.exist?(output_file)
        File.read(output_file).split(' ')
      else
        Gitlab.configure do |config|
          config.endpoint      = gitlab_endpoint
          config.private_token = gitlab_token
        end

        mr_changes = Gitlab.merge_request_changes(mr_project_path, mr_iid)

        mr_changes.changes.map { |change| change['new_path'] unless change['deleted_file'] }.compact
      end
  end

  def test_files
    return [] if !matched_tests_file || !File.exist?(matched_tests_file)

    File.read(matched_tests_file).split(' ')
  end

  def frontend_fixtures_mapping
    return {} if !frontend_fixtures_mapping_path || !File.exist?(frontend_fixtures_mapping_path)

    JSON.parse(File.read(frontend_fixtures_mapping_path)) # rubocop:disable Gitlab/Json
  end

  attr_reader :gitlab_token, :gitlab_endpoint, :mr_project_path, :mr_iid, :output_file, :matched_tests_file, :frontend_fixtures_mapping_path
end

output_file = ARGV.shift
raise ArgumentError, "An path to an output file must be given as first argument of #{__FILE__}." if output_file.nil?

matched_tests_file = ARGV.shift
frontend_fixtures_mapping_path = ARGV.shift

FindChanges
  .new(output_file: output_file, matched_tests_file: matched_tests_file, frontend_fixtures_mapping_path: frontend_fixtures_mapping_path)
  .execute