18F/identity-idp

View on GitHub
Makefile

Summary

Maintainability
Test Coverage
# Makefile for building and running the project.
# The purpose of this Makefile is to avoid developers having to remember
# project-specific commands for building, running, etc.  Recipes longer
# than one or two lines should live in script files of their own in the
# bin/ directory.

CONFIG = config/application.yml
HOST ?= localhost
PORT ?= 3000
GZIP_COMMAND ?= gzip
ARTIFACT_DESTINATION_FILE ?= ./tmp/idp.tar.gz

.PHONY: \
    analytics_events \
    audit \
    brakeman \
    build_artifact \
    check \
    clobber_db \
    clobber_assets \
    clobber_logs \
    watch_events \
    download_acuant_sdk \
    help \
    lint \
    lint_analytics_events \
    lint_analytics_events_sorted \
    lint_country_dialing_codes \
    lint_database_schema_files \
    lint_erb \
    lint_font_glyphs \
    lint_lockfiles \
    lint_new_typescript_files \
    lint_optimized_assets \
    lint_yaml \
    lint_yarn_workspaces \
    lint_asset_bundle_size \
    lint_readme \
    lint_spec_file_name \
    lintfix \
    normalize_yaml \
    optimize_assets \
    optimize_svg \
    run \
    tidy \
    update \
    urn \
    README.md \
    setup \
    test \
    update_pinpoint_supported_countries

help: ## Show this help
    @echo "--- Help ---"
    @ruby lib/makefile_help_parser.rb

all: check

setup $(CONFIG): config/application.yml.default ## Runs setup scripts (updates packages, dependencies, databases, etc)
    bin/setup

check: lint test ## Runs lint tests and spec tests

lint: ## Runs all lint tests
    # Ruby
    @echo "--- erb-lint ---"
    make lint_erb
    @echo "--- rubocop ---"
ifdef JUNIT_OUTPUT
    bundle exec rubocop --parallel --format progress --format junit --out rubocop.xml --display-only-failed
else
    bundle exec rubocop --parallel
endif
    @echo "--- analytics_events ---"
    make lint_analytics_events
    make lint_analytics_events_sorted
    @echo "--- brakeman ---"
    make brakeman
    # JavaScript
    @echo "--- eslint ---"
    yarn run lint
    @echo "--- typescript ---"
    yarn run typecheck
    # Other
    @echo "--- lint yaml ---"
    make lint_yaml
    @echo "--- lint font glyphs ---"
    make lint_font_glyphs
    @echo "--- lint Yarn workspaces ---"
    make lint_yarn_workspaces
    @echo "--- lint new TypeScript files ---"
    make lint_new_typescript_files
    @echo "--- lint lockfiles ---"
    make lint_lockfiles
    @echo "--- check assets are optimized ---"
    make lint_optimized_assets
    @echo "--- stylelint ---"
    yarn lint:css
    @echo "--- README.md ---"
    make lint_readme
    @echo "--- lint spec file names ---"
    make lint_spec_file_name
    @echo "--- lint migrations ---"
    make lint_migrations

audit: ## Checks packages for vulnerabilities
    @echo "--- bundler-audit ---"
    bundle exec bundler-audit check --update
    @echo "--- yarn audit ---"
    yarn audit --groups dependencies; test $$? -le 7

lint_erb: ## Lints ERB files
    bundle exec erblint app/views app/components

lint_yaml: normalize_yaml ## Lints YAML files
    (! git diff --name-only | grep "^config/.*\.yml$$") || (echo "Error: Run 'make normalize_yaml' to normalize YAML"; exit 1)

lint_font_glyphs: ## Lints to validate content glyphs match expectations from fonts
    scripts/yaml_characters \
        --exclude-locale=zh \
        --exclude-gem-path=faker \
        --exclude-gem-path=good_job \
        --exclude-gem-path=i18n-tasks \
        > app/assets/fonts/glyphs.txt
    (! git diff --name-only | grep "glyphs\.txt$$") || (echo "Error: New character data found. Follow 'Fonts' instructions in 'docs/frontend.md' to regenerate fonts."; exit 1)

lint_yarn_workspaces: ## Lints Yarn workspace packages
    scripts/validate-workspaces.mjs

lint_asset_bundle_size: ## Lints JavaScript and CSS compiled bundle size
    @# This enforces an asset size budget to ensure that download sizes are reasonable and to protect
    @# against accidentally importing large pieces of third-party libraries. If you're here debugging
    @# a failing build, check to ensure that you've not added more JavaScript or CSS than necessary,
    @# and you have no options to split that from the common bundles. If you need to increase this
    @# budget and accept the fact that this will force end-users to endure longer load times, you
    @# should set the new budget to within a few thousand bytes of the production-compiled size.
    find app/assets/builds/application.css -size -185000c | grep .
    find public/packs/application-*.digested.js -size -5000c | grep .

lint_migrations:
    scripts/migration_check

lint_gemfile_lock: Gemfile Gemfile.lock ## Lints the Gemfile and its lockfile
    @bundle check
    @git diff-index --quiet HEAD Gemfile.lock || (echo "Error: There are uncommitted changes after running 'bundle install'"; exit 1)

lint_yarn_lock: package.json yarn.lock ## Lints the package.json and its lockfile
    @yarn install --ignore-scripts
    @(! git diff --name-only | grep yarn.lock) || (echo "Error: There are uncommitted changes after running 'yarn install'"; exit 1)

lint_lockfiles: lint_gemfile_lock lint_yarn_lock ## Lints to ensure lockfiles are in sync

lint_new_typescript_files:
    scripts/enforce-typescript-files.mjs

lint_readme: README.md ## Lints README.md
    (! git diff --name-only | grep "^README.md$$") || (echo "Error: Run 'make README.md' to regenerate the README.md"; exit 1)

lint_spec_file_name:
    @find spec/*/** -type f \
        -name '*.rb' \
        -and -not -name '*_spec.rb' \
        -and -not -path 'spec/factories/*' \
        -and -not -path 'spec/support/*' \
        -and -not -path '*/previews/*' \
        -exec false {} + \
        -exec echo "Error: Spec files named incorrectly, should end in '_spec.rb':" {} +
    @find app/javascript/packages -type f \
        "(" -name '*spec.js' -or -name '*spec.ts' -or -name '*spec.jsx' -or -name '*spec.tsx' ")" \
        -and -not \
        "(" -name '*.spec.js' -or -name '*.spec.ts' -or -name '*.spec.jsx' -or -name '*.spec.tsx' ")" \
        -exec false {} + \
        -exec echo "Error: Spec files named incorrectly, should end in '.spec.(js|ts|jsx|tsx)':" {} +

lintfix: ## Try to automatically fix any Ruby, ERB, JavaScript, YAML, or CSS lint errors
    @echo "--- rubocop fix ---"
    bundle exec rubocop -a
    @echo "--- erblint fix ---"
    bundle exec erblint app/views app/components -a
    @echo "--- eslint fix ---"
    yarn lint --fix
    @echo "--- stylelint fix ---"
    yarn lint:css --fix
    @echo "--- normalize yaml ---"
    make normalize_yaml

brakeman: ## Runs brakeman code security check
    (bundle exec brakeman) || (echo "Error: update code as needed to remove security issues. For known exceptions already in brakeman.ignore, use brakeman to interactively update exceptions."; exit 1)

public/packs/manifest.json: yarn.lock $(shell find app/javascript -type f) ## Builds JavaScript assets
    yarn build:js

browsers.json: yarn.lock .browserslistrc ## Generates browsers.json browser support file
    yarn generate-browsers-json

test: export RAILS_ENV := test
test: $(CONFIG) ## Runs RSpec and yarn tests
    bundle exec rspec && yarn test

test_serial: export RAILS_ENV := test
test_serial: $(CONFIG) ## Runs RSpec and yarn tests serially
    bundle exec rake spec && yarn test

tmp/$(HOST)-$(PORT).key tmp/$(HOST)-$(PORT).crt: ## Self-signed cert for local HTTPS development
    mkdir -p tmp
    openssl req \
        -newkey rsa:2048 \
        -x509 \
        -sha256 \
        -nodes \
        -days 365 \
        -subj "/C=US/ST=District of Columbia/L=Washington/O=GSA/OU=Login.gov/CN=$(HOST):$(PORT)"  \
        -keyout tmp/$(HOST)-$(PORT).key \
        -out tmp/$(HOST)-$(PORT).crt

run: browsers.json ## Runs the development server
    foreman start -p $(PORT)

urn:
    @echo "⚱️"
    make run

run-https: tmp/$(HOST)-$(PORT).key tmp/$(HOST)-$(PORT).crt ## Runs the development server with HTTPS
    HTTPS=on FOREMAN_HOST="ssl://$(HOST):$(PORT)?key=tmp/$(HOST)-$(PORT).key&cert=tmp/$(HOST)-$(PORT).crt" foreman start -p $(PORT)

normalize_yaml: ## Normalizes YAML files (alphabetizes keys, fixes line length, smart quotes)
    yarn normalize-yaml .rubocop.yml --disable-sort-keys --disable-smart-punctuation
    find ./config/locales/transliterate -type f -name '*.yml' -exec yarn normalize-yaml --disable-sort-keys --disable-smart-punctuation {} \;
    find ./config/locales/telephony -type f -name '*.yml' | xargs yarn normalize-yaml --disable-smart-punctuation
    find ./config/locales -not \( -path "./config/locales/telephony*" -o -path "./config/locales/transliterate/*" \) -type f -name '*.yml' | \
    xargs yarn normalize-yaml \
        config/pinpoint_supported_countries.yml \
        config/pinpoint_overrides.yml \
        config/country_dialing_codes.yml

optimize_svg: ## Optimizes SVG images
    # Exclusions:
    # - `login-icon-bimi.svg` is hand-optimized and includes required metadata that would be stripped by SVGO
    find app/assets/images public -name '*.svg' -not -name 'login-icon-bimi.svg' | xargs ./node_modules/.bin/svgo

optimize_assets: optimize_svg ## Optimizes all assets

lint_optimized_assets: optimize_assets ## Checks that assets are optimized
    (! git diff --name-only | grep "\.svg$$") || (echo "Error: Optimize assets using 'make optimize_assets'"; exit 1)

update_pinpoint_supported_countries: ## Updates list of countries supported by Pinpoint for voice and SMS
    bundle exec ./scripts/pinpoint-supported-countries > config/pinpoint_supported_countries.yml
    bundle exec ./scripts/deep-merge-yaml \
        --comment 'Generated from `make update_pinpoint_supported_countries`' \
        --sources \
        -- \
        config/pinpoint_supported_countries.yml \
        config/pinpoint_overrides.yml \
        > config/country_dialing_codes.yml
    yarn normalize-yaml config/country_dialing_codes.yml config/pinpoint_supported_countries.yml

lint_country_dialing_codes: update_pinpoint_supported_countries ## Checks that countries supported by Pinpoint for voice and SMS are up to date
    (! git diff --name-only | grep config/country_dialing_codes.yml) || (echo "Error: Run 'make update_pinpoint_supported_countries' to update country codes"; exit 1)

lint_database_schema_files: ## Checks that database schema files have not changed
    (! git diff --name-only | grep db/schema.rb) || (echo "Error: db/schema.rb does not match after running migrations"; exit 1)
    (! git diff --name-only | grep db/worker_jobs_schema.rb) || (echo "Error: db/worker_jobs_schema.rb does not match after running migrations"; exit 1)

build_artifact $(ARTIFACT_DESTINATION_FILE): ## Builds zipped tar file artifact with IDP source code and Ruby/JS dependencies
    @echo "Building artifact into $(ARTIFACT_DESTINATION_FILE)"
    bundle config set --local cache_all true
    bundle package
    tar \
      --exclude './config/agencies.yml' \
      --exclude './config/iaa_gtcs.yml' \
      --exclude './config/iaa_orders.yml' \
      --exclude './config/iaa_statuses.yml' \
      --exclude './config/integration_statuses.yml' \
      --exclude './config/integrations.yml' \
      --exclude './config/partner_account_statuses.yml' \
      --exclude './config/partner_accounts.yml' \
      --exclude './config/service_providers.yml' \
      --exclude='./certs/sp' \
      --exclude='./identity-idp-config' \
      --exclude='./tmp' \
      --exclude='./log' \
      --exclude='./app/javascript/packages/**/node_modules' \
      --exclude='./node_modules' \
      --exclude='./geo_data/GeoLite2-City.mmdb' \
      --exclude='./pwned_passwords/pwned_passwords.txt' \
      --exclude='./vendor/ruby' \
      --exclude='./config/application.yml' \
      -cf - "." | "$(GZIP_COMMAND)" > $(ARTIFACT_DESTINATION_FILE)

