Skip to content

Commit

Permalink
Add input to output full esp-web-tools manifest (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
jesserockz authored Aug 1, 2024
1 parent cedc256 commit e8be2d3
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 40 deletions.
19 changes: 13 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ concurrency:

jobs:
build:
name: Build test configuration for esphome:${{ matrix.esphome-version }}
name: Build test configuration for esphome:${{ matrix.esphome-version }} with ${{ matrix.manifest }} manifest
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand All @@ -28,6 +28,9 @@ jobs:
- stable
- beta
- dev
manifest:
- complete
- partial
steps:
- name: Checkout
uses: actions/checkout@v4.1.7
Expand All @@ -41,16 +44,17 @@ jobs:
cache: true
release_summary: "Test release summary"
release_url: "https://github.com/esphome/build-action"
complete-manifest: ${{ matrix.manifest == 'complete' }}
- name: Write version to file
run: echo ${{ steps.esphome-build.outputs.version }} > ${{ steps.esphome-build.outputs.name }}/version
- name: Upload ESPHome binary
uses: actions/upload-artifact@v4.3.4
with:
name: build-output-files-${{ matrix.esphome-version }}
name: build-output-files-${{ matrix.esphome-version }}-${{ matrix.manifest }}
path: ${{ steps.esphome-build.outputs.name }}

verify:
name: Verify output files for esphome:${{ matrix.esphome-version }}
name: Verify output files for esphome:${{ matrix.esphome-version }} with ${{ matrix.manifest }} manifest
runs-on: ubuntu-latest
needs: build
strategy:
Expand All @@ -60,20 +64,23 @@ jobs:
- stable
- beta
- dev
manifest:
- complete
- partial
steps:
- name: Checkout
uses: actions/checkout@v4.1.7
- name: Download files
uses: actions/download-artifact@v4.1.8
with:
name: build-output-files-${{ matrix.esphome-version }}
name: build-output-files-${{ matrix.esphome-version }}-${{ matrix.manifest }}

- name: List files
run: |-
ls -al
tree
- name: Validate json file matches manifest-template.json
- name: Validate json file matches ${{ matrix.manifest }} manifest-template.json
run: |
jq -n --arg md5 "$(md5sum test-esp32.ota.bin | head -c 32)" -f tests/manifest-template.json > /tmp/manifest.json
jq -n --arg md5 "$(md5sum test-esp32.ota.bin | head -c 32)" -f tests/${{ matrix.manifest }}-manifest-template.json > /tmp/manifest.json
diff <(jq --sort-keys . /tmp/manifest.json) <(jq --sort-keys . manifest.json)
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
venv
*.bin
*.json
!/tests/manifest-template.json
!/tests/*manifest-template.json
config/
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ This action is used by the [ESPHome publish workflow](https://github.com/esphome
## Inputs
| Name | Default | Description |
| ----------------- | ------------- | --------------------------------------------------------------------------------- |
| `yaml_file` | _None_ | The YAML file to be compiled. |
| `version` | `latest` | The ESPHome version to build using. |
| `platform` | `linux/amd64` | The docker platform to use during build. (linux/amd64, linux/arm64, linux/arm/v7) |
| `cache` | `false` | Whether to cache the build folder. |
| `release_summary` | _None_ | A small summary of the release that will be added to the manifest file. |
| `release_url` | _None_ | A URL to the release page that will be added to the manifest file. |
| Name | Default | Description |
| ------------------- | ------------- | --------------------------------------------------------------------------------------- |
| `yaml_file` | _None_ | The YAML file to be compiled. |
| `version` | `latest` | The ESPHome version to build using. |
| `platform` | `linux/amd64` | The docker platform to use during build. (linux/amd64, linux/arm64, linux/arm/v7) |
| `cache` | `false` | Whether to cache the build folder. |
| `release_summary` | _None_ | A small summary of the release that will be added to the manifest file. |
| `release_url` | _None_ | A URL to the release page that will be added to the manifest file. |
| `complete-manifest` | `false` | Whether to output a complete manifest file. Defaults to output a partial manifest only. |

## Outputs

Expand All @@ -41,6 +42,8 @@ This action is used by the [ESPHome publish workflow](https://github.com/esphome

This action will output a folder named with the output `name` and will contain three files:

- `manifest.json` - This goes into the `builds` section of an esp-web-tools manifest.json.
- `manifest.json`
- If `complete-manifest` is set to `true` then this file is directly usable by esp-web-tools.
- Otherwise, this goes into the `builds` section of an esp-web-tools manifest.json.
- `{name}.factory.bin` - The firmware to be flashed with esp-web-tools.
- `{name}.ota.bin` - The firmware that can be flashed over-the-air to the device using the [Managed Updated via HTTP Request](https://esphome.io/components/update/http_request).
25 changes: 15 additions & 10 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ inputs:
description: Release URL
required: false
default: ""
complete-manifest:
description: Output complete esp-web-tools manifest.json
required: false
default: false

outputs:
name:
Expand Down Expand Up @@ -94,16 +98,17 @@ runs:
id: build-step
run: |-
docker run --rm \
--platform ${{ inputs.platform }} \
--workdir /github/workspace \
-v "$(pwd)":"/github/workspace" -v "$HOME:$HOME" \
--user $(id -u):$(id -g) \
-e HOME \
esphome:${{ inputs.version }} \
${{ inputs.yaml_file }} \
--release-summary "${{ inputs.release_summary }}" \
--release-url "${{ inputs.release_url }}" \
--outputs-file "$GITHUB_OUTPUT"
--platform ${{ inputs.platform }} \
--workdir /github/workspace \
-v "$(pwd)":"/github/workspace" -v "$HOME:$HOME" \
--user $(id -u):$(id -g) \
-e HOME \
esphome:${{ inputs.version }} \
${{ inputs.yaml_file }} \
--release-summary "${{ inputs.release_summary }}" \
--release-url "${{ inputs.release_url }}" \
--outputs-file "$GITHUB_OUTPUT" \
${{ inputs.complete-manifest == 'true' && '--complete-manifest' || '--partial-manifest' }}
branding:
icon: "archive"
Expand Down
72 changes: 58 additions & 14 deletions entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@
from __future__ import annotations

import argparse
from dataclasses import dataclass
import hashlib
import json
import re
import shutil
import subprocess
import sys
from dataclasses import dataclass
from pathlib import Path

import yaml


ESP32_CHIP_FAMILIES = {
"ESP32": "ESP32",
"ESP32S2": "ESP32-S2",
Expand All @@ -30,6 +29,21 @@ def parse_args(argv):
parser.add_argument("--release-summary", help="Release summary", nargs="?")
parser.add_argument("--release-url", help="Release URL", nargs="?")

complete_parser = parser.add_mutually_exclusive_group()
complete_parser.add_argument(
"--complete-manifest",
help="Write complete esp-web-tools manifest.json",
action="store_true",
dest="complete_manifest",
)
complete_parser.add_argument(
"--partial-manifest",
help="Write partial esp-web-tools manifest.json",
action="store_false",
dest="complete_manifest",
)
parser.set_defaults(complete_manifest=False)

parser.add_argument("--outputs-file", help="GitHub Outputs file", nargs="?")

return parser.parse_args(argv[1:])
Expand Down Expand Up @@ -57,7 +71,7 @@ def get_esphome_version(outputs_file: str | None) -> tuple[str, int]:
print("::endgroup::")
return "", e.returncode

version = version.decode("utf-8")
version = version.decode("utf-8").strip()
print(version)
version = version.split(" ")[1].strip()
if outputs_file:
Expand All @@ -74,6 +88,10 @@ class Config:
name: str
platform: str
original_name: str
friendly_name: str | None = None

project_name: str | None = None
project_version: str | None = None

raw_config: dict | None = None

Expand Down Expand Up @@ -115,6 +133,7 @@ def get_config(filename: Path, outputs_file: str | None) -> tuple[Config | None,
config = yaml.load(config, Loader=yaml.FullLoader)

original_name = config["esphome"]["name"]
friendly_name = config["esphome"].get("friendly_name")

if outputs_file:
with open(outputs_file, "a", encoding="utf-8") as output:
Expand All @@ -135,13 +154,24 @@ def get_config(filename: Path, outputs_file: str | None) -> tuple[Config | None,
print(f"name={name}", file=output)

if project_config := config["esphome"].get("project"):
project_name = project_config["name"]
project_version = project_config["version"]
if outputs_file:
with open(outputs_file, "a", encoding="utf-8") as output:
print(f"project-name={project_config['name']}", file=output)
print(f"project-version={project_config['version']}", file=output)
print(f"project-name={project_name}", file=output)
print(f"project-version={project_version}", file=output)
else:
project_name = None
project_version = None
print("::endgroup::")
return Config(
name=name, platform=platform, original_name=original_name, raw_config=config
name=name,
platform=platform,
original_name=original_name,
raw_config=config,
friendly_name=friendly_name,
project_name=project_name,
project_version=project_version,
), 0


Expand All @@ -161,15 +191,14 @@ def get_idedata(filename: Path) -> tuple[dict | None, int]:
return data, 0


def generate_manifest(
def generate_manifest_part(
idedata: dict,
factory_bin: Path,
ota_bin: Path,
release_summary: str | None,
release_url: str | None,
) -> tuple[dict | None, int]:
"""Generate the manifest."""
print("::group::Generate manifest")

chip_family = None
define: str
Expand Down Expand Up @@ -216,10 +245,6 @@ def generate_manifest(
}
]

print("Writing manifest file:")
print(json.dumps(manifest, indent=2))

print("::endgroup::")
return manifest, 0


Expand All @@ -232,7 +257,7 @@ def main(argv) -> int:
if (rc := compile_firmware(filename)) != 0:
return rc

_, rc = get_esphome_version(args.outputs_file)
esphome_version, rc = get_esphome_version(args.outputs_file)
if rc != 0:
return rc

Expand Down Expand Up @@ -261,11 +286,14 @@ def main(argv) -> int:
file_base.mkdir(parents=True, exist_ok=True)

shutil.copyfile(source_factory_bin, dest_factory_bin)
print("Copied factory binary to:", dest_factory_bin)
shutil.copyfile(source_ota_bin, dest_ota_bin)
print("Copied OTA binary to:", dest_ota_bin)

print("::endgroup::")

manifest, rc = generate_manifest(
print("::group::Generate manifest")
manifest, rc = generate_manifest_part(
idedata,
dest_factory_bin,
dest_ota_bin,
Expand All @@ -275,9 +303,25 @@ def main(argv) -> int:
if rc != 0:
return rc

if args.complete_manifest:
manifest = {
"name": config.friendly_name or config.original_name,
"version": config.project_version or esphome_version,
"home_assistant_domain": "esphome",
"new_install_prompt_erase": False,
"builds": [
manifest,
],
}

print("Writing manifest file:")
print(json.dumps(manifest, indent=2))

with open(file_base / "manifest.json", "w", encoding="utf-8") as f:
json.dump(manifest, f, indent=2)

print("::endgroup::")

return 0


Expand Down
23 changes: 23 additions & 0 deletions tests/complete-manifest-template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "test",
"version": "3.5.0",
"home_assistant_domain": "esphome",
"new_install_prompt_erase": false,
"builds": [
{
"chipFamily": "ESP32",
"ota": {
"path": "test-esp32/test-esp32.ota.bin",
"md5": "\($md5)",
"summary": "Test release summary",
"release_url": "https://github.com/esphome/build-action"
},
"parts": [
{
"path": "test-esp32/test-esp32.factory.bin",
"offset": 0
}
]
}
]
}
File renamed without changes.

0 comments on commit e8be2d3

Please sign in to comment.