Verified line-addressed file editor using lnhash addresses
Project description
exhash — Verified Line-Addressed File Editor
exhash combines Can Bölük's very clever line number + hash editing system with the powerful and expressive syntax of the classic ex editor.
Install via pip to get both a convenient Python API, and native CLI binaries:
pip install exhash
Or install just the CLI binaries via cargo:
cargo install exhash
lnhash format
We refer to an lnhash as a tag of the form lineno|hash|, where hash is the lower 16 bits of Rust's DefaultHasher over the line content.
Address forms:
lineno|hash|— hash-verified address$— last line (no hash)%— whole file (1,$, no hashes)
CLI
The native Rust binaries are installed into your PATH via pip.
View
# Shows every line prefixed with its lnhash
lnhashview path/to/file.txt
# Optional line number range to show
lnhashview path/to/file.txt 10 20
If end is past EOF, lnhashview returns through the last available line instead of failing.
Edit
# Substitute on one line
exhash file.txt '12|abcd|s/foo/bar/g'
# Transliterate characters on one line
exhash file.txt '12|abcd|y/abc/ABC/'
# Append multiline text (terminated by a single dot)
exhash file.txt '12|abcd|a' <<'EOF'
new line 1
new line 2
.
EOF
# Dry-run
exhash --dry-run file.txt '12|abcd|d'
# Set shift width for < and >
exhash --sw 2 file.txt '12|abcd|>1'
# Last line and whole file shorthands (no hash)
exhash file.txt '$d'
exhash file.txt '%j'
# Move a line to EOF using $ as the destination
exhash file.txt '12|abcd|m$'
# Create a missing file by treating it as empty input
exhash new.txt '0|0000|a' <<'EOF'
first line
.
EOF
Substitute uses Rust regex syntax:
- Pattern syntax is from
regex - Replacement syntax is from
regex::Replacer, e.g.$1,$0,${name} \/escapes the command delimiter in pattern/replacement- Custom delimiters:
s,y,g,g!, andvall accept any non-alphanumeric char as delimiter instead of/, e.g.s@pat@rep@,g@pat@cmd. Each command in a combo picks its own delimiter independently:g@a/b@s/old/new/ - Literal newlines in pattern/replacement are supported (joins/splits lines as needed)
- Transliteration uses
y/src/dst/and requires source/destination to have equal character counts
When passing multiple commands, each command's lnhashes are verified immediately before that command runs.
For a/i/c commands, provide the text block on stdin:
printf "new line 1\nnew line 2\n.\n" | exhash file.txt "2|beef|a"
If the file does not exist and the command set is valid on empty input, exhash treats it as an empty file and writes the result. For example, 0|0000|a can create a new file.
Stdin filter mode
cat file.txt | exhash --stdin - '1|abcd|s/foo/bar/'
In --stdin mode, multiline a/i/c text blocks are not available.
Python API
from exhash import exhash, exhash_file, lnhash, lnhashview, lnhashview_file, line_hash
Viewing
text = "foo\nbar\n"
view = lnhashview(text) # ["1|a1b2| foo", "2|c3d4| bar"]
view = lnhashview_file("f.py", start=1, end=260) # end past EOF is clamped
Editing
exhash(text, cmds, sw=4) takes the text and a required iterable of command strings (use [] for no-op). sw controls how far < and > shift. For multiline a/i/c commands, include the inserted text in the same command string using newline characters, e.g. ["12|abcd|c\nnew line 1\nnew line 2"]. Do not use . terminators, and do not split the text block into separate cmds entries. If you include a final . line, it is inserted literally and exhash emits a warning.
addr = lnhash(1, "foo") # "1|a1b2|"
res = exhash(text, [f"{addr}s/foo/baz/"])
print(res["lines"]) # ["baz", "bar"]
print(res["modified"]) # [1]
# Multiple commands
a1, a2 = lnhash(1, "foo"), lnhash(2, "bar")
res = exhash(text, [f"{a1}s/foo/FOO/", f"{a2}s/bar/BAR/"])
# Hashes are checked just-in-time per command.
# If earlier commands change/shift a later target line, recompute lnhash first.
# Append multiline text in the same command string (no dot terminator)
res = exhash(text, [f"{addr}a\nnew line 1\nnew line 2"])
# Wrong for the Python API: the trailing "." would be inserted literally
# res = exhash(text, [f"{addr}a\nnew line 1\nnew line 2\n."])
# Also wrong: do not split the inserted text into separate cmds entries
# res = exhash(text, [f"{addr}a", "new line 1", "new line 2"])
# Change shift width for < and >
res = exhash(text, [f"{addr}>1"], sw=2)
# Custom delimiters (useful when pattern/replacement contains /)
res = exhash(text, [f"{addr}s|foo|bar|"])
# Literal newlines in pattern/replacement (joins/splits lines)
a1, a2 = lnhash(1, "foo"), lnhash(2, "bar")
res = exhash("foo\nbar\n", [f"{a1},{a2}s/foo\nbar/replaced/"])
File helpers
lnhashview_file reads directly from one file path. exhash_file(path, cmds, sw=4, inplace=False) uses path as the default file context for unqualified addresses, and also accepts file-qualified source and m/t destination addresses:
view = lnhashview_file("file.py")
# Returns FileSetEditResult, files unchanged
res = exhash_file("file.py", [f"{addr}s/foo/bar/"])
print(res.changed) # ["file.py"]
print(res["file.py"].lines)
print(res.format_diff()) # includes --- file.py / +++ file.py headers
# With inplace=True, writes changed files after every command succeeds
# and returns the combined diff string.
diff = exhash_file("file.py", [f"{addr}s/foo/bar/"], inplace=True)
# Missing files are treated as empty only when the command is valid on empty input.
diff = exhash_file("new.py", ["0|0000|a\nprint('hi')"], inplace=True)
# File-qualified addresses can edit or transfer lines across files.
cmds = [
"src/a.py:24|8f12|,38|c0de|m src/b.py:$",
r"src/a.py:5|91aa|s/from \.b import old/from \.b import helper/",
]
diff = exhash_file("src/a.py", cmds, inplace=True)
A file prefix is separated from the address with :. Escape literal colons in filenames as \: and literal backslashes as \\.
exhash_file(..., inplace=False) returns a FileSetEditResult:
res.files— dict of path toFileEditResultres.changed— changed paths, in first-touch orderres.default_path— the default path passed toexhash_fileres[path]— shorthand forres.files[path]res.format_diff(context=1)— combined diff with--- path/+++ pathheaders
Pyskill
The package registers exhash.skill as a pyskill exposing the primary Python APIs with LLM-oriented workflow docs. Use doc(exhash.skill) after importing it through a pyskills host.
EditResult
exhash() returns an EditResult with attributes (also accessible via res["key"]):
lines— list of output lineshashes— lnhash for each output linemodified— 1-based line numbers of modified/added linesdeleted— 1-based line numbers of removed lines (in original)origins— for each output line, the 1-based original line number (None if inserted)
res.format_diff(context=1) returns a unified-diff-style summary showing only changed lines with context:
res = exhash(text, [f"{addr}s/foo/baz/"])
print(res.format_diff())
# --- original
# +++ modified
# -1|a1b2| foo
# +1|c3d4| baz
# 2|e5f6| bar
Tests
cargo test && pytest -q
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file exhash-0.3.3.tar.gz.
File metadata
- Download URL: exhash-0.3.3.tar.gz
- Upload date:
- Size: 37.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
87e8c2d31529a92c19556233b2b5bb51227f66d4d9814c9fb92fe3dcb4818a6a
|
|
| MD5 |
5b568d7a147fa728e29a30e12ce9e74c
|
|
| BLAKE2b-256 |
2069b390513c6ac733a40b3b87d32286a41ec83cd1309bf088090023d1b28045
|
Provenance
The following attestation bundles were made for exhash-0.3.3.tar.gz:
Publisher:
ci.yml on AnswerDotAI/exhash
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exhash-0.3.3.tar.gz -
Subject digest:
87e8c2d31529a92c19556233b2b5bb51227f66d4d9814c9fb92fe3dcb4818a6a - Sigstore transparency entry: 1386318420
- Sigstore integration time:
-
Permalink:
AnswerDotAI/exhash@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/AnswerDotAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Trigger Event:
push
-
Statement type:
File details
Details for the file exhash-0.3.3-cp313-cp313-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: exhash-0.3.3-cp313-cp313-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.13, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae47b89460834b4e83f30a90ccf752afa6bd3b198f0a167e696cc074d8ae667a
|
|
| MD5 |
2e5223657f68d91377b072344304d9fe
|
|
| BLAKE2b-256 |
8f101dabe6d9da6ea122c32274070482699df7b8869a05d0926b6e3bad86db0d
|
Provenance
The following attestation bundles were made for exhash-0.3.3-cp313-cp313-manylinux_2_34_x86_64.whl:
Publisher:
ci.yml on AnswerDotAI/exhash
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exhash-0.3.3-cp313-cp313-manylinux_2_34_x86_64.whl -
Subject digest:
ae47b89460834b4e83f30a90ccf752afa6bd3b198f0a167e696cc074d8ae667a - Sigstore transparency entry: 1386318552
- Sigstore integration time:
-
Permalink:
AnswerDotAI/exhash@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/AnswerDotAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Trigger Event:
push
-
Statement type:
File details
Details for the file exhash-0.3.3-cp313-cp313-macosx_11_0_arm64.whl.
File metadata
- Download URL: exhash-0.3.3-cp313-cp313-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.13, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5a34acae6dabc2bc3801df7c91b280b57a836abf6f7a398125d49077ea884a4
|
|
| MD5 |
83741c2a5b8c6f206bf18bd982062374
|
|
| BLAKE2b-256 |
62f1bd8d20791e6a8a2564fc4d1f28120629ed6fa79a365ebf2c03c53374958a
|
Provenance
The following attestation bundles were made for exhash-0.3.3-cp313-cp313-macosx_11_0_arm64.whl:
Publisher:
ci.yml on AnswerDotAI/exhash
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exhash-0.3.3-cp313-cp313-macosx_11_0_arm64.whl -
Subject digest:
a5a34acae6dabc2bc3801df7c91b280b57a836abf6f7a398125d49077ea884a4 - Sigstore transparency entry: 1386318641
- Sigstore integration time:
-
Permalink:
AnswerDotAI/exhash@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/AnswerDotAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Trigger Event:
push
-
Statement type:
File details
Details for the file exhash-0.3.3-cp312-cp312-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: exhash-0.3.3-cp312-cp312-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.12, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f78b52f59a56cabdcf6108f5604bfdb3bb9d843d30be8488b459aa0c157b0c15
|
|
| MD5 |
cbe1db716ec726327a95f24351390f15
|
|
| BLAKE2b-256 |
da080ff7fed9c5f382bd87be2d141efe5dbd23873694d551b4df0ba438f98af4
|
Provenance
The following attestation bundles were made for exhash-0.3.3-cp312-cp312-manylinux_2_34_x86_64.whl:
Publisher:
ci.yml on AnswerDotAI/exhash
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exhash-0.3.3-cp312-cp312-manylinux_2_34_x86_64.whl -
Subject digest:
f78b52f59a56cabdcf6108f5604bfdb3bb9d843d30be8488b459aa0c157b0c15 - Sigstore transparency entry: 1386318608
- Sigstore integration time:
-
Permalink:
AnswerDotAI/exhash@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/AnswerDotAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Trigger Event:
push
-
Statement type:
File details
Details for the file exhash-0.3.3-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: exhash-0.3.3-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da45e654689f333de89c6fd1b52c1b76d2af42ccab769ec20b75e1795ac88183
|
|
| MD5 |
4cba2ace7b640b5830030c476caf0a04
|
|
| BLAKE2b-256 |
ab290df52f0bee8b67aa1a23e0bf04ba9a35bdce8c2bf2f9b537e0a88602a240
|
Provenance
The following attestation bundles were made for exhash-0.3.3-cp312-cp312-macosx_11_0_arm64.whl:
Publisher:
ci.yml on AnswerDotAI/exhash
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exhash-0.3.3-cp312-cp312-macosx_11_0_arm64.whl -
Subject digest:
da45e654689f333de89c6fd1b52c1b76d2af42ccab769ec20b75e1795ac88183 - Sigstore transparency entry: 1386318504
- Sigstore integration time:
-
Permalink:
AnswerDotAI/exhash@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/AnswerDotAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Trigger Event:
push
-
Statement type:
File details
Details for the file exhash-0.3.3-cp311-cp311-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: exhash-0.3.3-cp311-cp311-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.11, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5f0407dafa6307c2ddd766d19c7a2fd593beb009517f79233c9d214d6ea8a52c
|
|
| MD5 |
977c09a43bda13de04de5325a585bd13
|
|
| BLAKE2b-256 |
347da15d4bf44cd597274d98f63d1a1a70a69fcedf18ff571629b4f933756bdd
|
Provenance
The following attestation bundles were made for exhash-0.3.3-cp311-cp311-manylinux_2_34_x86_64.whl:
Publisher:
ci.yml on AnswerDotAI/exhash
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exhash-0.3.3-cp311-cp311-manylinux_2_34_x86_64.whl -
Subject digest:
5f0407dafa6307c2ddd766d19c7a2fd593beb009517f79233c9d214d6ea8a52c - Sigstore transparency entry: 1386318732
- Sigstore integration time:
-
Permalink:
AnswerDotAI/exhash@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/AnswerDotAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Trigger Event:
push
-
Statement type:
File details
Details for the file exhash-0.3.3-cp311-cp311-macosx_11_0_arm64.whl.
File metadata
- Download URL: exhash-0.3.3-cp311-cp311-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.11, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c66dfac1bb97d21a1f59c18ed3cc2e8a1ded1daf78a69ca7b125c7cfdab2feb8
|
|
| MD5 |
5daea9fd59c0f1c81bd85ae3ef1c7696
|
|
| BLAKE2b-256 |
f5b47b30176fc7c7400e67f7f9d186221944851a48d740de82b6b2a93e71b9c6
|
Provenance
The following attestation bundles were made for exhash-0.3.3-cp311-cp311-macosx_11_0_arm64.whl:
Publisher:
ci.yml on AnswerDotAI/exhash
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exhash-0.3.3-cp311-cp311-macosx_11_0_arm64.whl -
Subject digest:
c66dfac1bb97d21a1f59c18ed3cc2e8a1ded1daf78a69ca7b125c7cfdab2feb8 - Sigstore transparency entry: 1386318785
- Sigstore integration time:
-
Permalink:
AnswerDotAI/exhash@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/AnswerDotAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Trigger Event:
push
-
Statement type:
File details
Details for the file exhash-0.3.3-cp310-cp310-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: exhash-0.3.3-cp310-cp310-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.10, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a70212f714518e1e5ff09b3476226e3617d71881803de19d40e33c3e1848697d
|
|
| MD5 |
793e90ecaa2f506fc71c3b2f6ad01df9
|
|
| BLAKE2b-256 |
c5fe97dcb0fb5331a4f634731cad1d12f44b0406414a8be541b4a674209bb5a1
|
Provenance
The following attestation bundles were made for exhash-0.3.3-cp310-cp310-manylinux_2_34_x86_64.whl:
Publisher:
ci.yml on AnswerDotAI/exhash
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exhash-0.3.3-cp310-cp310-manylinux_2_34_x86_64.whl -
Subject digest:
a70212f714518e1e5ff09b3476226e3617d71881803de19d40e33c3e1848697d - Sigstore transparency entry: 1386318863
- Sigstore integration time:
-
Permalink:
AnswerDotAI/exhash@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/AnswerDotAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Trigger Event:
push
-
Statement type:
File details
Details for the file exhash-0.3.3-cp310-cp310-macosx_11_0_arm64.whl.
File metadata
- Download URL: exhash-0.3.3-cp310-cp310-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.10, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0eec73eb540f265007c5f4b4af1372dbf650f0370b6321edf8e15e04278016a
|
|
| MD5 |
cd55c933acd7737331893a4e9da7c134
|
|
| BLAKE2b-256 |
86b36bcf520fd5b371a24ade0ac5e1ffb387ca995523be2fce7f3ccc465ae187
|
Provenance
The following attestation bundles were made for exhash-0.3.3-cp310-cp310-macosx_11_0_arm64.whl:
Publisher:
ci.yml on AnswerDotAI/exhash
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exhash-0.3.3-cp310-cp310-macosx_11_0_arm64.whl -
Subject digest:
c0eec73eb540f265007c5f4b4af1372dbf650f0370b6321edf8e15e04278016a - Sigstore transparency entry: 1386318690
- Sigstore integration time:
-
Permalink:
AnswerDotAI/exhash@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/AnswerDotAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@68eb59c604303b70bd963be6fa330d06ab1c17fa -
Trigger Event:
push
-
Statement type: