Skip to content

Commit eb45858

Browse files
committed
Initial commit
0 parents  commit eb45858

106 files changed

Lines changed: 17439 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
name: Submit OTA (URL)
2+
description: Submit new or updated OTA files by providing a download URL (recommended).
3+
labels: ["ota-submit"]
4+
body:
5+
- type: markdown
6+
attributes:
7+
value: |
8+
**Title:** Please enter a descriptive title above, like: `Add manufacturer smart plug v1.2.3`
9+
- type: input
10+
attributes:
11+
label: OTA image URL
12+
description: |
13+
URL where the OTA file can be downloaded. This should be a direct link to the OTA file.\
14+
Ideally, this is a link from the manufacturer's official website or repository.
15+
placeholder: "https://example.com/releases/firmware-v1.2.3.ota"
16+
validations:
17+
required: true # false
18+
- type: input
19+
id: manufacturer_name
20+
attributes:
21+
label: Manufacturer name
22+
description: |
23+
The device manufacturer's name for display purposes only (e.g., in the generated PR).\
24+
The actual storage location is determined automatically from the manufacturer ID inside the OTA file.
25+
placeholder: "Example: Aeotec"
26+
validations:
27+
required: false
28+
- type: textarea
29+
attributes:
30+
label: Release notes
31+
description: |
32+
A short description of what's new in this firmware version. Use bullet points to list changes.
33+
placeholder: |
34+
- Bug fixes
35+
- New features
36+
- etc.
37+
validations:
38+
required: false
39+
# Third-party download option is currently disabled. It works fine, but we don't want to encourage its use yet.
40+
# - type: checkboxes
41+
# id: third_party_download
42+
# attributes:
43+
# label: Third-party download (external hosting)
44+
# description: |
45+
# If checked, the OTA image file will **NOT** be stored in this repository.\
46+
# Instead, it will always be downloaded from the URL you provided above when generating the index.
47+
#
48+
# **You generally want to leave this unchecked** to ensure the OTA image is stored in this repository for reliability.\
49+
# **Note:** If the external URL becomes unavailable, the OTA image will no longer be accessible.
50+
#
51+
# **Note:** This option is just for testing and will likely not be available in the first zigpy-ota release.
52+
# options:
53+
# - label: Store OTA image externally (always download from provided URL)
54+
- type: dropdown
55+
attributes:
56+
label: How to handle existing images of the same type
57+
description: |
58+
Choose how to handle any existing images with the same manufacturer ID and image type.\
59+
Note: Older images are always kept for historic purposes. Newer images are always preferred by zigpy, so older images will only be used if they have constraints that make them more specific.
60+
61+
- **Keep all**: Keep all existing images without setting version constraints (newer images will always be preferred).\
62+
Use this when adding a new image or when the new image fully replaces older versions without requiring intermediate upgrade steps.
63+
- **Set version constraint**: Keep existing images and automatically set `min_current_file_version` to the highest existing version (that's still older than the new image).\
64+
Use this when the new image requires the device to first have the older firmware version already present in the repository (multi-step upgrades).
65+
options:
66+
- Keep all (standard)
67+
- Keep all with version constraint (multi-step)
68+
# We're now keeping all images by default. Older ones just aren't used anymore, so we hide the replacement option for now.
69+
# - Replace existing images with the same manufacturer ID and image type
70+
# - Keep existing images and set min_current_file_version to highest existing version
71+
# - Keep all existing images without automatic version constraints
72+
validations:
73+
required: true
74+
- type: textarea
75+
attributes:
76+
label: Optional metadata
77+
description: |
78+
Optional metadata fields for the OTA image. Provide as YAML key-value pairs.\
79+
This can most likely be left empty (GitHub placeholders will still show in text field below).
80+
81+
Supported fields: `manufacturer_names`, `model_names`, `min_current_file_version`, `max_current_file_version`, `min_hardware_version`, `max_hardware_version`, `specificity`, `channel`, `disabled`
82+
83+
**Example:** To restrict this firmware to only specific device models, set `model_names` to a list of model names that should match. The image will only be applied to devices that match both the manufacturer/image type AND one of the specified model names. Example: `model_names: [Model A]`
84+
85+
**Channel:** Set `channel` to `beta` or `dev` to make the image available only in non-stable release channels.
86+
placeholder: |
87+
manufacturer_names: [Manufacturer 1, Manufacturer 2]
88+
model_names: [Model 1, Model 2]
89+
min_hardware_version: 2
90+
max_hardware_version: 10
91+
min_current_file_version: 20
92+
max_current_file_version: 100
93+
channel: beta
94+
validations:
95+
required: false
96+
- type: checkboxes
97+
attributes:
98+
label: Checklist
99+
description: |
100+
Check the boxes that apply to your submission. Please answer truthfully.
101+
**Note:** You do NOT need to check all of these before submitting the image.
102+
options:
103+
- label: The OTA image provided is in a supported format (e.g., .zigbee, .ota)
104+
required: true
105+
- label: The OTA image URL provided is from an official source (e.g., manufacturer's website, official repository)
106+
- label: I have filled out the release notes to the best of my ability
107+
- label: The OTA image is tested and verified to work on a physical device
108+
- type: textarea
109+
attributes:
110+
label: Additional information
111+
description: |
112+
If you have additional information or context about the OTA image, provide it here.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
name: Submit OTA (File Upload)
2+
description: Submit new or updated OTA files by uploading them directly.
3+
labels: ["ota-submit"]
4+
body:
5+
- type: markdown
6+
attributes:
7+
value: |
8+
**Title:** Please enter a descriptive title above, like: `Add manufacturer smart plug v1.2.3`
9+
- type: textarea
10+
attributes:
11+
label: OTA file
12+
description: |
13+
Upload **one** OTA file here. **Please ZIP the OTA file first**, then drag-and-drop the ZIP file here.\
14+
**Note:** Only upload one OTA image per issue. If you need to submit multiple images, please create a separate issue for each.
15+
placeholder: |
16+
Drag-and-drop the zipped OTA file here.
17+
validations:
18+
required: true
19+
- type: input
20+
id: manufacturer_name
21+
attributes:
22+
label: Manufacturer name
23+
description: |
24+
The device manufacturer's name for display purposes only (e.g., in the generated PR).\
25+
The actual storage location is determined automatically from the manufacturer ID inside the OTA file.
26+
placeholder: "Example: Aeotec"
27+
validations:
28+
required: false
29+
- type: textarea
30+
attributes:
31+
label: Release notes
32+
description: |
33+
A short description of what's new in this firmware version. Use bullet points to list changes.
34+
placeholder: |
35+
- Bug fixes
36+
- New features
37+
- etc.
38+
validations:
39+
required: false
40+
- type: dropdown
41+
attributes:
42+
label: How to handle existing images of the same type
43+
description: |
44+
Choose how to handle any existing images with the same manufacturer ID and image type.\
45+
Note: Older images are always kept for historic purposes. Newer images are always preferred by zigpy, so older images will only be used if they have constraints that make them more specific.
46+
47+
- **Keep all**: Keep all existing images without setting version constraints (newer images will always be preferred).\
48+
Use this when adding a new image or when the new image fully replaces older versions without requiring intermediate upgrade steps.
49+
- **Set version constraint**: Keep existing images and automatically set `min_current_file_version` to the highest existing version (that's still older than the new image).\
50+
Use this when the new image requires the device to first have the older firmware version already present in the repository (multi-step upgrades).
51+
options:
52+
- Keep all (standard)
53+
- Keep all with version constraint (multi-step)
54+
# We're now keeping all images by default. Older ones just aren't used anymore, so we hide the replacement option for now.
55+
# - Replace existing images with the same manufacturer ID and image type
56+
# - Keep existing images and set min_current_file_version to highest existing version
57+
# - Keep all existing images without automatic version constraints
58+
validations:
59+
required: true
60+
- type: textarea
61+
attributes:
62+
label: Optional metadata
63+
description: |
64+
Optional metadata fields for the OTA image. Provide as YAML key-value pairs.\
65+
This can most likely be left empty (GitHub placeholders will still show in text field below).
66+
67+
Supported fields: `manufacturer_names`, `model_names`, `min_current_file_version`, `max_current_file_version`, `min_hardware_version`, `max_hardware_version`, `specificity`, `channel`, `disabled`
68+
69+
**Example:** To restrict this firmware to only specific device models, set `model_names` to a list of model names that should match. The image will only be applied to devices that match both the manufacturer/image type AND one of the specified model names. Example: `model_names: [Model A]`
70+
71+
**Channel:** Set `channel` to `beta` or `dev` to make the image available only in non-stable release channels.
72+
placeholder: |
73+
manufacturer_names: [Manufacturer 1, Manufacturer 2]
74+
model_names: [Model 1, Model 2]
75+
min_hardware_version: 2
76+
max_hardware_version: 10
77+
min_current_file_version: 20
78+
max_current_file_version: 100
79+
channel: beta
80+
validations:
81+
required: false
82+
- type: checkboxes
83+
attributes:
84+
label: Checklist
85+
description: |
86+
Check the boxes that apply to your submission. Please answer truthfully.
87+
**Note:** You do NOT need to check all of these before submitting the image.
88+
options:
89+
- label: The OTA image provided is in a supported format (e.g., .zigbee, .ota, or a ZIP containing one of these)
90+
required: true
91+
- label: I have filled out the release notes to the best of my ability
92+
- label: The OTA image is tested and verified to work on a physical device
93+
- type: textarea
94+
attributes:
95+
label: Additional information
96+
description: |
97+
If you have additional information or context about the OTA image, provide it here.

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## Proposed change
2+
3+
## Checklist
4+
5+
<!--
6+
Put an 'x' in all boxes that apply, like this: [x].
7+
Note: Please answer the checklist questions truthfully.
8+
Do not tick a box if you are unsure. You can still create the PR.
9+
-->
10+
11+
- [ ] New OTA images are added to the `images` directory
12+
- [ ] The OTA image provided is in a supported format (e.g., .zigbee, .ota)
13+
- [ ] A YAML file with the same name as the image and a `.yaml` extension is added to the `images` directory
14+
- [ ] I have the rights to distribute this OTA image
15+
- [ ] The OTA images are tested and verified to work on a physical device

.github/scripts/create-pr.sh

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#!/usr/bin/env bash
2+
# Creates or updates a PR for an OTA submission
3+
#
4+
# Required environment variables:
5+
# GH_TOKEN - GitHub token for gh CLI
6+
# BRANCH_NAME - Branch name for the PR
7+
# ISSUE_NUMBER - GitHub issue number
8+
# ISSUE_TITLE - GitHub issue title
9+
# ISSUE_AUTHOR_LOGIN - GitHub username of issue creator
10+
# ISSUE_AUTHOR_ID - GitHub user ID of issue creator
11+
# PR_BODY_FILE - Path to file containing PR body markdown
12+
#
13+
# Optional environment variables:
14+
# COMMIT_MSG_FILE - Path to file containing detailed commit message
15+
16+
set -euo pipefail
17+
18+
# Add pull_request field to YAML files and commit
19+
# Returns 0 if changes were committed, 1 if no YAML files to update
20+
add_pr_to_yaml_files() {
21+
local pr_number="$1"
22+
local yaml_files
23+
yaml_files=$(git diff --name-only HEAD~1 HEAD -- 'images/*.yaml' 'images/**/*.yaml' || true)
24+
25+
if [ -z "$yaml_files" ]; then
26+
echo "No YAML files to update"
27+
return 1
28+
fi
29+
30+
echo "Adding pull_request field to YAML files..."
31+
for yaml_file in $yaml_files; do
32+
if [ -f "$yaml_file" ] && ! grep -q "^pull_request:" "$yaml_file"; then
33+
echo "Updating $yaml_file"
34+
# Insert pull_request after source_url if present, otherwise after source_file_name
35+
if grep -q "^source_url:" "$yaml_file"; then
36+
sed -i "s|^source_url:.*|&\npull_request: $pr_number|" "$yaml_file"
37+
else
38+
sed -i "s|^source_file_name:.*|&\npull_request: $pr_number|" "$yaml_file"
39+
fi
40+
fi
41+
done
42+
43+
git add images/
44+
if git diff --cached --quiet; then
45+
echo "No changes to commit (all files already had pull_request field)"
46+
return 1
47+
fi
48+
git commit -m "Add PR number to YAML metadata"
49+
return 0
50+
}
51+
52+
# Check if PR already exists (for resubmits) so we can get PR number early
53+
EXISTING_PR_NUMBER=$(gh pr view "$BRANCH_NAME" --json number --jq '.number' 2>/dev/null || echo "")
54+
if [ -n "$EXISTING_PR_NUMBER" ]; then
55+
echo "Existing PR found: #$EXISTING_PR_NUMBER"
56+
fi
57+
58+
# Delete local branch if it exists and create new one
59+
git branch -D "$BRANCH_NAME" 2>/dev/null || true
60+
git checkout -b "$BRANCH_NAME"
61+
62+
# Add changes in images directory
63+
git add images/
64+
65+
# Get issue creator information for co-authoring
66+
ISSUE_AUTHOR_NAME=$(gh api /users/"$ISSUE_AUTHOR_LOGIN" --jq '.name // .login')
67+
ISSUE_AUTHOR_EMAIL="${ISSUE_AUTHOR_ID}+${ISSUE_AUTHOR_LOGIN}@users.noreply.github.com"
68+
69+
# First commit: Add OTA files
70+
COMMIT_TITLE="Add OTA files from issue #${ISSUE_NUMBER}"
71+
COMMIT_FOOTER="Closes: #${ISSUE_NUMBER}
72+
Co-authored-by: ${ISSUE_AUTHOR_NAME} <${ISSUE_AUTHOR_EMAIL}>"
73+
74+
if [ -n "${COMMIT_MSG_FILE:-}" ] && [ -f "$COMMIT_MSG_FILE" ]; then
75+
# Include commit file as body with footer
76+
COMMIT_BODY=$(cat "$COMMIT_MSG_FILE")
77+
FULL_MSG=$(printf '%s\n\n%s\n\n%s' "$COMMIT_TITLE" "$COMMIT_BODY" "$COMMIT_FOOTER")
78+
git commit -m "$FULL_MSG"
79+
else
80+
git commit -m "$COMMIT_TITLE" -m "$COMMIT_FOOTER"
81+
fi
82+
83+
# Build PR body with footer
84+
PR_BODY=$(cat "$PR_BODY_FILE")
85+
PR_BODY_WITH_FOOTER="${PR_BODY}
86+
87+
---
88+
89+
- Closes #${ISSUE_NUMBER}
90+
- Submitted by @${ISSUE_AUTHOR_LOGIN}"
91+
92+
if [ -n "$EXISTING_PR_NUMBER" ]; then
93+
# Resubmit: We have the PR number, so we can create both commits and push once
94+
add_pr_to_yaml_files "$EXISTING_PR_NUMBER" || true
95+
git push -f origin "$BRANCH_NAME"
96+
gh pr edit "$EXISTING_PR_NUMBER" --title "$ISSUE_TITLE" --body "$PR_BODY_WITH_FOOTER"
97+
else
98+
# New PR: Must push first to create PR, then add second commit
99+
git push -f origin "$BRANCH_NAME"
100+
101+
echo "Creating new PR..."
102+
PR_URL=$(gh pr create \
103+
--title "$ISSUE_TITLE" \
104+
--body "$PR_BODY_WITH_FOOTER" \
105+
--label "ota-submit" \
106+
--base dev)
107+
PR_NUMBER="${PR_URL##*/}"
108+
109+
add_pr_to_yaml_files "$PR_NUMBER" || true
110+
git push origin "$BRANCH_NAME"
111+
fi
112+
113+
# Add "ota-processed" label to the issue
114+
gh issue edit "$ISSUE_NUMBER" --add-label "ota-processed"

0 commit comments

Comments
 (0)