-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add read-file * Use YYYY.MM cache hash * Correct inputs & outputs * Cleanup * Add default value for when file doesn't exist * Convert positionals to options * Invalidate cache based on workflows * Correct README * Improve caching * Use Python >=3.8 * Initialize test suite * Install all dependencies * Upload coverage * Add badges * Update README.md * Update test_combine_durations.py * Add test_read_file.py * Correct nested double quotes * Use Python >=3.9 * Stringify * Don't specify testpaths, allow pytest to autodetect * Add comment regarding hashing * Test GHA * Debug * Correct remote URL * Fix quoting * Setup python * Standardize Python * Enable dependabot updates for pip * Add analyze step with automated error reports * Minor cleanup * Update existing failures * Apply suggestions from code review * Typing * Update README.md * Apply suggestions from code review * Update .github/workflows/tests.yml --------- Co-authored-by: Jannis Leidel <[email protected]>
- Loading branch information
1 parent
6151812
commit c01236b
Showing
9 changed files
with
424 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Read File | ||
|
||
A composite GitHub Action to read a local file or remote URL with an optional JSON/YAML parser. | ||
|
||
## Action Inputs | ||
|
||
| Name | Description | Default | | ||
|------|-------------|---------| | ||
| `path` | Local path or remote URL to the file to read. | **required** | | ||
| `parser` | Parser to use for the file. Choose json, yaml, or null (to leave it as plain text). | **optional** | | ||
| `default` | File contents to use if the file is not found. | **optional** | | ||
|
||
## Action Outputs | ||
|
||
| Name | Description | | ||
|------|-------------| | ||
| `content` | File contents as a JSON object (if a parser is specified) or the raw text. | | ||
|
||
## Sample Workflows | ||
|
||
```yaml | ||
name: Read File | ||
|
||
on: | ||
pull_request: | ||
|
||
jobs: | ||
read: | ||
steps: | ||
- id: read_json | ||
uses: conda/actions/read-file | ||
with: | ||
path: https://raw.githubusercontent.com/owner/repo/ref/path/to/json.json | ||
default: '{}' | ||
parser: json | ||
|
||
- id: read_yaml | ||
uses: conda/actions/read-file | ||
with: | ||
path: https://raw.githubusercontent.com/owner/repo/ref/path/to/yaml.yaml | ||
default: '{}' | ||
parser: yaml | ||
|
||
- id: read_text | ||
uses: conda/actions/read-file | ||
with: | ||
path: path/to/text.text | ||
|
||
- run: echo "${{ fromJSON(steps.read_json.outputs.content)['key'] }}" | ||
- run: echo "${{ fromJSON(steps.read_yaml.outputs.content)['key'] }}" | ||
- run: echo "${{ steps.read_file.outputs.content }}" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
name: Read File | ||
description: Read a local file or remote URL. | ||
author: Anaconda Inc. | ||
branding: | ||
icon: book-open | ||
color: green | ||
|
||
inputs: | ||
path: | ||
description: Local path or remote URL to the file to read. | ||
required: true | ||
parser: | ||
description: Parser to use for the file. Choose json, yaml, or null (to leave it as plain text). | ||
default: | ||
description: File contents to use if the file is not found. | ||
outputs: | ||
content: | ||
description: File contents as a JSON object (if a parser is specified) or the raw text. | ||
value: ${{ steps.read.outputs.content }} | ||
|
||
runs: | ||
using: composite | ||
steps: | ||
# `hashFiles` only works on files within the working directory, since `requirements.txt` | ||
# is not in the working directory we need to manually compute the SHA256 hash | ||
- name: Compute Hash | ||
id: hash | ||
shell: bash | ||
run: echo hash=$(sha256sum ${{ github.action_path }}/requirements.txt | awk '{print $1}') >> $GITHUB_OUTPUT | ||
|
||
- name: Pip Cache | ||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 | ||
with: | ||
path: ~/.cache/pip | ||
key: ${{ github.workflow }}-read-file-${{ steps.hash.outputs.hash }} | ||
|
||
- name: Setup Python | ||
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 | ||
with: | ||
python-version: '>=3.9' | ||
|
||
- name: Pip Install | ||
shell: bash | ||
run: pip install --quiet -r ${{ github.action_path }}/requirements.txt | ||
|
||
- name: Pip List | ||
shell: bash | ||
run: pip list | ||
|
||
- name: Read JSON | ||
id: read | ||
shell: bash | ||
run: > | ||
python ${{ github.action_path }}/read_file.py | ||
${{ inputs.path }} | ||
${{ inputs.parser && format('"--parser={0}"', inputs.parser) || '' }} | ||
${{ inputs.default && format('"--default={0}"', inputs.default) || '' }} | ||
env: | ||
GITHUB_TOKEN: ${{ github.token }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"foo": "bar"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
foo: bar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
"""Read a local file or remote URL.""" | ||
|
||
from __future__ import annotations | ||
|
||
import json | ||
import os | ||
from argparse import ArgumentParser | ||
from pathlib import Path | ||
from typing import TYPE_CHECKING | ||
|
||
import requests | ||
import yaml | ||
from requests.exceptions import HTTPError, MissingSchema | ||
|
||
if TYPE_CHECKING: | ||
from argparse import Namespace | ||
from collections.abc import Sequence | ||
from typing import Literal | ||
|
||
|
||
def parse_args(argv: Sequence[str] | None = None) -> Namespace: | ||
# parse CLI for inputs | ||
parser = ArgumentParser() | ||
parser.add_argument( | ||
"file", | ||
type=str, | ||
help="Local path or remote URL to the file to read.", | ||
) | ||
parser.add_argument( | ||
"--parser", | ||
choices=["json", "yaml"], | ||
help=( | ||
"Parser to use for the file. " | ||
"If not specified, the file content is returned as is." | ||
), | ||
) | ||
parser.add_argument( | ||
"--default", | ||
type=str, | ||
help=( | ||
"Default value to use if the file is not found. " | ||
"If not specified, an error is raised." | ||
), | ||
) | ||
return parser.parse_args(argv) | ||
|
||
|
||
def read_file(file: str | os.PathLike[str] | Path, default: str | None) -> str: | ||
try: | ||
response = requests.get(file) | ||
response.raise_for_status() | ||
except (HTTPError, MissingSchema): | ||
# HTTPError: if the response status code is not ok | ||
# MissingSchema: if the URL is not valid | ||
try: | ||
return Path(file).read_text() | ||
except FileNotFoundError: | ||
if default is None: | ||
raise | ||
return default | ||
else: | ||
return response.text | ||
|
||
|
||
def parse_content(content: str, parser: Literal["json", "yaml"]) -> str: | ||
# if a parser is defined we parse the content and dump it as JSON | ||
if parser == "json": | ||
content = json.loads(content) | ||
return json.dumps(content) | ||
elif parser == "yaml": | ||
content = yaml.safe_load(content) | ||
return json.dumps(content) | ||
else: | ||
raise ValueError("Parser not supported.") | ||
|
||
|
||
def get_output(content: str) -> str: | ||
return f"content<<GITHUB_OUTPUT_content\n{content}\nGITHUB_OUTPUT_content\n" | ||
|
||
|
||
def dump_output(content: str) -> None: | ||
if output := os.getenv("GITHUB_OUTPUT"): | ||
with Path(output).open("a") as fh: | ||
fh.write(get_output(content)) | ||
|
||
|
||
def main() -> None: | ||
args = parse_args() | ||
|
||
content = read_file(args.file, args.default) | ||
if args.parser: | ||
content = parse_content(content, args.parser) | ||
dump_output(content) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pyyaml==6.0.2 | ||
requests==2.32.3 |
Oops, something went wrong.