Skip to content
Merged
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
243 changes: 243 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ HAS_ANSIBLE := $(filter ansible,$(LANGUAGES))
HAS_RUBY := $(filter ruby,$(LANGUAGES))
HAS_GO := $(filter go,$(LANGUAGES))
HAS_JAVASCRIPT := $(filter javascript,$(LANGUAGES))
HAS_RUST := $(filter rust,$(LANGUAGES))

# ---------------------------------------------------------------------------
# .PHONY declarations
Expand Down Expand Up @@ -255,6 +256,21 @@ _lint: _check-config
exit $$overall_exit; \
fi; \
fi; \
if [ -n "$(HAS_RUST)" ]; then \
ran_languages="$${ran_languages}\"rust\","; \
rs_files=$$(find . -name '*.rs' -not -path './.git/*' -not -path './vendor/*' -not -path './target/*' 2>/dev/null); \
if [ -n "$$rs_files" ]; then \
cargo clippy --all-targets --all-features -- -D warnings || { overall_exit=1; failed_languages="$${failed_languages}\"rust\","; }; \
else \
echo '{"level":"info","msg":"skipping rust lint: no .rs files found","language":"rust"}' >&2; \
fi; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
echo "{\"target\":\"lint\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}]}"; \
exit $$overall_exit; \
fi; \
fi; \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
if [ $$overall_exit -eq 0 ]; then \
Expand Down Expand Up @@ -298,6 +314,10 @@ _format: _check-config
if [ -n "$(HAS_TERRAFORM)" ]; then \
ran_languages="$${ran_languages}\"terraform\","; \
terraform fmt -check -recursive || { overall_exit=1; failed_languages="$${failed_languages}\"terraform\","; }; \
tg_files=$$(find . -name 'terragrunt.hcl' -not -path './.git/*' -not -path './.terraform/*' 2>/dev/null); \
if [ -n "$$tg_files" ]; then \
terragrunt hclfmt --terragrunt-check || { overall_exit=1; failed_languages="$${failed_languages}\"terraform:terragrunt\","; }; \
fi; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
Expand Down Expand Up @@ -354,6 +374,21 @@ _format: _check-config
exit $$overall_exit; \
fi; \
fi; \
if [ -n "$(HAS_RUST)" ]; then \
ran_languages="$${ran_languages}\"rust\","; \
rs_files=$$(find . -name '*.rs' -not -path './.git/*' -not -path './vendor/*' -not -path './target/*' 2>/dev/null); \
if [ -n "$$rs_files" ]; then \
cargo fmt --all -- --check || { overall_exit=1; failed_languages="$${failed_languages}\"rust\","; }; \
else \
echo '{"level":"info","msg":"skipping rust format: no .rs files found","language":"rust"}' >&2; \
fi; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
echo "{\"target\":\"format\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}]}"; \
exit $$overall_exit; \
fi; \
fi; \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
if [ $$overall_exit -eq 0 ]; then \
Expand All @@ -363,6 +398,124 @@ _format: _check-config
fi; \
exit $$overall_exit

