@switchbot/homebridge-switchbot 4.3.2-beta.9 → 4.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/copilot-instructions.md +328 -0
- package/.github/scripts/npm-version-script-esm-auto.js +207 -0
- package/.github/workflows/beta-release.yml +8 -12
- package/.github/workflows/release.yml +54 -22
- package/CHANGELOG.md +1 -1
- package/README.md +13 -10
- package/config.schema.json +2 -2
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +15847 -0
- package/coverage/coverage-final.json +42 -0
- package/coverage/docs/assets/dmt/dmt-component-data.js.html +85 -0
- package/coverage/docs/assets/dmt/dmt-components.js.html +286 -0
- package/coverage/docs/assets/dmt/index.html +131 -0
- package/coverage/docs/assets/hierarchy.js.html +85 -0
- package/coverage/docs/assets/icons.js.html +136 -0
- package/coverage/docs/assets/index.html +146 -0
- package/coverage/docs/assets/main.js.html +265 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +191 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/coverage/src/device/blindtilt.ts.html +3238 -0
- package/coverage/src/device/bot.ts.html +2803 -0
- package/coverage/src/device/ceilinglight.ts.html +2338 -0
- package/coverage/src/device/colorbulb.ts.html +2824 -0
- package/coverage/src/device/contact.ts.html +1465 -0
- package/coverage/src/device/curtain.ts.html +2869 -0
- package/coverage/src/device/device.ts.html +2500 -0
- package/coverage/src/device/fan.ts.html +2242 -0
- package/coverage/src/device/hub.ts.html +1408 -0
- package/coverage/src/device/humidifier.ts.html +2116 -0
- package/coverage/src/device/index.html +416 -0
- package/coverage/src/device/iosensor.ts.html +1375 -0
- package/coverage/src/device/lightstrip.ts.html +2617 -0
- package/coverage/src/device/lock.ts.html +1963 -0
- package/coverage/src/device/meter.ts.html +1372 -0
- package/coverage/src/device/meterplus.ts.html +1384 -0
- package/coverage/src/device/meterpro.ts.html +1618 -0
- package/coverage/src/device/motion.ts.html +1264 -0
- package/coverage/src/device/plug.ts.html +1372 -0
- package/coverage/src/device/relayswitch.ts.html +2284 -0
- package/coverage/src/device/robotvacuumcleaner.ts.html +1810 -0
- package/coverage/src/device/waterdetector.ts.html +1294 -0
- package/coverage/src/homebridge-ui/index.html +116 -0
- package/coverage/src/homebridge-ui/server.ts.html +229 -0
- package/coverage/src/index.html +161 -0
- package/coverage/src/index.ts.html +124 -0
- package/coverage/src/irdevice/airconditioner.ts.html +1687 -0
- package/coverage/src/irdevice/airpurifier.ts.html +844 -0
- package/coverage/src/irdevice/camera.ts.html +475 -0
- package/coverage/src/irdevice/fan.ts.html +766 -0
- package/coverage/src/irdevice/index.html +251 -0
- package/coverage/src/irdevice/irdevice.ts.html +1117 -0
- package/coverage/src/irdevice/light.ts.html +826 -0
- package/coverage/src/irdevice/other.ts.html +2458 -0
- package/coverage/src/irdevice/tv.ts.html +1222 -0
- package/coverage/src/irdevice/vacuumcleaner.ts.html +466 -0
- package/coverage/src/irdevice/waterheater.ts.html +469 -0
- package/coverage/src/platform.ts.html +8776 -0
- package/coverage/src/settings.ts.html +934 -0
- package/coverage/src/utils.ts.html +2092 -0
- package/dist/device/blindtilt.d.ts.map +1 -1
- package/dist/device/blindtilt.js +12 -4
- package/dist/device/blindtilt.js.map +1 -1
- package/dist/device/bot.d.ts.map +1 -1
- package/dist/device/bot.js +12 -4
- package/dist/device/bot.js.map +1 -1
- package/dist/device/ceilinglight.d.ts.map +1 -1
- package/dist/device/ceilinglight.js +18 -7
- package/dist/device/ceilinglight.js.map +1 -1
- package/dist/device/colorbulb.d.ts.map +1 -1
- package/dist/device/colorbulb.js +18 -7
- package/dist/device/colorbulb.js.map +1 -1
- package/dist/device/contact.d.ts.map +1 -1
- package/dist/device/contact.js +6 -2
- package/dist/device/contact.js.map +1 -1
- package/dist/device/curtain.d.ts.map +1 -1
- package/dist/device/curtain.js +12 -4
- package/dist/device/curtain.js.map +1 -1
- package/dist/device/device.d.ts +5 -7
- package/dist/device/device.d.ts.map +1 -1
- package/dist/device/device.js +11 -5
- package/dist/device/device.js.map +1 -1
- package/dist/device/fan.d.ts.map +1 -1
- package/dist/device/fan.js +16 -6
- package/dist/device/fan.js.map +1 -1
- package/dist/device/hub.d.ts +2 -2
- package/dist/device/hub.d.ts.map +1 -1
- package/dist/device/hub.js +8 -3
- package/dist/device/hub.js.map +1 -1
- package/dist/device/humidifier.d.ts.map +1 -1
- package/dist/device/humidifier.js +16 -6
- package/dist/device/humidifier.js.map +1 -1
- package/dist/device/iosensor.d.ts.map +1 -1
- package/dist/device/iosensor.js +6 -2
- package/dist/device/iosensor.js.map +1 -1
- package/dist/device/lightstrip.d.ts.map +1 -1
- package/dist/device/lightstrip.js +16 -6
- package/dist/device/lightstrip.js.map +1 -1
- package/dist/device/lock.d.ts.map +1 -1
- package/dist/device/lock.js +12 -4
- package/dist/device/lock.js.map +1 -1
- package/dist/device/meter.d.ts.map +1 -1
- package/dist/device/meter.js +6 -2
- package/dist/device/meter.js.map +1 -1
- package/dist/device/meterplus.d.ts.map +1 -1
- package/dist/device/meterplus.js +6 -2
- package/dist/device/meterplus.js.map +1 -1
- package/dist/device/meterpro.d.ts.map +1 -1
- package/dist/device/meterpro.js +7 -4
- package/dist/device/meterpro.js.map +1 -1
- package/dist/device/motion.d.ts.map +1 -1
- package/dist/device/motion.js +6 -2
- package/dist/device/motion.js.map +1 -1
- package/dist/device/occupancy.d.ts +42 -0
- package/dist/device/occupancy.d.ts.map +1 -0
- package/dist/device/occupancy.js +349 -0
- package/dist/device/occupancy.js.map +1 -0
- package/dist/device/plug.d.ts.map +1 -1
- package/dist/device/plug.js +12 -4
- package/dist/device/plug.js.map +1 -1
- package/dist/device/relayswitch.d.ts.map +1 -1
- package/dist/device/relayswitch.js +12 -4
- package/dist/device/relayswitch.js.map +1 -1
- package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
- package/dist/device/robotvacuumcleaner.js +14 -5
- package/dist/device/robotvacuumcleaner.js.map +1 -1
- package/dist/device/waterdetector.d.ts.map +1 -1
- package/dist/device/waterdetector.js +6 -2
- package/dist/device/waterdetector.js.map +1 -1
- package/dist/homebridge-ui/public/index.html +1 -1
- package/dist/irdevice/airconditioner.d.ts.map +1 -1
- package/dist/irdevice/airconditioner.js +2 -1
- package/dist/irdevice/airconditioner.js.map +1 -1
- package/dist/irdevice/airpurifier.d.ts +1 -1
- package/dist/irdevice/airpurifier.d.ts.map +1 -1
- package/dist/irdevice/airpurifier.js +6 -5
- package/dist/irdevice/airpurifier.js.map +1 -1
- package/dist/irdevice/camera.d.ts.map +1 -1
- package/dist/irdevice/camera.js +2 -1
- package/dist/irdevice/camera.js.map +1 -1
- package/dist/irdevice/fan.d.ts.map +1 -1
- package/dist/irdevice/fan.js +2 -1
- package/dist/irdevice/fan.js.map +1 -1
- package/dist/irdevice/irdevice.d.ts +2 -6
- package/dist/irdevice/irdevice.d.ts.map +1 -1
- package/dist/irdevice/irdevice.js.map +1 -1
- package/dist/irdevice/light.d.ts.map +1 -1
- package/dist/irdevice/light.js +2 -1
- package/dist/irdevice/light.js.map +1 -1
- package/dist/irdevice/other.d.ts.map +1 -1
- package/dist/irdevice/other.js +2 -1
- package/dist/irdevice/other.js.map +1 -1
- package/dist/irdevice/tv.d.ts.map +1 -1
- package/dist/irdevice/tv.js +2 -1
- package/dist/irdevice/tv.js.map +1 -1
- package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
- package/dist/irdevice/vacuumcleaner.js +2 -1
- package/dist/irdevice/vacuumcleaner.js.map +1 -1
- package/dist/irdevice/waterheater.d.ts.map +1 -1
- package/dist/irdevice/waterheater.js +2 -1
- package/dist/irdevice/waterheater.js.map +1 -1
- package/dist/platform.d.ts +2 -2
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +77 -78
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +6 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +1 -0
- package/dist/settings.js.map +1 -1
- package/docs/index.html +20 -11
- package/docs/variables/default.html +1 -1
- package/eslint.config.js +0 -1
- package/package.json +9 -10
- package/src/device/blindtilt.ts +10 -4
- package/src/device/bot.ts +10 -4
- package/src/device/ceilinglight.ts +16 -7
- package/src/device/colorbulb.ts +16 -7
- package/src/device/contact.ts +5 -2
- package/src/device/curtain.ts +12 -6
- package/src/device/device.ts +14 -8
- package/src/device/fan.ts +14 -6
- package/src/device/hub.ts +10 -6
- package/src/device/humidifier.ts +14 -6
- package/src/device/iosensor.ts +5 -2
- package/src/device/lightstrip.ts +14 -6
- package/src/device/lock.ts +10 -4
- package/src/device/meter.ts +6 -3
- package/src/device/meterplus.ts +5 -2
- package/src/device/meterpro.ts +7 -5
- package/src/device/motion.ts +5 -2
- package/src/device/occupancy.ts +393 -0
- package/src/device/plug.ts +10 -4
- package/src/device/relayswitch.ts +10 -4
- package/src/device/robotvacuumcleaner.ts +12 -5
- package/src/device/waterdetector.ts +5 -2
- package/src/homebridge-ui/public/index.html +1 -1
- package/src/irdevice/airconditioner.ts +2 -1
- package/src/irdevice/airpurifier.ts +6 -5
- package/src/irdevice/camera.ts +2 -1
- package/src/irdevice/fan.ts +2 -1
- package/src/irdevice/irdevice.ts +2 -2
- package/src/irdevice/light.ts +2 -1
- package/src/irdevice/other.ts +2 -1
- package/src/irdevice/tv.ts +2 -1
- package/src/irdevice/vacuumcleaner.ts +2 -1
- package/src/irdevice/waterheater.ts +2 -1
- package/src/platform.ts +80 -88
- package/src/settings.ts +7 -0
- package/.github/npm-version-script-esm.js +0 -97
- package/.github/workflows/build.yml +0 -18
- package/.github/workflows/changerelease.yml +0 -11
- package/.github/workflows/labeler.yml +0 -16
- package/.github/workflows/release-drafter.yml +0 -14
- package/dist/device/airpurifier.d.ts +0 -54
- package/dist/device/airpurifier.d.ts.map +0 -1
- package/dist/device/airpurifier.js +0 -527
- package/dist/device/airpurifier.js.map +0 -1
- package/src/device/airpurifier.ts +0 -563
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
# Homebridge SwitchBot Plugin Development Guide
|
|
2
|
+
|
|
3
|
+
Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.
|
|
4
|
+
|
|
5
|
+
## Branch Targeting Strategy
|
|
6
|
+
|
|
7
|
+
When creating pull requests, ALWAYS follow this branch targeting strategy:
|
|
8
|
+
|
|
9
|
+
1. **Primary Target:** Look for branches that start with "beta-" (e.g., `beta-4.3.2`, `beta-4.4.0`)
|
|
10
|
+
- If a beta branch exists, target the most recent beta branch for your PR
|
|
11
|
+
- Beta branches are used for testing and staging changes before they go to the main branch
|
|
12
|
+
|
|
13
|
+
2. **Beta Branch Creation:** If no beta branches exist, create one based on the next possible version
|
|
14
|
+
- Parse the current version from `package.json` (e.g., "4.3.1")
|
|
15
|
+
- Determine version increment type using issue/PR labels (patch/minor/major)
|
|
16
|
+
- Calculate the appropriate next version based on detected labels
|
|
17
|
+
- Create a new beta branch with the format `beta-X.Y.Z` (e.g., `beta-4.3.2`)
|
|
18
|
+
- Base the new beta branch on the `latest` branch
|
|
19
|
+
- Push the new beta branch to origin and target it for the PR
|
|
20
|
+
|
|
21
|
+
3. **Fallback Target:** Only if beta branch creation fails, target the `latest` branch
|
|
22
|
+
- The `latest` branch is the main development branch when no beta releases are in progress
|
|
23
|
+
|
|
24
|
+
4. **Branch Detection and Creation:** Use these methods to check and create branches:
|
|
25
|
+
- **Detection:** GitHub API: Use `github-mcp-server-list_branches` to get all branches and filter for "beta-" prefix
|
|
26
|
+
- **Detection:** Git command: `git ls-remote --heads origin | grep beta | sort -V | tail -1` to find the latest beta branch
|
|
27
|
+
- **Version parsing:** Extract version from package.json: `node -p "require('./package.json').version"`
|
|
28
|
+
- **Label Detection:** Check for version increment labels on the issue/PR:
|
|
29
|
+
- Use GitHub API to get issue/PR labels
|
|
30
|
+
- Look for labels: `patch`, `minor`, `major`
|
|
31
|
+
- These labels should be set before assigning the issue to Copilot
|
|
32
|
+
- **Version Increment Logic:** Choose increment type based on detected labels:
|
|
33
|
+
- **patch label found:** `node -p "const v=require('./package.json').version.split('.'); v[2]=parseInt(v[2])+1; v.join('.')"` (4.3.1 → 4.3.2)
|
|
34
|
+
- **minor label found:** `node -p "const v=require('./package.json').version.split('.'); v[1]=parseInt(v[1])+1; v[2]='0'; v.join('.')"` (4.3.1 → 4.4.0)
|
|
35
|
+
- **major label found:** `node -p "const v=require('./package.json').version.split('.'); v[0]=parseInt(v[0])+1; v[1]='0'; v[2]='0'; v.join('.')"` (4.3.1 → 5.0.0)
|
|
36
|
+
- **No relevant labels:** Default to patch increment as fallback
|
|
37
|
+
- **Multiple increment labels:** Use highest priority (major > minor > patch)
|
|
38
|
+
- **Label-Based Beta Branch Creation:**
|
|
39
|
+
```bash
|
|
40
|
+
# Detect version increment type from issue/PR labels
|
|
41
|
+
# Use GitHub API: github-mcp-server-get_issue or github-mcp-server-get_pull_request
|
|
42
|
+
# Check labels array for: patch, minor, major
|
|
43
|
+
|
|
44
|
+
# Calculate next version based on detected labels
|
|
45
|
+
if [[ labels contains "major" ]]; then
|
|
46
|
+
NEXT_VERSION=$(node -p "const v=require('./package.json').version.split('.'); v[0]=parseInt(v[0])+1; v[1]='0'; v[2]='0'; v.join('.')")
|
|
47
|
+
elif [[ labels contains "minor" ]]; then
|
|
48
|
+
NEXT_VERSION=$(node -p "const v=require('./package.json').version.split('.'); v[1]=parseInt(v[1])+1; v[2]='0'; v.join('.')")
|
|
49
|
+
else
|
|
50
|
+
# Default to patch increment (includes when "patch" label found or no labels)
|
|
51
|
+
NEXT_VERSION=$(node -p "const v=require('./package.json').version.split('.'); v[2]=parseInt(v[2])+1; v.join('.')")
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
BETA_BRANCH="beta-${NEXT_VERSION}"
|
|
55
|
+
|
|
56
|
+
# Create and push the beta branch from latest
|
|
57
|
+
git fetch origin
|
|
58
|
+
git checkout -b "${BETA_BRANCH}" origin/latest
|
|
59
|
+
git push origin "${BETA_BRANCH}"
|
|
60
|
+
```
|
|
61
|
+
- Always verify the target branch exists before creating the PR
|
|
62
|
+
|
|
63
|
+
**NEVER target other branches** unless specifically instructed, and avoid targeting:
|
|
64
|
+
- Individual feature branches (copilot/*, fix/*, etc.)
|
|
65
|
+
- Release branches that are not beta branches
|
|
66
|
+
- The main branch directly
|
|
67
|
+
|
|
68
|
+
This ensures proper workflow where changes are tested in beta branches before being merged to the main development line.
|
|
69
|
+
|
|
70
|
+
### Branch Targeting Validation and Troubleshooting
|
|
71
|
+
|
|
72
|
+
**Before Starting Work:**
|
|
73
|
+
1. **Verify Issue Labels:** Check that the assigned issue has appropriate version increment labels (`patch`, `minor`, or `major`)
|
|
74
|
+
2. **Check Existing Beta Branches:** Use GitHub API or Git commands to identify current beta branches
|
|
75
|
+
3. **Validate Target Branch:** Confirm the target beta branch exists or can be created successfully
|
|
76
|
+
|
|
77
|
+
**Validation Commands:**
|
|
78
|
+
```bash
|
|
79
|
+
# Check for existing beta branches
|
|
80
|
+
git ls-remote --heads origin | grep "beta-" | sort -V
|
|
81
|
+
|
|
82
|
+
# Get current version for reference
|
|
83
|
+
node -p "require('./package.json').version"
|
|
84
|
+
|
|
85
|
+
# Example: Calculate next patch version
|
|
86
|
+
node -p "const v=require('./package.json').version.split('.'); v[2]=parseInt(v[2])+1; v.join('.')"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Troubleshooting Common Issues:**
|
|
90
|
+
- **No version labels on issue:** Proceed with patch increment but notify in PR description
|
|
91
|
+
- **Beta branch creation fails:** Fall back to targeting `latest` branch and document in PR
|
|
92
|
+
- **Multiple conflicting labels:** Use highest priority (major > minor > patch) and document decision
|
|
93
|
+
- **Network/API failures:** Use Git commands as fallback for branch detection
|
|
94
|
+
|
|
95
|
+
### Label Requirements for Version Management
|
|
96
|
+
|
|
97
|
+
**⚠️ CRITICAL REQUIREMENT:** Before assigning issues to Copilot, project maintainers **MUST** set appropriate version increment labels. This is required for proper branch targeting and version management.
|
|
98
|
+
|
|
99
|
+
**Required Labels:**
|
|
100
|
+
- **`patch`** - Bug fixes, documentation updates, minor improvements (4.3.1 → 4.3.2)
|
|
101
|
+
- **`minor`** - New features, device support additions, non-breaking enhancements (4.3.1 → 4.4.0)
|
|
102
|
+
- **`major`** - Breaking changes, API modifications, major architectural updates (4.3.1 → 5.0.0)
|
|
103
|
+
|
|
104
|
+
**Label Priority:** If multiple increment labels are present, the highest priority is used (major > minor > patch).
|
|
105
|
+
|
|
106
|
+
**Fallback Behavior:** If no version increment labels are found, the system defaults to patch increment to ensure conservative version management.
|
|
107
|
+
|
|
108
|
+
**Validation Process:** Copilot will:
|
|
109
|
+
1. Check for required labels on the assigned issue
|
|
110
|
+
2. Log a warning if no version increment labels are found
|
|
111
|
+
3. Proceed with patch increment as fallback
|
|
112
|
+
4. Create or target the appropriate beta branch based on version increment
|
|
113
|
+
|
|
114
|
+
## Working Effectively
|
|
115
|
+
|
|
116
|
+
### Bootstrap and Build Process
|
|
117
|
+
Run these commands in sequence to set up and build the project:
|
|
118
|
+
|
|
119
|
+
1. **Install dependencies:**
|
|
120
|
+
```bash
|
|
121
|
+
npm install --legacy-peer-deps
|
|
122
|
+
```
|
|
123
|
+
- CRITICAL: Must use `--legacy-peer-deps` flag due to TypeDoc dependency conflicts
|
|
124
|
+
- Takes approximately 30-45 seconds
|
|
125
|
+
- This is a known workaround documented in the codebase
|
|
126
|
+
|
|
127
|
+
2. **Build the project:**
|
|
128
|
+
```bash
|
|
129
|
+
npm run build
|
|
130
|
+
```
|
|
131
|
+
- Takes approximately 7-10 seconds
|
|
132
|
+
- Compiles TypeScript and copies UI files
|
|
133
|
+
- Output goes to `dist/` directory
|
|
134
|
+
|
|
135
|
+
3. **Run tests:**
|
|
136
|
+
```bash
|
|
137
|
+
npm run test
|
|
138
|
+
```
|
|
139
|
+
- Takes approximately 2-3 seconds
|
|
140
|
+
- Currently minimal test suite (1 test file)
|
|
141
|
+
- Use `npm run test:watch` for continuous testing during development
|
|
142
|
+
|
|
143
|
+
4. **Generate documentation:**
|
|
144
|
+
```bash
|
|
145
|
+
npm run docs
|
|
146
|
+
```
|
|
147
|
+
- Takes approximately 5-10 seconds
|
|
148
|
+
- Generates TypeDoc documentation in `docs/` directory
|
|
149
|
+
|
|
150
|
+
### Full Build and Validation Workflow
|
|
151
|
+
Complete validation workflow (approximately 30-45 seconds total):
|
|
152
|
+
```bash
|
|
153
|
+
npm install --legacy-peer-deps && npm run build && npm run test && npm run docs && npm run docs:lint && npm run docs:theme
|
|
154
|
+
```
|
|
155
|
+
- NEVER CANCEL: Set timeout to 90+ seconds for this complete workflow
|
|
156
|
+
- This validates TypeScript compilation, plugin loading, and documentation generation
|
|
157
|
+
|
|
158
|
+
### Development Commands
|
|
159
|
+
|
|
160
|
+
- **Watch mode for development:**
|
|
161
|
+
```bash
|
|
162
|
+
npm run watch
|
|
163
|
+
```
|
|
164
|
+
- Builds, links plugin locally, and starts nodemon for file watching
|
|
165
|
+
- Requires local Homebridge installation
|
|
166
|
+
|
|
167
|
+
- **Clean build artifacts:**
|
|
168
|
+
```bash
|
|
169
|
+
npm run clean
|
|
170
|
+
```
|
|
171
|
+
- Removes `dist/` directory
|
|
172
|
+
|
|
173
|
+
- **Check for outdated dependencies:**
|
|
174
|
+
```bash
|
|
175
|
+
npm run check
|
|
176
|
+
```
|
|
177
|
+
- WARNING: This will fail due to dependency conflicts - use with `--legacy-peer-deps`
|
|
178
|
+
|
|
179
|
+
### Known Issues and Workarounds
|
|
180
|
+
|
|
181
|
+
- **Linting fails:** `npm run lint` and `npm run lint:fix` currently fail due to ESLint configuration conflicts with import/extensions rule. Document any code style issues manually.
|
|
182
|
+
|
|
183
|
+
- **Dependency conflicts:** Always use `--legacy-peer-deps` flag for npm install due to TypeDoc theme dependency version mismatches.
|
|
184
|
+
|
|
185
|
+
- **Coverage and docs artifacts:** Add `coverage/` and `docs/` to `.gitignore` to prevent committing build artifacts.
|
|
186
|
+
|
|
187
|
+
## Validation Scenarios
|
|
188
|
+
|
|
189
|
+
### Manual Plugin Validation
|
|
190
|
+
After making changes, ALWAYS run these validation steps:
|
|
191
|
+
|
|
192
|
+
1. **Verify plugin builds and loads:**
|
|
193
|
+
```bash
|
|
194
|
+
npm run build && node -e "
|
|
195
|
+
try {
|
|
196
|
+
const plugin = require('./dist/index.js');
|
|
197
|
+
console.log('Plugin loads successfully');
|
|
198
|
+
console.log('Plugin type:', typeof plugin.default);
|
|
199
|
+
} catch (e) {
|
|
200
|
+
console.error('Plugin load failed:', e.message);
|
|
201
|
+
}"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
2. **Test plugin registration:**
|
|
205
|
+
- Plugin exports a default function that registers with Homebridge
|
|
206
|
+
- Uses `PLUGIN_NAME = '@switchbot/homebridge-switchbot'` and `PLATFORM_NAME = 'SwitchBot'`
|
|
207
|
+
- Main platform class is `SwitchBotPlatform`
|
|
208
|
+
|
|
209
|
+
3. **Validate TypeScript compilation:**
|
|
210
|
+
- Must have no TypeScript errors
|
|
211
|
+
- Check `dist/` directory contains all expected `.js`, `.d.ts`, and `.map` files
|
|
212
|
+
|
|
213
|
+
4. **Test documentation generation:**
|
|
214
|
+
```bash
|
|
215
|
+
npm run docs:lint
|
|
216
|
+
```
|
|
217
|
+
- Must pass without warnings when using `--treatWarningsAsErrors`
|
|
218
|
+
|
|
219
|
+
### Code Coverage Validation
|
|
220
|
+
Run comprehensive test coverage analysis:
|
|
221
|
+
```bash
|
|
222
|
+
npm run test-coverage
|
|
223
|
+
```
|
|
224
|
+
- Current coverage is minimal (~1.36% overall)
|
|
225
|
+
- Coverage reports generated in `coverage/` directory
|
|
226
|
+
|
|
227
|
+
## Codebase Navigation
|
|
228
|
+
|
|
229
|
+
### Project Structure
|
|
230
|
+
```
|
|
231
|
+
├── src/ # Source TypeScript files
|
|
232
|
+
│ ├── device/ # Device implementations (21 files)
|
|
233
|
+
│ │ ├── device.ts # Base device class (deviceBase)
|
|
234
|
+
│ │ ├── bot.ts # SwitchBot Bot device
|
|
235
|
+
│ │ ├── curtain.ts # SwitchBot Curtain device
|
|
236
|
+
│ │ └── ... # Other device implementations
|
|
237
|
+
│ ├── irdevice/ # IR device implementations (10 files)
|
|
238
|
+
│ │ ├── irdevice.ts # Base IR device class
|
|
239
|
+
│ │ ├── tv.ts # TV IR control
|
|
240
|
+
│ │ └── ... # Other IR device implementations
|
|
241
|
+
│ ├── homebridge-ui/ # Plugin configuration UI
|
|
242
|
+
│ │ ├── server.ts # UI backend server
|
|
243
|
+
│ │ └── public/ # UI frontend files
|
|
244
|
+
│ ├── platform.ts # Main platform class (SwitchBotPlatform)
|
|
245
|
+
│ ├── settings.ts # Configuration interfaces and constants
|
|
246
|
+
│ ├── utils.ts # Utility functions
|
|
247
|
+
│ └── index.ts # Plugin entry point
|
|
248
|
+
├── config.schema.json # Homebridge configuration schema
|
|
249
|
+
├── dist/ # Compiled JavaScript output
|
|
250
|
+
├── docs/ # Generated TypeDoc documentation
|
|
251
|
+
└── coverage/ # Test coverage reports
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Key Development Areas
|
|
255
|
+
|
|
256
|
+
- **Adding new devices:** Extend `src/device/device.ts` base class, implement in new file under `src/device/`
|
|
257
|
+
- **Adding IR devices:** Extend `src/irdevice/irdevice.ts` base class, implement in new file under `src/irdevice/`
|
|
258
|
+
- **Configuration changes:** Update `src/settings.ts` and `config.schema.json`
|
|
259
|
+
- **Platform modifications:** Edit `src/platform.ts` (main class with 2800+ lines)
|
|
260
|
+
- **Utility functions:** Modify `src/utils.ts` for shared functionality
|
|
261
|
+
|
|
262
|
+
### Device Connection Types
|
|
263
|
+
This plugin supports two connection methods to SwitchBot devices:
|
|
264
|
+
1. **OpenAPI Connection:** Requires SwitchBot Cloud API token/secret, works through SwitchBot Hub
|
|
265
|
+
2. **BLE (Bluetooth Low Energy):** Direct device connection, requires device MAC addresses
|
|
266
|
+
|
|
267
|
+
### Common Development Tasks
|
|
268
|
+
|
|
269
|
+
- **Testing device implementations:** Focus on `src/device/` and `src/irdevice/` directories
|
|
270
|
+
- **Configuration UI changes:** Modify `src/homebridge-ui/` files and rebuild with `npm run plugin-ui`
|
|
271
|
+
- **Platform logic changes:** Edit `src/platform.ts` - the main orchestration file
|
|
272
|
+
- **Adding device support:** Create new device class extending `deviceBase` or IR device class
|
|
273
|
+
|
|
274
|
+
### Important File Relationships
|
|
275
|
+
- Always update both device implementation AND platform.ts when adding new device types
|
|
276
|
+
- Configuration schema changes require updates to settings.ts interfaces
|
|
277
|
+
- Device MAC address validation is handled in utils.ts (`formatDeviceIdAsMac`)
|
|
278
|
+
- BLE connection handling is in the base device classes
|
|
279
|
+
|
|
280
|
+
## Build Time Expectations
|
|
281
|
+
|
|
282
|
+
- **npm install --legacy-peer-deps:** 30-45 seconds
|
|
283
|
+
- **npm run build:** 7-10 seconds
|
|
284
|
+
- **npm run test:** 2-3 seconds
|
|
285
|
+
- **npm run docs:** 5-10 seconds
|
|
286
|
+
- **Complete validation workflow:** 30-45 seconds total
|
|
287
|
+
- **NEVER CANCEL:** Always wait for builds to complete, set timeouts to 90+ seconds for safety
|
|
288
|
+
|
|
289
|
+
## CI/CD Integration
|
|
290
|
+
|
|
291
|
+
The project uses GitHub Actions for CI:
|
|
292
|
+
- **Build workflow:** `.github/workflows/build.yml` runs Node.js build and test, then ESLint
|
|
293
|
+
- **Required checks:** Build must pass, tests must pass
|
|
294
|
+
- **Known CI issue:** ESLint currently fails due to configuration conflicts
|
|
295
|
+
|
|
296
|
+
Always run the complete validation workflow locally before committing:
|
|
297
|
+
```bash
|
|
298
|
+
npm run build && npm run test && npm run docs:lint
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Complete Workflow Examples
|
|
302
|
+
|
|
303
|
+
### Example 1: Issue with Proper Labels
|
|
304
|
+
**Scenario:** Issue #1234 assigned to Copilot with `minor` label
|
|
305
|
+
|
|
306
|
+
**Workflow:**
|
|
307
|
+
1. **Label Detection:** Copilot detects `minor` label → target version 4.4.0
|
|
308
|
+
2. **Branch Check:** Look for existing beta branches: `git ls-remote --heads origin | grep beta-`
|
|
309
|
+
3. **Beta Branch Creation:** No beta-4.4.0 exists → create from latest branch
|
|
310
|
+
4. **PR Targeting:** Target the new beta-4.4.0 branch
|
|
311
|
+
5. **Development:** Make changes, test, commit to beta branch
|
|
312
|
+
|
|
313
|
+
### Example 2: Issue without Version Labels
|
|
314
|
+
**Scenario:** Issue #1276 assigned to Copilot with no version increment labels
|
|
315
|
+
|
|
316
|
+
**Workflow:**
|
|
317
|
+
1. **Label Detection:** No version labels found → default to patch increment
|
|
318
|
+
2. **Version Calculation:** Current 4.3.1 → next patch 4.3.2
|
|
319
|
+
3. **Branch Check:** beta-4.3.2 already exists → target existing branch
|
|
320
|
+
4. **Development:** Make changes, document label requirement in PR description
|
|
321
|
+
|
|
322
|
+
### Example 3: Multiple Version Labels
|
|
323
|
+
**Scenario:** Issue assigned with both `minor` and `patch` labels
|
|
324
|
+
|
|
325
|
+
**Workflow:**
|
|
326
|
+
1. **Label Priority:** minor (higher priority) overrides patch
|
|
327
|
+
2. **Version Target:** Calculate minor increment instead of patch
|
|
328
|
+
3. **Documentation:** Note in PR description why minor was chosen over patch
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Standalone ESM implementation — self-contained so this file can be copied
|
|
5
|
+
* into other repos without pulling any other files.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import assert from 'node:assert'
|
|
9
|
+
import child_process from 'node:child_process'
|
|
10
|
+
import fs from 'node:fs'
|
|
11
|
+
import process from 'node:process'
|
|
12
|
+
// Minimal, in-file semver utilities used by this script.
|
|
13
|
+
// This avoids an external dependency so the script can run in environments
|
|
14
|
+
// where `semver` isn't installed.
|
|
15
|
+
const semver = {
|
|
16
|
+
// Very small validation: match major.minor.patch with optional prerelease/build
|
|
17
|
+
valid(v) {
|
|
18
|
+
return /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?(?:\+[0-9A-Za-z-.]+)?$/.test(v)
|
|
19
|
+
},
|
|
20
|
+
// Return prerelease identifiers array or null
|
|
21
|
+
prerelease(v) {
|
|
22
|
+
const m = v.match(/^\d+\.\d+\.\d+-(.+)$/)
|
|
23
|
+
return m ? m[1].split('.') : null
|
|
24
|
+
},
|
|
25
|
+
// Compare two semver strings in reverse order (for rcompare use)
|
|
26
|
+
rcompare(a, b) {
|
|
27
|
+
// Use standard semver precedence rules for major.minor.patch; ignore prerelease complexity except that prerelease is lower than release
|
|
28
|
+
const pa = a.split('-')
|
|
29
|
+
const pb = b.split('-')
|
|
30
|
+
const aCore = pa[0].split('.').map(Number)
|
|
31
|
+
const bCore = pb[0].split('.').map(Number)
|
|
32
|
+
for (let i = 0; i < 3; i++) {
|
|
33
|
+
if (aCore[i] > bCore[i]) return -1
|
|
34
|
+
if (aCore[i] < bCore[i]) return 1
|
|
35
|
+
}
|
|
36
|
+
// equal core; releases (no prerelease) are greater than prerelease
|
|
37
|
+
if (pa.length === 1 && pb.length > 1) return -1
|
|
38
|
+
if (pa.length > 1 && pb.length === 1) return 1
|
|
39
|
+
// both same prerelease status: compare as strings
|
|
40
|
+
if (a > b) return -1
|
|
41
|
+
if (a < b) return 1
|
|
42
|
+
return 0
|
|
43
|
+
},
|
|
44
|
+
// Increment version by 'major'|'minor'|'patch'
|
|
45
|
+
inc(v, level) {
|
|
46
|
+
if (!this.valid(v)) throw new Error(`Invalid semver passed to inc: ${v}`)
|
|
47
|
+
// strip prerelease/build
|
|
48
|
+
const core = v.split('-')[0].split('+')[0]
|
|
49
|
+
const parts = core.split('.').map(Number)
|
|
50
|
+
switch (level) {
|
|
51
|
+
case 'major':
|
|
52
|
+
parts[0] += 1
|
|
53
|
+
parts[1] = 0
|
|
54
|
+
parts[2] = 0
|
|
55
|
+
break
|
|
56
|
+
case 'minor':
|
|
57
|
+
parts[1] += 1
|
|
58
|
+
parts[2] = 0
|
|
59
|
+
break
|
|
60
|
+
case 'patch':
|
|
61
|
+
default:
|
|
62
|
+
parts[2] += 1
|
|
63
|
+
break
|
|
64
|
+
}
|
|
65
|
+
return parts.join('.')
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const BRANCH_VERSION_PATTERN = /^([A-Z]+)-(\d+\.\d+\.\d+)$/i
|
|
70
|
+
|
|
71
|
+
// Load package.json
|
|
72
|
+
const packageJSON = JSON.parse(fs.readFileSync('package.json', 'utf8'))
|
|
73
|
+
|
|
74
|
+
const refArgument = process.argv[2]
|
|
75
|
+
const tagArgument = process.argv[3] || 'latest'
|
|
76
|
+
const prLabel = process.argv[4] || null // optional PR label: major, minor, patch
|
|
77
|
+
|
|
78
|
+
if (!refArgument) {
|
|
79
|
+
console.error('ref argument is missing')
|
|
80
|
+
console.error('Usage: npm-version-script-esm.js <ref> [tag] [pr_label]')
|
|
81
|
+
process.exit(1)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Queries the NPM registry for the latest version for the provided base version and tag.
|
|
86
|
+
* If the tag is latest, then the base version is returned if it exists. For other tags, the latest
|
|
87
|
+
* version found for that base version and tag is returned.
|
|
88
|
+
* @param baseVersion The base version to query for, e.g. 2.0.0
|
|
89
|
+
* @param tag The tag to query for, e.g. beta or latest
|
|
90
|
+
* @returns {string} Returns the version, or '' if not found
|
|
91
|
+
*/
|
|
92
|
+
function getTagVersionFromNpm(baseVersion, tag) {
|
|
93
|
+
try {
|
|
94
|
+
return JSON.parse(child_process.execSync(`npm info ${packageJSON.name} versions --json`).toString('utf8').trim())
|
|
95
|
+
.filter(v => (tag === 'latest' ? v === baseVersion : v.startsWith(`${baseVersion}-${tag}.`)))
|
|
96
|
+
.reduce((_, current) => current, '')
|
|
97
|
+
} catch (e) {
|
|
98
|
+
console.error(`Failed to query the npm registry for the latest version for tag: ${tag}`, e)
|
|
99
|
+
// throw e;
|
|
100
|
+
return ''
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function getLatestStableVersionFromNpm() {
|
|
105
|
+
try {
|
|
106
|
+
const versions = JSON.parse(child_process.execSync(`npm info ${packageJSON.name} versions --json`).toString('utf8').trim())
|
|
107
|
+
if (!Array.isArray(versions) || versions.length === 0) return ''
|
|
108
|
+
|
|
109
|
+
// Only consider stable semver versions (no prerelease)
|
|
110
|
+
const stable = versions.filter(v => semver.valid(v) && !semver.prerelease(v))
|
|
111
|
+
if (stable.length === 0) return ''
|
|
112
|
+
|
|
113
|
+
// Sort descending and return the highest
|
|
114
|
+
const sorted = stable.sort(semver.rcompare)
|
|
115
|
+
return sorted[0]
|
|
116
|
+
} catch (e) {
|
|
117
|
+
console.error('Failed to query the npm registry for published versions', e)
|
|
118
|
+
return ''
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function desiredTargetVersion(ref) {
|
|
123
|
+
// ref is a GitHub action ref string
|
|
124
|
+
if (ref.startsWith('refs/pull/')) {
|
|
125
|
+
throw new Error('The version script was executed inside a PR!')
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
assert(ref.startsWith('refs/heads/'))
|
|
129
|
+
const branchName = ref.slice('refs/heads/'.length)
|
|
130
|
+
|
|
131
|
+
const results = branchName.match(BRANCH_VERSION_PATTERN)
|
|
132
|
+
if (results !== null) {
|
|
133
|
+
if (results[1].toLowerCase() !== tagArgument.toLowerCase()) {
|
|
134
|
+
console.warn(`The base branch name (${results[1]}) differs from the tag name ${tagArgument}`)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return results[2]
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (branchName === 'latest') {
|
|
141
|
+
// For latest branch, start with package.json version as base
|
|
142
|
+
return packageJSON.version
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
throw new Error(`Malformed branch name for ref: ${ref}. Must be beta-x.x.x, alpha-x.x.x, or 'latest'`)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function bumpVersion(baseVersion, prLabel) {
|
|
149
|
+
const label = (prLabel || 'patch').toLowerCase()
|
|
150
|
+
if (!semver.valid(baseVersion)) {
|
|
151
|
+
throw new Error(`Invalid base version passed to bumpVersion: ${baseVersion}`)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
switch (label) {
|
|
155
|
+
case 'major':
|
|
156
|
+
return semver.inc(baseVersion, 'major')
|
|
157
|
+
case 'minor':
|
|
158
|
+
return semver.inc(baseVersion, 'minor')
|
|
159
|
+
case 'patch':
|
|
160
|
+
default:
|
|
161
|
+
return semver.inc(baseVersion, 'patch')
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const baseVersion = desiredTargetVersion(refArgument)
|
|
166
|
+
let publishTag = baseVersion
|
|
167
|
+
|
|
168
|
+
if (refArgument.includes('latest')) {
|
|
169
|
+
if (prLabel) {
|
|
170
|
+
// For latest branch when a PR label is provided, bump according to PR label
|
|
171
|
+
publishTag = bumpVersion(baseVersion, prLabel)
|
|
172
|
+
} else {
|
|
173
|
+
// No PR label: determine next version based on the highest published stable version
|
|
174
|
+
const latestPublishedStable = getLatestStableVersionFromNpm()
|
|
175
|
+
if (latestPublishedStable) {
|
|
176
|
+
console.warn(`Latest published stable version is ${latestPublishedStable}; bumping patch`)
|
|
177
|
+
publishTag = bumpVersion(latestPublishedStable, 'patch')
|
|
178
|
+
} else {
|
|
179
|
+
console.warn('No published stable versions found; bumping package.json version patch')
|
|
180
|
+
publishTag = bumpVersion(baseVersion, 'patch')
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
// For alpha/beta, query npm for latest
|
|
185
|
+
const latestReleasedVersion = getTagVersionFromNpm(baseVersion, tagArgument)
|
|
186
|
+
if (latestReleasedVersion) {
|
|
187
|
+
console.warn(`Latest published version for ${baseVersion} with tag ${tagArgument} is ${latestReleasedVersion}`)
|
|
188
|
+
publishTag = latestReleasedVersion
|
|
189
|
+
} else {
|
|
190
|
+
console.warn(`No published versions for ${baseVersion} with tag ${tagArgument}`)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (packageJSON.version !== publishTag) {
|
|
195
|
+
console.warn(`Updating version in package.json from ${packageJSON.version} to ${publishTag}`)
|
|
196
|
+
packageJSON.version = publishTag
|
|
197
|
+
fs.writeFileSync('package.json', JSON.stringify(packageJSON, null, 2))
|
|
198
|
+
|
|
199
|
+
// perform the same change to the package-lock.json
|
|
200
|
+
const packageLockJSON = JSON.parse(fs.readFileSync('package-lock.json', 'utf8'))
|
|
201
|
+
packageLockJSON.version = publishTag
|
|
202
|
+
fs.writeFileSync('package-lock.json', JSON.stringify(packageLockJSON, null, 2))
|
|
203
|
+
} else {
|
|
204
|
+
console.warn(`Version in package.json is already ${packageJSON.version}`)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
console.log(publishTag)
|
|
@@ -7,22 +7,20 @@ on:
|
|
|
7
7
|
|
|
8
8
|
jobs:
|
|
9
9
|
build_and_test:
|
|
10
|
-
uses:
|
|
10
|
+
uses: homebridge/.github/.github/workflows/nodejs-build-and-test.yml@latest
|
|
11
11
|
with:
|
|
12
|
-
enable_coverage:
|
|
12
|
+
enable_coverage: false
|
|
13
13
|
secrets:
|
|
14
14
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
15
|
-
|
|
16
15
|
lint:
|
|
17
16
|
needs: build_and_test
|
|
18
|
-
uses:
|
|
17
|
+
uses: homebridge/.github/.github/workflows/eslint.yml@latest
|
|
19
18
|
|
|
20
19
|
publish:
|
|
21
20
|
needs: lint
|
|
22
|
-
if: ${{ github.repository == 'OpenWonderLabs/homebridge-switchbot' }}
|
|
23
21
|
permissions:
|
|
24
22
|
id-token: write
|
|
25
|
-
uses:
|
|
23
|
+
uses: homebridge/.github/.github/workflows/npm-publish-esm.yml@latest
|
|
26
24
|
with:
|
|
27
25
|
tag: 'beta'
|
|
28
26
|
dynamically_adjust_version: true
|
|
@@ -33,8 +31,7 @@ jobs:
|
|
|
33
31
|
|
|
34
32
|
pre-release:
|
|
35
33
|
needs: publish
|
|
36
|
-
|
|
37
|
-
uses: OpenWonderLabs/.github/.github/workflows/pre-release.yml@latest
|
|
34
|
+
uses: homebridge/.github/.github/workflows/pre-release.yml@latest
|
|
38
35
|
with:
|
|
39
36
|
npm_version: ${{ needs.publish.outputs.NPM_VERSION }}
|
|
40
37
|
body: |
|
|
@@ -45,12 +42,11 @@ jobs:
|
|
|
45
42
|
github-releases-to-discord:
|
|
46
43
|
name: Discord Webhooks
|
|
47
44
|
needs: [build_and_test,publish]
|
|
48
|
-
|
|
49
|
-
uses: OpenWonderLabs/.github/.github/workflows/discord-webhooks.yml@latest
|
|
45
|
+
uses: homebridge/.github/.github/workflows/discord-webhooks.yml@latest
|
|
50
46
|
with:
|
|
51
47
|
title: "SwitchBot Beta Release"
|
|
52
48
|
description: |
|
|
53
49
|
Version `v${{ needs.publish.outputs.NPM_VERSION }}`
|
|
54
|
-
url: "https://github.com/homebridge
|
|
50
|
+
url: "https://github.com/OpenWonderLabs/homebridge-switchbot/releases/tag/v${{ needs.publish.outputs.NPM_VERSION }}"
|
|
55
51
|
secrets:
|
|
56
|
-
DISCORD_WEBHOOK: ${{ secrets.
|
|
52
|
+
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL_LATEST }}
|
|
@@ -1,39 +1,71 @@
|
|
|
1
|
-
name: Release
|
|
1
|
+
name: Unified Release
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
#- "alpha-*"
|
|
7
|
+
#- "beta-*"
|
|
8
|
+
- latest
|
|
9
|
+
workflow_dispatch:
|
|
6
10
|
|
|
7
11
|
jobs:
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
# 1️⃣ Determine release type, ESM status, and branch name
|
|
13
|
+
determine-release-type:
|
|
14
|
+
uses: homebridge/.github/.github/workflows/determine-release-type.yml@latest
|
|
10
15
|
with:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
ref_name: ${{ github.ref_name }}
|
|
17
|
+
|
|
18
|
+
# 2️⃣ Update version and changelog using the scripts
|
|
19
|
+
update-version:
|
|
20
|
+
needs: determine-release-type
|
|
21
|
+
uses: homebridge/.github/.github/workflows/update-version.yml@latest
|
|
22
|
+
with:
|
|
23
|
+
release_type: ${{ needs.determine-release-type.outputs.release_type }}
|
|
24
|
+
is_esm: ${{ needs.determine-release-type.outputs.is_esm == 'true' }}
|
|
14
25
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
26
|
+
# 3️⃣ Publish to NPM and create GitHub release
|
|
27
|
+
publish-release:
|
|
28
|
+
needs: [determine-release-type, update-version]
|
|
18
29
|
permissions:
|
|
19
30
|
id-token: write
|
|
20
|
-
|
|
31
|
+
contents: write
|
|
32
|
+
uses: homebridge/.github/.github/workflows/publish-release.yml@latest
|
|
33
|
+
with:
|
|
34
|
+
release_type: ${{ needs.determine-release-type.outputs.release_type }}
|
|
35
|
+
version: ${{ needs.update-version.outputs.version }}
|
|
36
|
+
is_esm: ${{ needs.determine-release-type.outputs.is_esm == 'true' }}
|
|
21
37
|
secrets:
|
|
22
|
-
|
|
38
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
39
|
+
|
|
40
|
+
# 4️⃣ Promote branch if this is a prerelease (alpha/beta)
|
|
41
|
+
promote-branch:
|
|
42
|
+
needs: [determine-release-type, publish-release]
|
|
43
|
+
if: ${{ needs.determine-release-type.outputs.release_type != 'latest' && needs.determine-release-type.outputs.release_type != 'skip' }}
|
|
44
|
+
uses: homebridge/.github/.github/workflows/promote-branch.yml@latest
|
|
45
|
+
with:
|
|
46
|
+
branch_name: ${{ needs.determine-release-type.outputs.branch_name }}
|
|
47
|
+
release_type: ${{ needs.determine-release-type.outputs.release_type }}
|
|
48
|
+
is_esm: ${{ needs.determine-release-type.outputs.is_esm == 'true' }}
|
|
23
49
|
|
|
50
|
+
# 5️⃣ Notify if any previous job fails
|
|
51
|
+
workflow-failure:
|
|
52
|
+
if: ${{ failure() }}
|
|
53
|
+
needs: [determine-release-type, update-version, publish-release, promote-branch]
|
|
54
|
+
uses: homebridge/.github/.github/workflows/report-failure.yml@latest
|
|
55
|
+
with:
|
|
56
|
+
workflow_name: ${{ github.workflow }}
|
|
57
|
+
job_name: ${{ github.job }}
|
|
58
|
+
run_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
59
|
+
|
|
60
|
+
# 6️⃣ Post to Discord
|
|
24
61
|
github-releases-to-discord:
|
|
25
62
|
name: Discord Webhooks
|
|
26
|
-
needs: [
|
|
27
|
-
|
|
28
|
-
uses: OpenWonderLabs/.github/.github/workflows/discord-webhooks.yml@latest
|
|
63
|
+
needs: [determine-release-type, update-version, publish-release]
|
|
64
|
+
uses: homebridge/.github/.github/workflows/discord-webhooks.yml@latest
|
|
29
65
|
with:
|
|
30
66
|
title: "SwitchBot Release"
|
|
31
67
|
description: |
|
|
32
|
-
Version `v${{ needs.
|
|
33
|
-
url: "https://github.com/homebridge
|
|
68
|
+
Version `v${{ needs.update-version.outputs.version }}`
|
|
69
|
+
url: "https://github.com/OpenWonderLabs/homebridge-switchbot/releases/tag/v${{ needs.update-version.outputs.version }}"
|
|
34
70
|
secrets:
|
|
35
71
|
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL_LATEST }}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|