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

assets.rake « gitlab « tasks « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: b8a6e7018767fd6d2c837f1ce2a608f416e9351e (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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# frozen_string_literal: true

module Tasks
  module Gitlab
    module Assets
      FOSS_ASSET_FOLDERS = %w[app/assets fixtures/emojis vendor/assets].freeze
      EE_ASSET_FOLDERS = %w[ee/app/assets].freeze
      JH_ASSET_FOLDERS = %w[jh/app/assets].freeze
      # In the new caching strategy, we check the assets hash sum *before* compiling
      # the app/assets/javascripts/locale/**/app.js files. That means the hash sum
      # must depend on locale/**/gitlab.po.
      JS_ASSET_PATTERNS = %w[*.js config/**/*.js locale/**/gitlab.po].freeze
      JS_ASSET_FILES = %w[
        package.json
        yarn.lock
        babel.config.js
        config/webpack.config.js
        .nvmrc
      ].freeze
      # Ruby gems might emit assets which have an impact on compilation
      # or have a direct impact on asset compilation (e.g. scss) and therefore
      # we should compile when these change
      RAILS_ASSET_FILES = %w[
        Gemfile
        Gemfile.lock
      ].freeze
      EXCLUDE_PATTERNS = %w[
        app/assets/javascripts/locale/**/app.js
      ].freeze
      PUBLIC_ASSETS_DIR = 'public/assets'
      HEAD_ASSETS_SHA256_HASH_ENV = 'GITLAB_ASSETS_HASH'
      CACHED_ASSETS_SHA256_HASH_FILE = 'cached-assets-hash.txt'

      def self.master_assets_sha256
        @master_assets_sha256 ||=
          if File.exist?(Tasks::Gitlab::Assets::CACHED_ASSETS_SHA256_HASH_FILE)
            File.read(Tasks::Gitlab::Assets::CACHED_ASSETS_SHA256_HASH_FILE)
          else
            'missing!'
          end
      end

      def self.head_assets_sha256
        @head_assets_sha256 ||= ENV.fetch(Tasks::Gitlab::Assets::HEAD_ASSETS_SHA256_HASH_ENV) do
          Tasks::Gitlab::Assets.sha256_of_assets_impacting_compilation(verbose: false)
        end
      end

      def self.sha256_of_assets_impacting_compilation(verbose: true)
        start_time = Time.now
        asset_files = assets_impacting_compilation
        puts "Generating the SHA256 hash for #{asset_files.size} Webpack-related assets..." if verbose

        assets_sha256 = asset_files.map { |asset_file| Digest::SHA256.file(asset_file).hexdigest }.join

        Digest::SHA256.hexdigest(assets_sha256).tap { |sha256| puts "=> SHA256 generated in #{Time.now - start_time}: #{sha256}" if verbose }
      end

      # Files listed here should match the list in:
      # .assets-compilation-patterns in .gitlab/ci/rules.gitlab-ci.yml
      # So we make sure that any impacting changes we do rebuild cache
      def self.assets_impacting_compilation
        assets_folders = FOSS_ASSET_FOLDERS
        assets_folders += EE_ASSET_FOLDERS if ::Gitlab.ee?
        assets_folders += JH_ASSET_FOLDERS if ::Gitlab.jh?

        asset_files = Dir.glob(JS_ASSET_PATTERNS)
        asset_files += JS_ASSET_FILES
        asset_files += RAILS_ASSET_FILES

        assets_folders.each do |folder|
          asset_files.concat(Dir.glob(["#{folder}/**/*.*"]))
        end

        asset_files - Dir.glob(EXCLUDE_PATTERNS)
      end
      private_class_method :assets_impacting_compilation
    end
  end
end

namespace :gitlab do
  namespace :assets do
    desc 'GitLab | Assets | Return the hash sum of all frontend assets'
    task :hash_sum do
      print Tasks::Gitlab::Assets.sha256_of_assets_impacting_compilation(verbose: false)
    end

    desc 'GitLab | Assets | Compile all frontend assets'
    task :compile do
      require 'fileutils'

      require_dependency 'gitlab/task_helpers'

      puts "Assets SHA256 for `master`: #{Tasks::Gitlab::Assets.master_assets_sha256.inspect}"
      puts "Assets SHA256 for `HEAD`: #{Tasks::Gitlab::Assets.head_assets_sha256.inspect}"

      if Tasks::Gitlab::Assets.head_assets_sha256 != Tasks::Gitlab::Assets.master_assets_sha256
        FileUtils.rm_rf([Tasks::Gitlab::Assets::PUBLIC_ASSETS_DIR] + Dir.glob('app/assets/javascripts/locale/**/app.js'))

        # gettext:compile needs to run before rake:assets:precompile because
        # app/assets/javascripts/locale/**/app.js are pre-compiled by Sprockets
        Gitlab::TaskHelpers.invoke_and_time_task('gettext:compile')
        Gitlab::TaskHelpers.invoke_and_time_task('rake:assets:precompile')

        log_path = ENV['WEBPACK_COMPILE_LOG_PATH']

        cmd = 'yarn webpack'
        cmd += " > #{log_path}" if log_path

        unless system(cmd)
          abort 'Error: Unable to compile webpack production bundle.'.color(:red)
        end

        puts "Written webpack stdout log to #{log_path}" if log_path
        puts "You can inspect the webpack log here: #{ENV['CI_JOB_URL']}/artifacts/file/#{log_path}" if log_path && ENV['CI_JOB_URL']

        Gitlab::TaskHelpers.invoke_and_time_task('gitlab:assets:fix_urls')
        Gitlab::TaskHelpers.invoke_and_time_task('gitlab:assets:check_page_bundle_mixins_css_for_sideeffects')
      end
    end

    desc 'GitLab | Assets | Clean up old compiled frontend assets'
    task clean: ['rake:assets:clean']

    desc 'GitLab | Assets | Remove all compiled frontend assets'
    task purge: ['rake:assets:clobber']

    desc 'GitLab | Assets | Uninstall frontend dependencies'
    task purge_modules: ['yarn:clobber']

    desc 'GitLab | Assets | Fix all absolute url references in CSS'
    task :fix_urls do
      css_files = Dir['public/assets/*.css']
      css_files.each do |file|
        # replace url(/assets/*) with url(./*)
        puts "Fixing #{file}"
        system "sed", "-i", "-e", 's/url(\([\"\']\?\)\/assets\//url(\1.\//g', file

        # rewrite the corresponding gzip file (if it exists)
        gzip = "#{file}.gz"
        next unless File.exist?(gzip)

        puts "Fixing #{gzip}"

        FileUtils.rm(gzip)
        mtime = File.stat(file).mtime

        File.open(gzip, 'wb+') do |f|
          gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION)
          gz.mtime = mtime
          gz.write File.binread(file)
          gz.close

          File.utime(mtime, mtime, f.path)
        end
      end
    end

    desc 'GitLab | Assets | Compile vendor assets'
    task :vendor do
      unless system('yarn webpack-vendor')
        abort 'Error: Unable to compile webpack DLL.'.color(:red)
      end
    end

    desc 'GitLab | Assets | Check that scss mixins do not introduce any sideffects'
    task :check_page_bundle_mixins_css_for_sideeffects do
      unless system('./scripts/frontend/check_page_bundle_mixins_css_for_sideeffects.js')
        abort 'Error: At least one CSS changes introduces an unwanted sideeffect'.color(:red)
      end
    end
  end
end