# --- _fix: language-specific format fixing (in-place) ---
_fix: _check-config
@start_time=$$(date +%s%3N); \
overall_exit=0; \
ran_languages=""; \
failed_languages=""; \
if [ -n "$(HAS_PYTHON)" ]; then \
ran_languages="$${ran_languages}\"python\","; \
ruff format . || { overall_exit=1; failed_languages="$${failed_languages}\"python\","; }; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
echo "{\"target\":\"fix\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}]}"; \
exit $$overall_exit; \
fi; \
fi; \
if [ -n "$(HAS_BASH)" ]; then \
ran_languages="$${ran_languages}\"bash\","; \
sh_files=$$(find . -name '*.sh' -not -path './.git/*' -not -path './vendor/*' -not -path './node_modules/*' 2>/dev/null); \
if [ -n "$$sh_files" ]; then \
echo "$$sh_files" | xargs shfmt -w || { overall_exit=1; failed_languages="$${failed_languages}\"bash\","; }; \
else \
echo '{"level":"info","msg":"skipping bash fix: no .sh files found","language":"bash"}' >&2; \
fi; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
echo "{\"target\":\"fix\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}]}"; \
exit $$overall_exit; \
fi; \
fi; \
if [ -n "$(HAS_TERRAFORM)" ]; then \
ran_languages="$${ran_languages}\"terraform\","; \
terraform fmt -recursive || { overall_exit=1; failed_languages="$${failed_languages}\"terraform\","; }; \
tg_files=$$(find . -name 'terragrunt.hcl' -not -path './.git/*' -not -path './.terraform/*' 2>/dev/null); \
if [ -n "$$tg_files" ]; then \
terragrunt hclfmt || { overall_exit=1; failed_languages="$${failed_languages}\"terraform:terragrunt\","; }; \
fi; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
echo "{\"target\":\"fix\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}]}"; \
exit $$overall_exit; \
fi; \
fi; \
if [ -n "$(HAS_ANSIBLE)" ]; then \
ran_languages="$${ran_languages}\"ansible\","; \
echo '{"target":"fix","language":"ansible","status":"skip","reason":"no formatter configured"}' >&2; \
fi; \
if [ -n "$(HAS_RUBY)" ]; then \
ran_languages="$${ran_languages}\"ruby\","; \
rb_files=$$(find . -name '*.rb' -not -path './.git/*' -not -path './vendor/*' -not -path './node_modules/*' 2>/dev/null); \
if [ -n "$$rb_files" ]; then \
rubocop -a . || { overall_exit=1; failed_languages="$${failed_languages}\"ruby\","; }; \
else \
echo '{"level":"info","msg":"skipping ruby fix: no .rb files found","language":"ruby"}' >&2; \
fi; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
echo "{\"target\":\"fix\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}]}"; \
exit $$overall_exit; \
fi; \
fi; \
if [ -n "$(HAS_GO)" ]; then \
ran_languages="$${ran_languages}\"go\","; \
go_files=$$(find . -name '*.go' -not -path './.git/*' -not -path './vendor/*' -not -path './node_modules/*' 2>/dev/null); \
if [ -n "$$go_files" ]; then \
gofumpt -w . || { overall_exit=1; failed_languages="$${failed_languages}\"go\","; }; \
else \
echo '{"level":"info","msg":"skipping go fix: no .go files found","language":"go"}' >&2; \
fi; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
echo "{\"target\":\"fix\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}]}"; \
exit $$overall_exit; \
fi; \
fi; \
if [ -n "$(HAS_JAVASCRIPT)" ]; then \
ran_languages="$${ran_languages}\"javascript\","; \
js_files=$$(find . \( -name '*.js' -o -name '*.jsx' -o -name '*.ts' -o -name '*.tsx' -o -name '*.mjs' -o -name '*.cjs' \) -not -path './.git/*' -not -path './vendor/*' -not -path './node_modules/*' -not -path './dist/*' -not -path './build/*' 2>/dev/null); \
if [ -n "$$js_files" ]; then \
prettier --write . || { overall_exit=1; failed_languages="$${failed_languages}\"javascript\","; }; \
else \
echo '{"level":"info","msg":"skipping javascript fix: no JS/TS files found","language":"javascript"}' >&2; \
fi; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
echo "{\"target\":\"fix\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}]}"; \
exit $$overall_exit; \
fi; \
fi; \
if [ -n "$(HAS_RUST)" ]; then \
ran_languages="$${ran_languages}\"rust\","; \
rs_files=$$(find . -name '*.rs' -not -path './.git/*' -not -path './vendor/*' -not -path './target/*' 2>/dev/null); \
if [ -n "$$rs_files" ]; then \
cargo fmt --all || { overall_exit=1; failed_languages="$${failed_languages}\"rust\","; }; \
else \
echo '{"level":"info","msg":"skipping rust fix: no .rs files found","language":"rust"}' >&2; \
fi; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
echo "{\"target\":\"fix\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}]}"; \
exit $$overall_exit; \
fi; \
fi; \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
if [ $$overall_exit -eq 0 ]; then \
echo "{\"target\":\"fix\",\"status\":\"pass\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}]}"; \
else \
echo "{\"target\":\"fix\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}]}"; \
fi; \
exit $$overall_exit

