Skip to content

Commit

Permalink
Add --limit-bytes to diff command to truncate output in github actions (
Browse files Browse the repository at this point in the history
#208)

Add a default limit so that very large diffs do not fail github actions

Issue #207
  • Loading branch information
allenporter authored May 27, 2023
1 parent 17b6e79 commit f0d5a85
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 10 deletions.
4 changes: 4 additions & 0 deletions action/diff/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ inputs:
debug:
description: When true, uses the DEBUG log level
default: false
limit-bytes:
description: Maximum number of bytes per individual diff (0=unlimited)
default: 20000
outputs:
diff:
description: Output of the diff command or empty if there is no diff
Expand Down Expand Up @@ -70,6 +73,7 @@ runs:
--strip-attrs "${{ inputs.strip-attrs }}" \
--${{ inputs.skip-crds != 'true' && 'no-' || '' }}skip-crds \
--${{ inputs.skip-secrets != 'true' && 'no-' || '' }}skip-secrets \
--limit-bytes ${{ inputs.limit-bytes }} \
--all-namespaces \
>> $GITHUB_OUTPUT
echo "${delimiter}" >> $GITHUB_OUTPUT
Expand Down
44 changes: 34 additions & 10 deletions flux_local/tool/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
# Type for command line flags of comma separated list
_CSV = functools.partial(str.split, sep=",")

_TRUNCATE = "[Diff truncated by flux-local]"


def perform_object_diff(
a: ObjectOutput,
b: ObjectOutput,
n: int,
a: ObjectOutput, b: ObjectOutput, n: int, limit_bytes: int
) -> Generator[str, None, None]:
"""Generate diffs between the two output objects."""
for kustomization_key in set(a.content.keys()) | set(b.content.keys()):
Expand All @@ -47,14 +47,20 @@ def perform_object_diff(
tofile=f"{kustomization_key.label} {resource_key.compact_label}",
n=n,
)
size = 0
for line in diff_text:
size += len(line)
if limit_bytes and size > limit_bytes:
yield _TRUNCATE
break
yield line


async def perform_external_diff(
cmd: list[str],
a: ObjectOutput,
b: ObjectOutput,
limit_bytes: int,
) -> AsyncGenerator[str, None]:
"""Generate diffs between the two output objects."""
with tempfile.TemporaryDirectory() as tmpdir:
Expand Down Expand Up @@ -90,7 +96,10 @@ async def perform_external_diff(
cmd + [str(a_file), str(b_file)], retcodes=[0, 1]
).run()
if out:
yield out.decode("utf-8")
result = out.decode("utf-8")
if limit_bytes and len(result) > limit_bytes:
result = result[:limit_bytes] + "\n" + _TRUNCATE
yield result


def omit_none(obj: Any) -> dict[str, Any]:
Expand All @@ -102,6 +111,7 @@ def perform_yaml_diff(
a: ObjectOutput,
b: ObjectOutput,
n: int,
limit_bytes: int,
) -> Generator[str, None, None]:
"""Generate diffs between the two output objects."""

Expand All @@ -122,6 +132,8 @@ def perform_yaml_diff(
diff_content = "\n".join(diff_text)
if not diff_content:
continue
if limit_bytes and len(diff_content) > limit_bytes:
diff_content = diff_content[:limit_bytes] + "\n" + _TRUNCATE
obj = {
**asdict(resource_key, dict_factory=omit_none),
"diff": diff_content,
Expand Down Expand Up @@ -184,6 +196,12 @@ def add_diff_flags(args: ArgumentParser) -> None:
help="Labels or annotations to strip from the diff",
type=_CSV,
)
args.add_argument(
"--limit-bytes",
help="Maximum bytes for each diff output (0=unlimited)",
type=int,
default=0,
)


@contextmanager
Expand Down Expand Up @@ -234,6 +252,7 @@ async def run( # type: ignore[no-untyped-def]
output: str,
unified: int,
strip_attrs: list[str] | None,
limit_bytes: int,
**kwargs, # pylint: disable=unused-argument
) -> None:
"""Async Action implementation."""
Expand All @@ -256,16 +275,16 @@ async def run( # type: ignore[no-untyped-def]

_LOGGER.debug("Diffing content")
if output == "yaml":
result = perform_yaml_diff(orig_content, content, unified)
result = perform_yaml_diff(orig_content, content, unified, limit_bytes)
for line in result:
print(line)
elif external_diff := os.environ.get("DIFF"):
async for line in perform_external_diff(
shlex.split(external_diff), orig_content, content
shlex.split(external_diff), orig_content, content, limit_bytes
):
print(line)
else:
result = perform_object_diff(orig_content, content, unified)
result = perform_object_diff(orig_content, content, unified, limit_bytes)
for line in result:
print(line)

Expand Down Expand Up @@ -300,6 +319,7 @@ async def run( # type: ignore[no-untyped-def]
output: str,
unified: int,
strip_attrs: list[str] | None,
limit_bytes: int,
**kwargs, # pylint: disable=unused-argument
) -> None:
"""Async Action implementation."""
Expand Down Expand Up @@ -375,15 +395,19 @@ async def run( # type: ignore[no-untyped-def]
)

if output == "yaml":
for line in perform_yaml_diff(orig_helm_content, helm_content, unified):
for line in perform_yaml_diff(
orig_helm_content, helm_content, unified, limit_bytes
):
print(line)
elif external_diff := os.environ.get("DIFF"):
async for line in perform_external_diff(
shlex.split(external_diff), orig_helm_content, helm_content
shlex.split(external_diff), orig_helm_content, helm_content, limit_bytes
):
print(line)
else:
for line in perform_object_diff(orig_helm_content, helm_content, unified):
for line in perform_object_diff(
orig_helm_content, helm_content, unified, limit_bytes
):
print(line)


Expand Down
13 changes: 13 additions & 0 deletions tests/tool/testdata/diff_hr_external_limit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
env:
DIFF: diff
args:
- diff
- hr
- podinfo
- -n
- podinfo
- --path
- tests/testdata/cluster/
- --limit-bytes
- "20"
stdout: ''
11 changes: 11 additions & 0 deletions tests/tool/testdata/diff_hr_limit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
args:
- diff
- hr
- podinfo
- -n
- podinfo
- --path
- tests/testdata/cluster/
- --limit-bytes
- "20000"
stdout: ''
10 changes: 10 additions & 0 deletions tests/tool/testdata/diff_ks_yaml_limit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
args:
- diff
- ks
- apps
- --path
- tests/testdata/cluster/
- -o
- yaml
- --limit-bytes
- "20000"

0 comments on commit f0d5a85

Please sign in to comment.