Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,8 @@ normalize_yaml:
i18n-tasks normalize
find ./config/locales -type f | xargs ./scripts/normalize-yaml

check_asset_strings:
find ./app/javascript -name "*.js*" | xargs ./scripts/check-assets

generate_deploy_checklist:
ruby lib/release_management/generate_deploy_checklist.rb
37 changes: 37 additions & 0 deletions lib/asset_checker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
class AssetChecker
def self.check_files(argv)
assets_file = 'app/assets/javascripts/assets.js.erb'
translations_file = 'app/assets/javascripts/i18n-strings.js.erb'
@asset_strings = load_included_strings(assets_file)
@translation_strings = load_included_strings(translations_file)
argv.any? { |f| file_has_missing?(f) }
end

def self.file_has_missing?(file)
data = File.open(file).read
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally prefer:

data = File.read(file)

but not a huge deal

missing_translations = find_missing(data, /\Wt\s?\(['"]([^'^"]*)['"]\)/, @translation_strings)
missing_assets = find_missing(data, /\WassetPath=["'](.*)['"]/, @asset_strings)
has_missing = (missing_translations.any? || missing_assets.any?)
if has_missing
warn file
missing_translations.each do |t|
warn "Missing translation, #{t}"
end
missing_assets.each do |a|
warn "Missing asset, #{a}"
end
Comment on lines 16 to 22
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depending how this checker could be integrated into e.g. continuous integration, might it be worth raising an exception, or otherwise ensuring that the script exits with a non-zero exit code, so that it can be treated as a failure?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added 👍

end
has_missing
end

def self.find_missing(file_data, pattern, source)
strings = (file_data.scan pattern).flatten
strings.reject { |s| source.include? s }
end

def self.load_included_strings(file)
data = File.open(file).read
key_data = data.split('<% keys = [')[1].split('] %>')[0]
key_data.scan(/['"](.*)['"]/).flatten
end
end
6 changes: 6 additions & 0 deletions scripts/check-assets
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env ruby
$LOAD_PATH.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
require 'asset_checker'

exit(AssetChecker.check_files(ARGV) ? 1 : 0)

81 changes: 81 additions & 0 deletions spec/lib/asset_checker_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
require 'asset_checker'

def get_js_with_strings(asset, translation)
"
import React from 'react';
import AcuantCapture from './acuant-capture';
import DocumentTips from './document-tips';
import Image from './image';
import useI18n from '../hooks/use-i18n';

function DocumentCapture() {
const t = useI18n();

const sample = (
<Image
assetPath=\"#{asset}\"
alt=\"Sample front of state issued ID\"
width={450}
height={338}
/>
);

return (
<>
<h2>{t('#{translation}')}</h2>
<DocumentTips sample={sample} />
<AcuantCapture />
</>
);
}

export default DocumentCapture;
"
end

RSpec.describe AssetChecker do
describe '.check_files' do
let(:translation_strings) { %w[first_translation second_translation] }
let(:asset_strings) { %w[first_asset.png second_asset.gif] }

context 'with matching assets' do
let(:tempfile) { Tempfile.new }

before do
File.open(tempfile.path, 'w') do |f|
f.puts(get_js_with_strings('first_asset.png', 'first_translation'))
end
end

after { tempfile.unlink }

it 'identifies no issues ' do
allow(AssetChecker).to receive(:load_included_strings).and_return(asset_strings,
translation_strings)

expect(AssetChecker.check_files([tempfile.path])).to eq(false)
end
end

context 'with an asset mismatch' do
let(:tempfile) { Tempfile.new }

before do
File.open(tempfile.path, 'w') do |f|
f.puts(get_js_with_strings('wont_find.svg', 'not-found'))
end
end

after { tempfile.unlink }

it 'identifies issues' do
allow(AssetChecker).to receive(:load_included_strings).and_return(asset_strings,
translation_strings)
expect(AssetChecker).to receive(:warn).with(tempfile.path)
expect(AssetChecker).to receive(:warn).with('Missing translation, not-found')
expect(AssetChecker).to receive(:warn).with('Missing asset, wont_find.svg')
expect(AssetChecker.check_files([tempfile.path])).to eq(true)
end
end
end
end