# --- _test: language-specific test runners ---
_test: _check-config
@start_time=$$(date +%s%3N); \
Expand Down Expand Up @@ -475,6 +628,22 @@ _test: _check-config
exit $$overall_exit; \
fi; \
fi; \
if [ -n "$(HAS_RUST)" ]; then \
rs_files=$$(find . -name '*.rs' -not -path './.git/*' -not -path './vendor/*' -not -path './target/*' 2>/dev/null); \
if [ -n "$$rs_files" ] && [ -f "Cargo.toml" ]; then \
ran_languages="$${ran_languages}\"rust\","; \
cargo test --all-targets || { overall_exit=1; failed_languages="$${failed_languages}\"rust\","; }; \
else \
skipped_languages="$${skipped_languages}\"rust\","; \
echo '{"level":"info","msg":"skipping rust tests: no .rs files or Cargo.toml found","language":"rust"}' >&2; \
fi; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
echo "{\"target\":\"test\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}],\"skipped\":[$${skipped_languages%,}]}"; \
exit $$overall_exit; \
fi; \
fi; \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
if [ -z "$${ran_languages}" ] && [ -n "$${skipped_languages}" ]; then \
Expand Down Expand Up @@ -590,6 +759,32 @@ _security: _check-config
exit $$overall_exit; \
fi; \
fi; \
if [ -n "$(HAS_RUST)" ]; then \
if [ -f "Cargo.lock" ]; then \
ran_languages="$${ran_languages}\"rust\","; \
cargo audit || { overall_exit=1; failed_languages="$${failed_languages}\"rust:cargo-audit\","; }; \
else \
skipped_languages="$${skipped_languages}\"rust:cargo-audit\","; \
echo '{"level":"info","msg":"skipping cargo audit: no Cargo.lock found","language":"rust"}' >&2; \
fi; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
echo "{\"target\":\"security\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}]}"; \
exit $$overall_exit; \
fi; \
if [ -f "deny.toml" ]; then \
cargo deny check || { overall_exit=1; failed_languages="$${failed_languages}\"rust:cargo-deny\","; }; \
else \
echo '{"level":"info","msg":"skipping cargo deny: no deny.toml found","language":"rust"}' >&2; \
fi; \
if [ "$(DEVRAIL_FAIL_FAST)" = "1" ] && [ $$overall_exit -ne 0 ]; then \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
echo "{\"target\":\"security\",\"status\":\"fail\",\"duration_ms\":$$duration,\"languages\":[$${ran_languages%,}],\"failed\":[$${failed_languages%,}]}"; \
exit $$overall_exit; \
fi; \
fi; \
end_time=$$(date +%s%3N); \
duration=$$((end_time - start_time)); \
if [ -z "$${ran_languages}" ] && [ -n "$${skipped_languages}" ]; then \
Expand Down Expand Up @@ -682,6 +877,7 @@ _docs: _check-config
_tv tfsec "tfsec --version"; \
_tv checkov "checkov --version"; \
_tv terraform-docs "terraform-docs --version"; \
_tv terragrunt "terragrunt --version"; \
fi; \
if [ -n "$(HAS_ANSIBLE)" ]; then \
_tv ansible-lint "ansible-lint --version"; \
Expand Down Expand Up @@ -709,6 +905,14 @@ _docs: _check-config
_tv tsc "tsc --version"; \
_tv vitest "vitest --version"; \
fi; \
if [ -n "$(HAS_RUST)" ]; then \
_tv rustc "rustc --version"; \
_tv cargo "cargo --version"; \
_tv clippy "cargo clippy --version"; \
_tv rustfmt "rustfmt --version"; \
_tv cargo-audit "cargo audit --version"; \
_tv cargo-deny "cargo deny --version"; \
fi; \
_tv trivy "trivy --version"; \
_tv gitleaks "gitleaks version"; \
_tv git-cliff "git-cliff --version"; \
Expand Down Expand Up @@ -915,6 +1119,45 @@ _init: _check-config
'build/' \
'coverage/'; \
fi; \
if [ -n "$(HAS_RUST)" ]; then \
scaffold clippy.toml \
'# clippy.toml -- DevRail Rust clippy configuration' \
'# See: https://doc.rust-lang.org/clippy/lint_configuration.html' \
'too-many-arguments-threshold = 7'; \
scaffold rustfmt.toml \
'# rustfmt.toml -- DevRail Rust formatter configuration' \
'edition = "2021"' \
'max_width = 100' \
'use_field_init_shorthand = true' \
'use_try_shorthand = true'; \
scaffold deny.toml \
'# deny.toml -- DevRail cargo-deny configuration' \
'# See: https://embarkstudios.github.io/cargo-deny/' \
'' \
'[advisories]' \
'vulnerability = "deny"' \
'unmaintained = "warn"' \
'yanked = "warn"' \
'' \
'[licenses]' \
'unlicensed = "deny"' \
'allow = [' \
' "MIT",' \
' "Apache-2.0",' \
' "BSD-2-Clause",' \
' "BSD-3-Clause",' \
' "ISC",' \
' "Unicode-3.0",' \
' "Unicode-DFS-2016",' \
']' \
'' \
'[bans]' \
'multiple-versions = "warn"' \
'' \
'[sources]' \
'unknown-registry = "deny"' \
'unknown-git = "warn"'; \
fi; \
echo "{\"target\":\"init\",\"created\":[$${created%,}],\"skipped\":[$${skipped%,}]}"

# --- _check: orchestrate all targets ---
Expand Down