Current section

42 Versions

Jump to

Compare versions

4 files changed
+65 additions
-11 deletions
  @@ -12,6 +12,15 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
12 12
13 13 <!-- changelog -->
14 14
15 + ## v1.2.5 (2026-03-09)
16 +
17 +
18 +
19 +
20 + ### Bug Fixes:
21 +
22 + * --check false positive after disk round-trip due to eof_newline mismatch (#59) by Barnabas Jovanovics
23 +
15 24 ## v1.2.4 (2026-03-02)
  @@ -7,7 +7,7 @@
7 7 {<<"GitHub">>,<<"https://github.com/ash-project/usage_rules">>},
8 8 {<<"Website">>,<<"https://ash-hq.org">>}]}.
9 9 {<<"name">>,<<"usage_rules">>}.
10 - {<<"version">>,<<"1.2.4">>}.
10 + {<<"version">>,<<"1.2.5">>}.
11 11 {<<"description">>,
12 12 <<"A config-driven dev tool for Elixir projects to manage AGENTS.md files and agent skills from dependencies">>}.
13 13 {<<"elixir">>,<<"~> 1.18">>}.
  @@ -853,7 +853,7 @@ if Code.ensure_loaded?(Igniter) do
853 853 acc,
854 854 ref_path,
855 855 content,
856 - fn source -> Rewrite.Source.update(source, :content, content) end
856 + fn source -> update_source_content(source, content) end
857 857 )
858 858 end
859 859
  @@ -868,7 +868,7 @@ if Code.ensure_loaded?(Igniter) do
868 868 inner_acc,
869 869 ref_path,
870 870 content,
871 - fn source -> Rewrite.Source.update(source, :content, content) end
871 + fn source -> update_source_content(source, content) end
872 872 )
873 873 end)
874 874 end)
  @@ -1038,7 +1038,7 @@ if Code.ensure_loaded?(Igniter) do
1038 1038 acc2,
1039 1039 dst_path,
1040 1040 content,
1041 - fn source -> Rewrite.Source.update(source, :content, content) end
1041 + fn source -> update_source_content(source, content) end
1042 1042 )
1043 1043 end)
1044 1044 end)
  @@ -1346,20 +1346,50 @@ if Code.ensure_loaded?(Igniter) do
1346 1346 if String.contains?(current_content, "<!-- usage-rules-skill-start -->") do
1347 1347 custom = extract_skill_custom_content(current_content)
1348 1348
1349 - if custom != "" do
1350 - [new_frontmatter, new_managed] =
1351 - String.split(new_skill_md, "\n\n<!-- usage-rules-skill-start -->", parts: 2)
1349 + new_content =
1350 + if custom != "" do
1351 + [frontmatter, managed_body] =
1352 + String.split(new_skill_md, "\n\n<!-- usage-rules-skill-start -->", parts: 2)
1352 1353
1353 - new_frontmatter <>
1354 - "\n\n" <> custom <> "\n\n<!-- usage-rules-skill-start -->" <> new_managed
1354 + frontmatter <>
1355 + "\n\n" <> custom <> "\n\n<!-- usage-rules-skill-start -->" <> managed_body
1356 + else
1357 + new_skill_md
1358 + end
1359 +
1360 + # Only return new content if the managed section actually changed.
1361 + # Rewrite.Source.write/2 applies eof_newline/1 which appends "\n"
1362 + # to disk content (see rewrite/lib/rewrite/source.ex, write/3 and
1363 + # eof_newline/1). The generated content may not end with "\n", so
1364 + # subsequent reads see a trailing-whitespace diff that isn't a real
1365 + # change. Comparing just the managed section avoids this.
1366 + if managed_section_changed?(current_content, new_content) do
1367 + new_content
1355 1368 else
1356 - new_skill_md
1369 + current_content
1357 1370 end
1358 1371 else
1359 1372 new_skill_md
1360 1373 end
1361 1374 end
1362 1375
1376 + defp managed_section_changed?(current, new) do
1377 + extract_managed_section(current) != extract_managed_section(new)
1378 + end
1379 +
1380 + defp extract_managed_section(content) do
1381 + case String.split(content, "<!-- usage-rules-skill-start -->", parts: 2) do
1382 + [_, rest] ->
1383 + case String.split(rest, "<!-- usage-rules-skill-end -->", parts: 2) do
1384 + [managed, _] -> String.trim(managed)
1385 + _ -> String.trim(rest)
1386 + end
1387 +
1388 + _ ->
1389 + nil
1390 + end
1391 + end
1392 +
1363 1393 defp strip_managed_skill_content(content) do
1364 1394 # Remove managed-by metadata from frontmatter
1365 1395 content = String.replace(content, ~r/metadata:\n\s+managed-by: usage-rules\n/, "")
  @@ -1385,6 +1415,21 @@ if Code.ensure_loaded?(Igniter) do
1385 1415 String.replace(content, ~r/\A\s*<!--\s*\n(?:.*?SPDX-.*?\n)*.*?-->\s*\n*/s, "")
1386 1416 end
1387 1417
1418 + # Updates a reference file's content, ignoring trailing whitespace differences.
1419 + # Reference files have no managed-section markers — the entire file is synced
1420 + # content. Rewrite.Source.write/2 applies eof_newline/1 (see
1421 + # rewrite/lib/rewrite/source.ex) which appends "\n" when writing to disk,
1422 + # but dep content may not end with one, causing false diffs on subsequent syncs.
1423 + defp update_source_content(source, new_content) do
1424 + current = Rewrite.Source.get(source, :content)
1425 +
1426 + if String.trim_trailing(current) == String.trim_trailing(new_content) do
1427 + source
1428 + else
1429 + Rewrite.Source.update(source, :content, new_content)
1430 + end
1431 + end
1432 +
1388 1433 defp format_yaml_string(str) do
1389 1434 str = String.trim(str)
  @@ -5,7 +5,7 @@
5 5 defmodule UsageRules.MixProject do
6 6 use Mix.Project
7 7
8 - @version "1.2.4"
8 + @version "1.2.5"
9 9 @description """
10 10 A config-driven dev tool for Elixir projects to manage AGENTS.md files and agent skills from dependencies
11 11 """