chore: Speed up compilation in CI

This commit is contained in:
Robert Prehn 2021-04-24 11:20:17 -05:00
parent 5ff02b80c3
commit 79d68fb144
5 changed files with 96 additions and 4 deletions

View file

@ -1,5 +1,3 @@
_build
deps
cover
.elixir_ls
*.dump

View file

@ -18,6 +18,10 @@ variables:
test:
stage: test
image: "elixir:1.10"
cache:
paths:
- _build/
- deps/
services:
- name: postgres:12
script: script/cibuild
@ -27,9 +31,14 @@ build_image_for_commit:
image: "docker:20.10"
only:
- master
cache:
paths:
- _build/
- deps/
services:
- name: docker:20.10-dind
script:
- script/ci/restore-timestamps
- docker login "https://${CI_REGISTRY}" -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD
- docker pull $CI_REGISTRY_IMAGE:latest || true
# This enables fast parallel builds
@ -38,6 +47,9 @@ build_image_for_commit:
# Push the commit SHA tagged version to registry. We will later choose to tag that as stable
# if everything passes.
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
# Pull out the built _build/prod directory so we can cache it!
- docker cp `docker create $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA`:/root/app/_build/prod _build
- script/ci/restore-timestamps
# If tests pass, tag the commit and update package versions
deploy_to_tags:

View file

@ -26,16 +26,18 @@ ADD ./apps/admin/mix.exs /root/app/apps/admin/
ADD ./apps/app/mix.exs /root/app/apps/app/
ADD ./apps/content/mix.exs /root/app/apps/content/
ADD ./apps/core/mix.exs /root/app/apps/core/
ADD ./_build/ /root/app/_build/
ADD ./deps/ /root/app/deps/
RUN mix deps.get
RUN mix deps.compile
ADD ./apps /root/app/apps
# Leave off here so that we can built assets and compile the elixir app in parallel
FROM node:15.0
# Build assets in a node container
ADD ./apps/app/assets/ /root/app/apps/app/assets/
WORKDIR /root/app/apps/app/assets/
COPY --from=0 /root/app/ /root/app/
RUN npm install
@ -43,6 +45,8 @@ RUN npm run deploy
FROM elixir1
ADD ./apps /root/app/apps
# Resume compilation of the elixir app
ADD ./script /root/app/script
RUN MAKE=cmake mix compile

74
script/ci/restore-timestamps Executable file
View file

@ -0,0 +1,74 @@
#!/usr/bin/env elixir
defmodule TimestampRestorer do
@environment System.get_env("MIX_ENV", "dev")
@db_path "_build/#{@environment}/timestamp-database"
def sha_all do
timestamp_database = load_timestamp_database()
"**/*.{ex,exs,beam}"
|> Path.wildcard()
|> Enum.reduce(%{}, fn filename, acc ->
{sha, timestamp} = process(filename, timestamp_database)
Map.put(acc, sha, timestamp)
end)
|> write_timestamp_database()
end
defp load_timestamp_database() do
if File.exists?(@db_path) do
@db_path
|> File.read!()
|> String.split("\n")
|> Enum.reduce(%{}, fn line, acc ->
[sha, timestamp_string] = String.split(line, ":")
{timestamp, ""} = Integer.parse(timestamp_string)
Map.put(acc, sha, timestamp)
end)
else
%{}
end
end
defp write_timestamp_database(database) do
database
|> Enum.map(fn {key, value} -> "#{key}:#{value}" end)
|> Enum.join("\n")
|> (& File.write!(@db_path, &1)).()
end
defp process(filename, timestamp_database) do
sha = sha(filename)
{:ok, %{mtime: new_timestamp}} = File.lstat(filename, time: :posix)
case Map.get(timestamp_database, sha) do
nil ->
:logger.debug("[NEW SHA ] #{filename}: #{new_timestamp}")
timestamp when timestamp < new_timestamp ->
:logger.debug("[RESTORED ] #{filename}: #{timestamp}")
File.touch(filename, timestamp)
timestamp when timestamp >= new_timestamp ->
:logger.debug("[UNCHANGED] #{filename}: #{timestamp}")
end
{sha, new_timestamp}
end
defp sha(filename) do
hash_ref = :crypto.hash_init(:sha)
File.stream!(filename)
|> Enum.reduce(hash_ref, fn chunk, prev_ref->
new_ref = :crypto.hash_update(prev_ref, chunk)
new_ref
end)
|> :crypto.hash_final()
|> Base.encode16()
|> String.downcase()
end
end
{time, _result} = :timer.tc(TimestampRestorer, :sha_all, [])
:logger.info("Restored timestamps in #{time / 1_000_000}s")

View file

@ -6,8 +6,12 @@ set -e
mix local.hex --force
mix local.rebar --force
script/ci/restore-timestamps
mix deps.get
mix ecto.create
mix ecto.migrate
mix test
script/ci/restore-timestamps