analytics_events: public/api/_analytics-events.json ## Generates a JSON file that documents analytics events for events.log

lint_analytics_events: .yardoc ## Checks that all methods on AnalyticsEvents are documented
    bundle exec ruby lib/analytics_events_documenter.rb --class-name="AnalyticsEvents" --check $<

lint_analytics_events_sorted:
    @test "$(shell grep '^  def ' app/services/analytics_events.rb)" = "$(shell grep '^  def ' app/services/analytics_events.rb | sort)" \
        || (echo '\033[1;31mError: methods in analytics_events.rb are not sorted alphabetically\033[0m' && exit 1)

public/api/_analytics-events.json: .yardoc .yardoc/objects/root.dat
    mkdir -p public/api
    bundle exec ruby lib/analytics_events_documenter.rb --class-name="AnalyticsEvents" --json $< > $@

.yardoc .yardoc/objects/root.dat: app/services/analytics_events.rb
    bundle exec yard doc \
        --fail-on-warning \
        --type-tag identity.idp.previous_event_name:"Previous Event Name" \
        --no-output \
        --db $@ \
        -- $^

update: ## Update dependencies, useful after a git pull
    bundle install
    yarn install
    bundle exec rails db:migrate

README.md: docs/ ## Generates README.md based on the contents of the docs directory
    bundle exec ruby scripts/generate_readme.rb --docs-dir $< > $@

download_acuant_sdk: ## Downloads the most recent Acuant SDK release from Github
    @scripts/download_acuant_sdk.sh

clobber_db: ## Resets the database for make setup
    bin/rake db:create
    bin/rake db:environment:set
    bin/rake db:reset
    bin/rake db:environment:set
    bin/rake dev:prime

clobber_assets: ## Removes (clobbers) assets
    bin/rake assets:clobber
    RAILS_ENV=test bin/rake assets:clobber

clobber_logs: ## Purges logs and tmp/
    rm -f log/*
    rm -rf tmp/cache/*
    rm -rf tmp/encrypted_doc_storage
    rm -rf tmp/letter_opener
    rm -rf tmp/mails

watch_events: ## Prints events logging as they happen
    @tail -F -n0 log/events.log | jq "select(.name | test(\".*$$EVENT_NAME.*\"; \"i\")) | ."

tidy: clobber_assets clobber_logs ## Remove assets, logs, and unused gems, but leave DB alone
    bundle clean