feat: embed build metadata in generated dotslash files (#13)

* feat: embed build metadata in generated dotslash files

- Add build metadata collection from GitHub Actions environment
- Include source config path, CI information, and generation timestamp
- Add CI job URL for traceability back to the generating workflow
- Support disabling metadata via include-build-metadata input
- Update action.yml to expose new input parameter
- Add comprehensive documentation with examples

Fixes #2

* feat: pass include-build-metadata as argument instead of environment variable

- Remove environment variable approach from action.yml
- Pass include-build-metadata as command-line argument
- Update argument parsing to handle string values ('true'/'false')
- Maintain backward compatibility with environment variable fallback

Addresses review feedback from @bigfootjon in PR #13
This commit is contained in:
prathish D
2025-11-17 09:33:11 -08:00
committed by GitHub
parent 9c9ec02751
commit 6cf5d80be8
3 changed files with 134 additions and 0 deletions
+50
View File
@@ -261,6 +261,56 @@ Each platform entry recognizes the following properties:
* `hash` must be one of `"blake3"` or `"sha256"`, but it defaults to `"blake3"`,
so it is optional.
## Action Inputs
This action supports the following inputs:
* `config` (required): Path to .json file in the repo that defines how DotSlash files should be generated.
* `tag` (required): Tag identifying the release whose assets should be used.
* `include-build-metadata` (optional): Whether to include build metadata in the generated DotSlash files. Defaults to `true`.
## Build Metadata
By default, the action embeds build metadata in the generated DotSlash files to provide traceability about how and when the files were generated. This metadata includes:
* **Source configuration**: Path to the config file used to generate the DotSlash file
* **CI information**: Repository, commit SHA, run ID, workflow name, actor, and event type
* **Generation timestamp**: When the DotSlash file was generated
* **CI job URL**: Direct link to the GitHub Actions run that generated the file
Example of embedded metadata:
```json
{
"name": "my-tool",
"platforms": { ... },
"build_metadata": {
"source_config": ".github/workflows/dotslash-config.json",
"ci": {
"github_repository": "owner/repo",
"github_sha": "abc123def456",
"github_run_id": "987654321",
"github_workflow": "Build and Release",
"github_actor": "john-doe",
"github_event_name": "release",
"github_server_url": "https://github.com"
},
"generated_at": "2025-09-28T15:23:57.878282Z",
"ci_job_url": "https://github.com/owner/repo/actions/runs/987654321"
}
}
```
To disable build metadata inclusion, set `include-build-metadata` to `false`:
```yaml
- uses: facebook/dotslash-publish-release@v1
with:
config: .github/workflows/dotslash-config.json
tag: ${{ github.event.workflow_run.head_branch }}
include-build-metadata: false
```
## License
dotslash-publish-release is [MIT licensed](./LICENSE).
+6
View File
@@ -7,6 +7,10 @@ inputs:
tag:
description: tag identifying the release whose assets should be used
required: true
include-build-metadata:
description: include build metadata in the generated DotSlash files
required: false
default: 'true'
runs:
using: docker
image: Dockerfile
@@ -16,3 +20,5 @@ runs:
- '--tag'
- ${{ inputs.tag }}
- '--upload'
- '--include-build-metadata'
- ${{ inputs.include-build-metadata }}
+78
View File
@@ -12,6 +12,7 @@ import re
import subprocess
import sys
import tempfile
import datetime
from functools import cache
from typing import Any, Dict, Literal, Optional, Tuple, Union
@@ -26,6 +27,47 @@ EXCLUDE_HTTP_PROVIDER_PARAM = "exclude-http-provider"
EXCLUDE_GITHUB_PROVIDER_PARAM = "exclude-github-release-provider"
def collect_build_metadata(config_path: str) -> Dict[str, Any]:
"""Collect build metadata from GitHub Actions environment variables."""
metadata = {}
# Source file information
if config_path:
metadata["source_config"] = config_path
# CI/GitHub Actions information
github_env_vars = [
("github_repository", "GITHUB_REPOSITORY"),
("github_ref", "GITHUB_REF"),
("github_sha", "GITHUB_SHA"),
("github_run_id", "GITHUB_RUN_ID"),
("github_run_number", "GITHUB_RUN_NUMBER"),
("github_workflow", "GITHUB_WORKFLOW"),
("github_actor", "GITHUB_ACTOR"),
("github_event_name", "GITHUB_EVENT_NAME"),
("github_server_url", "GITHUB_SERVER_URL"),
]
ci_info = {}
for key, env_var in github_env_vars:
value = os.getenv(env_var)
if value:
ci_info[key] = value
if ci_info:
metadata["ci"] = ci_info
# Build timestamp
metadata["generated_at"] = datetime.datetime.utcnow().isoformat() + "Z"
# Add link to the CI job if we have the necessary info
if all(os.getenv(var) for var in ["GITHUB_SERVER_URL", "GITHUB_REPOSITORY", "GITHUB_RUN_ID"]):
job_url = f"{os.getenv('GITHUB_SERVER_URL')}/{os.getenv('GITHUB_REPOSITORY')}/actions/runs/{os.getenv('GITHUB_RUN_ID')}"
metadata["ci_job_url"] = job_url
return metadata
def main() -> None:
exit_code = _main()
sys.exit(exit_code)
@@ -93,6 +135,23 @@ def _main() -> int:
logging.info("using config:")
logging.info(json.dumps(config, indent=2))
# Collect build metadata from the environment
build_metadata = None
# Convert string argument to boolean
include_metadata_str = str(args.include_build_metadata).lower()
include_metadata = include_metadata_str not in ["false", "0", "no"] and not args.exclude_build_metadata
# Also check for environment variable (for Docker action support)
include_metadata_env = os.getenv("INCLUDE_BUILD_METADATA", "true").lower()
if include_metadata_env in ["false", "0", "no"]:
include_metadata = False
if include_metadata:
build_metadata = collect_build_metadata(args.config)
logging.info("build metadata:")
logging.info(json.dumps(build_metadata, indent=2))
name_to_asset = get_release_assets(tag=tag, github_repository=repo)
logging.info(json.dumps(name_to_asset, indent=2))
@@ -111,6 +170,7 @@ def _main() -> int:
platform_entries,
include_http_provider=not exclude_http_provider,
include_github_release_provider=not exclude_github_release_provider,
build_metadata=build_metadata,
)
logging.info(manifest_file_contents)
@@ -150,6 +210,7 @@ def generate_manifest_file(
platform_entries,
include_http_provider: bool,
include_github_release_provider: bool,
build_metadata: Optional[Dict[str, Any]] = None,
) -> str:
platforms = {}
with tempfile.TemporaryDirectory() as temp_dir:
@@ -224,6 +285,10 @@ def generate_manifest_file(
"name": name,
"platforms": platforms,
}
# Add build metadata if available
if build_metadata:
manifest["build_metadata"] = build_metadata
return f"""#!/usr/bin/env dotslash
@@ -458,6 +523,19 @@ def parse_args():
default=os.getenv("GITHUB_WORKSPACE"),
)
parser.add_argument(
"--include-build-metadata",
type=str,
default="true",
help="include build metadata in the generated DotSlash files (default: true)",
)
parser.add_argument(
"--exclude-build-metadata",
action="store_true",
help="exclude build metadata from the generated DotSlash files",
)
return parser.parse_args()