iobroker.fakeroku 0.4.0 → 0.5.1

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.
@@ -1,20 +1,29 @@
1
- # Dependabot will run on day 20 of each month at 03:55 (Europe/Berlin timezone)
1
+ # Dependabot configuration
2
+ # Cooldown delays updating normal npm dependencies by 7 days but allows security updates to be processed immediately.
3
+ # Note: Cooldown is not supported for the github-actions ecosystem.
4
+ # Reference: https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference
2
5
  version: 2
3
6
  updates:
4
7
 
5
- - package-ecosystem: "npm"
6
- directory: "/"
8
+ - package-ecosystem: 'npm'
9
+ directory: '/'
7
10
  schedule:
8
- interval: "cron"
9
- timezone: "Europe/Berlin"
10
- cronjob: "55 3 20 * *"
11
+ interval: 'cron'
12
+ timezone: 'Europe/Berlin'
13
+ cronjob: '55 3 20 * *'
11
14
  open-pull-requests-limit: 15
12
- versioning-strategy: "increase"
15
+ versioning-strategy: 'increase'
16
+ cooldown:
17
+ default-days: 7
18
+ ignore:
19
+ - dependency-name: '@types/node'
20
+ update-types:
21
+ - 'version-update:semver-major'
13
22
 
14
- - package-ecosystem: "github-actions"
15
- directory: "/"
23
+ - package-ecosystem: 'github-actions'
24
+ directory: '/'
16
25
  schedule:
17
- interval: "cron"
18
- timezone: "Europe/Berlin"
19
- cronjob: "55 3 20 * *"
26
+ interval: 'cron'
27
+ timezone: 'Europe/Berlin'
28
+ cronjob: '55 3 20 * *'
20
29
  open-pull-requests-limit: 15
@@ -0,0 +1,25 @@
1
+ # Workflow for auto-merging ioBroker-Bot PRs
2
+ # This workflow uses the action-automerge-iobroker-bot action to automatically merge
3
+ # PRs created by ioBroker-Bot if all required checks pass successfully.
4
+
5
+ name: Auto-Merge ioBroker-Bot PRs
6
+
7
+ on:
8
+ pull_request_target:
9
+ types: [opened, synchronize, reopened, edited]
10
+
11
+ jobs:
12
+ auto-merge:
13
+ runs-on: ubuntu-latest
14
+ if: github.actor == 'ioBroker-Bot'
15
+
16
+ permissions:
17
+ contents: write
18
+ pull-requests: write
19
+
20
+ steps:
21
+ - name: Auto-merge ioBroker-Bot PRs
22
+ uses: iobroker-bot-orga/action-automerge-iobroker-bot@v1
23
+ with:
24
+ github-token: ${{ secrets.AUTO_MERGE_TOKEN_IOBROKER_BOT }}
25
+ pull-request-ref: ${{ github.event.pull_request.number }}
@@ -26,9 +26,9 @@ jobs:
26
26
  runs-on: ubuntu-latest
27
27
 
28
28
  steps:
29
- - uses: ioBroker/testing-action-check@v1
29
+ - uses: ioBroker/testing-action-check@v2
30
30
  with:
31
- node-version: '22.x'
31
+ node-version: '24.x'
32
32
  # Uncomment the following line if your adapter cannot be installed using 'npm ci'
33
33
  # install-command: 'npm install'
34
34
  lint: false
@@ -42,7 +42,7 @@ jobs:
42
42
  runs-on: ${{ matrix.os }}
43
43
  strategy:
44
44
  matrix:
45
- node-version: [20.x, 22.x, 24.x]
45
+ node-version: [22.x, 24.x]
46
46
  os: [ubuntu-latest, windows-latest, macos-latest]
47
47
 
48
48
  steps:
@@ -77,7 +77,7 @@ jobs:
77
77
  steps:
78
78
  - uses: ioBroker/testing-action-deploy@v1
79
79
  with:
80
- node-version: '22.x'
80
+ node-version: '24.x'
81
81
  # Uncomment the following line if your adapter cannot be installed using 'npm ci'
82
82
  # install-command: 'npm install'
83
83
  # npm-token: ${{ secrets.NPM_TOKEN }} # Commented out for migration to Trusted Publishing
package/CHANGELOG_OLD.md CHANGED
@@ -1,4 +1,7 @@
1
1
  # Older changes
2
+ ## 0.2.0
3
+ (Pmant) run multiple fakeroku's in one instance
4
+
2
5
  ## 0.1.1
3
6
  (Pmant) fix package.json
4
7
 
package/README.md CHANGED
@@ -30,6 +30,10 @@ States are automatically created when fakeRoku receives a key for the first time
30
30
  Placeholder for the next version (at the beginning of the line):
31
31
  ### __WORK IN PROGRESS__
32
32
  -->
33
+ ### 0.5.1 (2026-08-05)
34
+ - (copilot) Adapter requires node.js >= 22 now
35
+ * (mcm1957) Dependencies have been updated
36
+
33
37
  ### 0.4.0 (2026-03-07)
34
38
  - (iobroker-bot) Adapter requires node.js >= 20 now.
35
39
  - (copilot) Adapter requires admin >= 7.7.22 now
@@ -47,8 +51,8 @@ States are automatically created when fakeRoku receives a key for the first time
47
51
  (Pmant) fix jQuery error in admin
48
52
  (ykuendig) add translations
49
53
 
50
- ### 0.2.0
51
- (Pmant) run multiple fakeroku's in one instance
54
+
55
+ [Older changelogs can be found there](CHANGELOG_OLD.md)
52
56
 
53
57
  ## License
54
58
  The MIT License (MIT)
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "fakeroku",
4
- "version": "0.4.0",
4
+ "version": "0.5.1",
5
5
  "news": {
6
+ "0.5.1": {
7
+ "en": "Adapter requires node.js >= 22 now\nDependencies have been updated",
8
+ "de": "Der Adapter benötigt jetzt Node.js >= 22.\nDie Abhängigkeiten wurden aktualisiert.",
9
+ "ru": "Для работы адаптера требуется Node.js версии >= 22.\nЗависимости обновлены.",
10
+ "pt": "O adaptador agora requer Node.js >= 22.\nAs dependências foram atualizadas.",
11
+ "nl": "De adapter vereist nu Node.js versie 22 of hoger.\nAfhankelijkheden zijn bijgewerkt.",
12
+ "fr": "L'adaptateur nécessite désormais Node.js >= 22.\nLes dépendances ont été mises à jour",
13
+ "it": "L'adattatore ora richiede Node.js >= 22\nLe dipendenze sono state aggiornate",
14
+ "es": "El adaptador ahora requiere node.js >= 22.\nSe han actualizado las dependencias.",
15
+ "pl": "Adapter wymaga teraz node.js >= 22\nZaktualizowano zależności",
16
+ "uk": "Адаптер тепер вимагає node.js >= 22\nЗалежності оновлено",
17
+ "zh-cn": "适配器现在需要 node.js 版本 >= 22。\n依赖项已更新"
18
+ },
19
+ "0.5.0": {
20
+ "en": "Adapter requires node.js >= 22 now\nDependencies have been updated",
21
+ "de": "Der Adapter benötigt jetzt Node.js >= 22.\nDie Abhängigkeiten wurden aktualisiert.",
22
+ "ru": "Для работы адаптера требуется Node.js версии >= 22.\nЗависимости обновлены.",
23
+ "pt": "O adaptador agora requer Node.js >= 22.\nAs dependências foram atualizadas.",
24
+ "nl": "De adapter vereist nu Node.js versie 22 of hoger.\nAfhankelijkheden zijn bijgewerkt.",
25
+ "fr": "L'adaptateur nécessite désormais Node.js >= 22.\nLes dépendances ont été mises à jour",
26
+ "it": "L'adattatore ora richiede Node.js >= 22\nLe dipendenze sono state aggiornate",
27
+ "es": "El adaptador ahora requiere node.js >= 22.\nSe han actualizado las dependencias.",
28
+ "pl": "Adapter wymaga teraz node.js >= 22\nZaktualizowano zależności",
29
+ "uk": "Адаптер тепер вимагає node.js >= 22\nЗалежності оновлено",
30
+ "zh-cn": "适配器现在需要 node.js 版本 >= 22。\n依赖项已更新"
31
+ },
6
32
  "0.4.0": {
7
33
  "en": "Adapter requires node.js >= 20 now.\nAdapter requires admin >= 7.7.22 now\nAdapter requires js-controller >= 6.0.11 now\nDependencies have been updated",
8
34
  "de": "Adapter benötigt jetzt node.js >= 20.\nAdapter benötigt admin >= 7.7.22 jetzt\nAdapter benötigt jetzt js-controller >= 6.0.11\nAbhängigkeiten wurden aktualisiert",
@@ -67,32 +93,6 @@
67
93
  "pl": "emulować wiele roku",
68
94
  "uk": "емулювати кілька rokus",
69
95
  "zh-cn": "模拟多个 roku"
70
- },
71
- "0.1.1": {
72
- "en": "fix package.json",
73
- "de": "fix package.json",
74
- "ru": "fix package.json",
75
- "pt": "corrigir pacote.json",
76
- "nl": "pakket.json repareren",
77
- "fr": "réparer package.json",
78
- "it": "correggere pacchetto.json",
79
- "es": "arreglar paquete.json",
80
- "pl": "napraw pakiet.json",
81
- "uk": "виправити package.json",
82
- "zh-cn": "修复 package.json"
83
- },
84
- "0.1.0": {
85
- "en": "first version",
86
- "de": "erste Version",
87
- "ru": "first version",
88
- "pt": "primeira versão",
89
- "nl": "eerste versie",
90
- "fr": "première version",
91
- "it": "prima versione",
92
- "es": "primera versión",
93
- "pl": "pierwsza wersja",
94
- "uk": "перша версія",
95
- "zh-cn": "第一个版本"
96
96
  }
97
97
  },
98
98
  "titleLang": {
package/main.js CHANGED
@@ -2,8 +2,8 @@
2
2
  /*jslint node: true */
3
3
  'use strict';
4
4
 
5
- var dgram = require('dgram');
6
- var http = require('http');
5
+ var dgram = require('node:dgram');
6
+ var http = require('node:http');
7
7
  var httpHeaders = require('http-headers');
8
8
 
9
9
  var utils = require('@iobroker/adapter-core'); // Get common adapter utils
@@ -418,7 +418,7 @@ function setState(device, channel, state, val, callback) {
418
418
  }
419
419
 
420
420
  function genUUID(device) {
421
- var crypto = require('crypto');
421
+ var crypto = require('node:crypto');
422
422
  var uuid = crypto.createHash('md5').update(crypto.randomBytes(256)).digest('hex');
423
423
  for (var i = 0; i < adapter.config.devices.length; i++) {
424
424
  if (adapter.config.devices[i].name === device) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.fakeroku",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "ioBroker fakeroku Adapter",
5
5
  "author": "Pmant <patrickmo@gmx.de>",
6
6
  "contributors": [
@@ -20,22 +20,22 @@
20
20
  "url": "https://github.com/iobroker-community-adapters/ioBroker.fakeroku"
21
21
  },
22
22
  "engines": {
23
- "node": ">=20"
23
+ "node": ">=22"
24
24
  },
25
25
  "dependencies": {
26
- "@iobroker/adapter-core": "^3.3.2",
26
+ "@iobroker/adapter-core": "^3.4.3",
27
27
  "http-headers": "^3.0.1"
28
28
  },
29
29
  "devDependencies": {
30
- "@alcalzone/release-script": "^5.1.1",
31
- "@alcalzone/release-script-plugin-iobroker": "^5.1.2",
32
- "@alcalzone/release-script-plugin-license": "^5.1.1",
33
- "@alcalzone/release-script-plugin-manual-review": "^5.1.1",
30
+ "@alcalzone/release-script": "^5.2.1",
31
+ "@alcalzone/release-script-plugin-iobroker": "^5.2.0",
32
+ "@alcalzone/release-script-plugin-license": "^5.2.0",
33
+ "@alcalzone/release-script-plugin-manual-review": "^5.2.0",
34
34
  "@iobroker/adapter-dev": "^1.5.0",
35
- "@iobroker/eslint-config": "^2.2.0",
36
- "@iobroker/testing": "^5.2.2",
37
- "@tsconfig/node14": "^14.1.8",
38
- "@types/node": "^24.11.0",
35
+ "@iobroker/eslint-config": "^2.3.4",
36
+ "@iobroker/testing": "^5.3.0",
37
+ "@tsconfig/node22": "^22.0.5",
38
+ "@types/node": "^22.20.1",
39
39
  "typescript": "~5.9.3"
40
40
  },
41
41
  "main": "main.js",
@@ -1,917 +0,0 @@
1
- # ioBroker Adapter Development with GitHub Copilot
2
-
3
- **Version:** 0.5.7
4
- **Template Source:** https://github.com/DrozmotiX/ioBroker-Copilot-Instructions
5
-
6
- This file contains instructions and best practices for GitHub Copilot when working on ioBroker adapter development.
7
-
8
- ---
9
-
10
- ## 📑 Table of Contents
11
-
12
- 1. [Project Context](#project-context)
13
- 2. [Code Quality & Standards](#code-quality--standards)
14
- - [Code Style Guidelines](#code-style-guidelines)
15
- - [ESLint Configuration](#eslint-configuration)
16
- 3. [Testing](#testing)
17
- - [Unit Testing](#unit-testing)
18
- - [Integration Testing](#integration-testing)
19
- - [API Testing with Credentials](#api-testing-with-credentials)
20
- 4. [Development Best Practices](#development-best-practices)
21
- - [Dependency Management](#dependency-management)
22
- - [HTTP Client Libraries](#http-client-libraries)
23
- - [Error Handling](#error-handling)
24
- 5. [Admin UI Configuration](#admin-ui-configuration)
25
- - [JSON-Config Setup](#json-config-setup)
26
- - [Translation Management](#translation-management)
27
- 6. [Documentation](#documentation)
28
- - [README Updates](#readme-updates)
29
- - [Changelog Management](#changelog-management)
30
- 7. [CI/CD & GitHub Actions](#cicd--github-actions)
31
- - [Workflow Configuration](#workflow-configuration)
32
- - [Testing Integration](#testing-integration)
33
-
34
- ---
35
-
36
- ## Project Context
37
-
38
- You are working on an ioBroker adapter. ioBroker is an integration platform for the Internet of Things, focused on building smart home and industrial IoT solutions. Adapters are plugins that connect ioBroker to external systems, devices, or services.
39
-
40
- This is the **fakeroku** adapter, which emulates Roku devices to enable integration with Logitech Harmony Hubs. The adapter creates virtual Roku devices that can be discovered and controlled by Harmony Hubs, allowing ioBroker to respond to Harmony Hub commands as if it were a real Roku device.
41
-
42
- ## Adapter-Specific Context
43
-
44
- - **Adapter Name:** fakeroku
45
- - **Primary Function:** Emulates Roku devices for Logitech Harmony Hub integration
46
- - **Key Dependencies:**
47
- - `http-headers` for HTTP response handling
48
- - `@iobroker/adapter-core` for ioBroker integration
49
- - UDP multicast for device discovery (SSDP protocol)
50
- - **Configuration Requirements:**
51
- - LAN IP address (not 0.0.0.0)
52
- - Multicast IP (default: 239.255.255.250)
53
- - Virtual Roku devices configuration (name, port, UUID)
54
- - **Network Protocols:**
55
- - HTTP server for command reception
56
- - UDP multicast for SSDP device discovery
57
- - ECP (External Control Protocol) for Roku command handling
58
-
59
- ---
60
-
61
- ## Code Quality & Standards
62
-
63
- ### Code Style Guidelines
64
-
65
- - Follow JavaScript/TypeScript best practices
66
- - Use async/await for asynchronous operations
67
- - Implement proper resource cleanup in `unload()` method
68
- - Use semantic versioning for adapter releases
69
- - Include proper JSDoc comments for public methods
70
-
71
- **Timer and Resource Cleanup Example:**
72
- ```javascript
73
- private connectionTimer?: NodeJS.Timeout;
74
-
75
- async onReady() {
76
- this.connectionTimer = setInterval(() => this.checkConnection(), 30000);
77
- }
78
-
79
- onUnload(callback) {
80
- try {
81
- if (this.connectionTimer) {
82
- clearInterval(this.connectionTimer);
83
- this.connectionTimer = undefined;
84
- }
85
- callback();
86
- } catch (e) {
87
- callback();
88
- }
89
- }
90
- ```
91
-
92
- ### ESLint Configuration
93
-
94
- **CRITICAL:** ESLint validation must run FIRST in your CI/CD pipeline, before any other tests. This "lint-first" approach catches code quality issues early.
95
-
96
- #### Setup
97
- ```bash
98
- npm install --save-dev eslint @iobroker/eslint-config
99
- ```
100
-
101
- #### Configuration (.eslintrc.json)
102
- ```json
103
- {
104
- "extends": "@iobroker/eslint-config",
105
- "rules": {
106
- // Add project-specific rule overrides here if needed
107
- }
108
- }
109
- ```
110
-
111
- #### Package.json Scripts
112
- ```json
113
- {
114
- "scripts": {
115
- "lint": "eslint --max-warnings 0 .",
116
- "lint:fix": "eslint . --fix"
117
- }
118
- }
119
- ```
120
-
121
- #### Best Practices
122
- 1. ✅ Run ESLint before committing — fix ALL warnings, not just errors
123
- 2. ✅ Use `lint:fix` for auto-fixable issues
124
- 3. ✅ Don't disable rules without documentation
125
- 4. ✅ Lint all relevant files (main code, tests, build scripts)
126
- 5. ✅ Keep `@iobroker/eslint-config` up to date
127
- 6. ✅ **ESLint warnings are treated as errors in CI** (`--max-warnings 0`). The `lint` script above already includes this flag — run `npm run lint` to match CI behavior locally
128
-
129
- #### Common Issues
130
- - **Unused variables**: Remove or prefix with underscore (`_variable`)
131
- - **Missing semicolons**: Run `npm run lint:fix`
132
- - **Indentation**: Use 4 spaces (ioBroker standard)
133
- - **console.log**: Replace with `adapter.log.debug()` or remove
134
-
135
- ---
136
-
137
-
138
-
139
- ## Testing
140
-
141
- ### Unit Testing
142
-
143
- - Use Jest as the primary testing framework
144
- - Create tests for all adapter main functions and helper methods
145
- - Test error handling scenarios and edge cases
146
- - Mock external API calls and hardware dependencies
147
- - For adapters connecting to APIs/devices not reachable by internet, provide example data files
148
-
149
- **Example Structure:**
150
- ```javascript
151
- describe('AdapterName', () => {
152
- let adapter;
153
-
154
- beforeEach(() => {
155
- // Setup test adapter instance
156
- });
157
-
158
- test('should initialize correctly', () => {
159
- // Test adapter initialization
160
- });
161
- });
162
- ```
163
-
164
- ### Integration Testing
165
-
166
- **CRITICAL:** Use the official `@iobroker/testing` framework. This is the ONLY correct way to test ioBroker adapters.
167
-
168
- **Official Documentation:** https://github.com/ioBroker/testing
169
-
170
- #### Framework Structure
171
-
172
- **✅ Correct Pattern:**
173
- ```javascript
174
- const path = require('path');
175
- const { tests } = require('@iobroker/testing');
176
-
177
- tests.integration(path.join(__dirname, '..'), {
178
- defineAdditionalTests({ suite }) {
179
- suite('Test adapter with specific configuration', (getHarness) => {
180
- let harness;
181
-
182
- before(() => {
183
- harness = getHarness();
184
- });
185
-
186
- it('should configure and start adapter', function () {
187
- return new Promise(async (resolve, reject) => {
188
- try {
189
- // Get adapter object
190
- const obj = await new Promise((res, rej) => {
191
- harness.objects.getObject('system.adapter.your-adapter.0', (err, o) => {
192
- if (err) return rej(err);
193
- res(o);
194
- });
195
- });
196
-
197
- if (!obj) return reject(new Error('Adapter object not found'));
198
-
199
- // Configure adapter
200
- Object.assign(obj.native, {
201
- position: '52.520008,13.404954',
202
- createHourly: true,
203
- });
204
-
205
- harness.objects.setObject(obj._id, obj);
206
-
207
- // Start and wait
208
- await harness.startAdapterAndWait();
209
- await new Promise(resolve => setTimeout(resolve, 15000));
210
-
211
- // Verify states
212
- const stateIds = await harness.dbConnection.getStateIDs('your-adapter.0.*');
213
-
214
- if (stateIds.length > 0) {
215
- console.log('✅ Adapter successfully created states');
216
- await harness.stopAdapter();
217
- resolve(true);
218
- } else {
219
- reject(new Error('Adapter did not create any states'));
220
- }
221
- } catch (error) {
222
- reject(error);
223
- }
224
- });
225
- }).timeout(40000);
226
- });
227
- }
228
- });
229
- ```
230
-
231
- #### Testing Success AND Failure Scenarios
232
-
233
- **IMPORTANT:** For every "it works" test, implement corresponding "it fails gracefully" tests.
234
-
235
- **Failure Scenario Example:**
236
- ```javascript
237
- it('should NOT create daily states when daily is disabled', function () {
238
- return new Promise(async (resolve, reject) => {
239
- try {
240
- harness = getHarness();
241
- const obj = await new Promise((res, rej) => {
242
- harness.objects.getObject('system.adapter.your-adapter.0', (err, o) => {
243
- if (err) return rej(err);
244
- res(o);
245
- });
246
- });
247
-
248
- if (!obj) return reject(new Error('Adapter object not found'));
249
-
250
- Object.assign(obj.native, {
251
- createDaily: false, // Daily disabled
252
- });
253
-
254
- await new Promise((res, rej) => {
255
- harness.objects.setObject(obj._id, obj, (err) => {
256
- if (err) return rej(err);
257
- res(undefined);
258
- });
259
- });
260
-
261
- await harness.startAdapterAndWait();
262
- await new Promise((res) => setTimeout(res, 20000));
263
-
264
- const stateIds = await harness.dbConnection.getStateIDs('your-adapter.0.*');
265
- const dailyStates = stateIds.filter((key) => key.includes('daily'));
266
-
267
- if (dailyStates.length === 0) {
268
- console.log('✅ No daily states found as expected');
269
- resolve(true);
270
- } else {
271
- reject(new Error('Expected no daily states but found some'));
272
- }
273
-
274
- await harness.stopAdapter();
275
- } catch (error) {
276
- reject(error);
277
- }
278
- });
279
- }).timeout(40000);
280
- ```
281
-
282
- #### Key Rules
283
-
284
- 1. ✅ Use `@iobroker/testing` framework
285
- 2. ✅ Configure via `harness.objects.setObject()`
286
- 3. ✅ Start via `harness.startAdapterAndWait()`
287
- 4. ✅ Verify states via `harness.states.getState()`
288
- 5. ✅ Allow proper timeouts for async operations
289
- 6. ❌ NEVER test API URLs directly
290
- 7. ❌ NEVER bypass the harness system
291
-
292
- #### Workflow Dependencies
293
-
294
- Integration tests should run ONLY after lint and adapter tests pass:
295
-
296
- ```yaml
297
- integration-tests:
298
- needs: [check-and-lint, adapter-tests]
299
- runs-on: ubuntu-22.04
300
- ```
301
-
302
- ### API Testing with Credentials
303
-
304
- For adapters connecting to external APIs requiring authentication:
305
-
306
- #### Password Encryption for Integration Tests
307
-
308
- ```javascript
309
- async function encryptPassword(harness, password) {
310
- const systemConfig = await harness.objects.getObjectAsync("system.config");
311
- if (!systemConfig?.native?.secret) {
312
- throw new Error("Could not retrieve system secret for password encryption");
313
- }
314
-
315
- const secret = systemConfig.native.secret;
316
- let result = '';
317
- for (let i = 0; i < password.length; ++i) {
318
- result += String.fromCharCode(secret[i % secret.length].charCodeAt(0) ^ password.charCodeAt(i));
319
- }
320
- return result;
321
- }
322
- ```
323
-
324
- #### Demo Credentials Testing Pattern
325
-
326
- - Use provider demo credentials when available (e.g., `demo@api-provider.com` / `demo`)
327
- - Create separate test file: `test/integration-demo.js`
328
- - Add npm script: `"test:integration-demo": "mocha test/integration-demo --exit"`
329
- - Implement clear success/failure criteria
330
-
331
- **Example Implementation:**
332
- ```javascript
333
- it("Should connect to API with demo credentials", async () => {
334
- const encryptedPassword = await encryptPassword(harness, "demo_password");
335
-
336
- await harness.changeAdapterConfig("your-adapter", {
337
- native: {
338
- username: "demo@provider.com",
339
- password: encryptedPassword,
340
- }
341
- });
342
-
343
- await harness.startAdapter();
344
- await new Promise(resolve => setTimeout(resolve, 60000));
345
-
346
- const connectionState = await harness.states.getStateAsync("your-adapter.0.info.connection");
347
-
348
- if (connectionState?.val === true) {
349
- console.log("✅ SUCCESS: API connection established");
350
- return true;
351
- } else {
352
- throw new Error("API Test Failed: Expected API connection. Check logs for API errors.");
353
- }
354
- }).timeout(120000);
355
- ```
356
-
357
- ---
358
-
359
- ## Development Best Practices
360
-
361
- ### Dependency Management
362
-
363
- - Always use `npm` for dependency management
364
- - Use `npm ci` for installing existing dependencies (respects package-lock.json)
365
- - Use `npm install` only when adding or updating dependencies
366
- - Keep dependencies minimal and focused
367
- - Only update dependencies in separate Pull Requests
368
-
369
- **When modifying package.json:**
370
- 1. Run `npm install` to sync package-lock.json
371
- 2. Commit both package.json and package-lock.json together
372
-
373
- **Best Practices:**
374
- - Prefer built-in Node.js modules when possible
375
- - Use `@iobroker/adapter-core` for adapter base functionality
376
- - Avoid deprecated packages
377
- - Document specific version requirements
378
-
379
- ### HTTP Client Libraries
380
-
381
- - **Preferred:** Use native `fetch` API (Node.js 20+ required)
382
- - **Avoid:** `axios` unless specific features are required
383
-
384
- **Example with fetch:**
385
- ```javascript
386
- try {
387
- const response = await fetch('https://api.example.com/data');
388
- if (!response.ok) {
389
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
390
- }
391
- const data = await response.json();
392
- } catch (error) {
393
- this.log.error(`API request failed: ${error.message}`);
394
- }
395
- ```
396
-
397
- **Other Recommendations:**
398
- - **Logging:** Use adapter built-in logging (`this.log.*`)
399
- - **Scheduling:** Use adapter built-in timers and intervals
400
- - **File operations:** Use Node.js `fs/promises`
401
- - **Configuration:** Use adapter config system
402
-
403
- ### Error Handling
404
-
405
- - Always catch and log errors appropriately
406
- - Use adapter log levels (error, warn, info, debug)
407
- - Provide meaningful, user-friendly error messages
408
- - Handle network failures gracefully
409
- - Implement retry mechanisms where appropriate
410
- - Always clean up timers, intervals, and resources in `unload()` method
411
-
412
- **Example:**
413
- ```javascript
414
- try {
415
- await this.connectToDevice();
416
- } catch (error) {
417
- this.log.error(`Failed to connect to device: ${error.message}`);
418
- this.setState('info.connection', false, true);
419
- // Implement retry logic if needed
420
- }
421
- ```
422
-
423
- ---
424
-
425
- ## Admin UI Configuration
426
-
427
- ### JSON-Config Setup
428
-
429
- Use JSON-Config format for modern ioBroker admin interfaces.
430
-
431
- **Example Structure:**
432
- ```json
433
- {
434
- "type": "panel",
435
- "items": {
436
- "host": {
437
- "type": "text",
438
- "label": "Host address",
439
- "help": "IP address or hostname of the device"
440
- }
441
- }
442
- }
443
- ```
444
-
445
- **Guidelines:**
446
- - ✅ Use consistent naming conventions
447
- - ✅ Provide sensible default values
448
- - ✅ Include validation for required fields
449
- - ✅ Add tooltips for complex options
450
- - ✅ Ensure translations for all supported languages (minimum English and German)
451
- - ✅ Write end-user friendly labels, avoid technical jargon
452
-
453
- ### Translation Management
454
-
455
- **CRITICAL:** Translation files must stay synchronized with `admin/jsonConfig.json`. Orphaned keys or missing translations cause UI issues and PR review delays.
456
-
457
- #### Overview
458
- - **Location:** `admin/i18n/{lang}/translations.json` for 11 languages (de, en, es, fr, it, nl, pl, pt, ru, uk, zh-cn)
459
- - **Source of truth:** `admin/jsonConfig.json` - all `label` and `help` properties must have translations
460
- - **Command:** `npm run translate` - auto-generates translations but does NOT remove orphaned keys
461
- - **Formatting:** English uses tabs, other languages use 4 spaces
462
-
463
- #### Critical Rules
464
- 1. ✅ Keys must match exactly with jsonConfig.json
465
- 2. ✅ No orphaned keys in translation files
466
- 3. ✅ All translations must be in native language (no English fallbacks)
467
- 4. ✅ Keys must be sorted alphabetically
468
-
469
- #### Workflow for Translation Updates
470
-
471
- **When modifying admin/jsonConfig.json:**
472
-
473
- 1. Make your changes to labels/help texts
474
- 2. Run automatic translation: `npm run translate`
475
- 3. Create validation script (`scripts/validate-translations.js`):
476
-
477
- ```javascript
478
- const fs = require('fs');
479
- const path = require('path');
480
- const jsonConfig = JSON.parse(fs.readFileSync('admin/jsonConfig.json', 'utf8'));
481
-
482
- function extractTexts(obj, texts = new Set()) {
483
- if (typeof obj === 'object' && obj !== null) {
484
- if (obj.label) texts.add(obj.label);
485
- if (obj.help) texts.add(obj.help);
486
- for (const key in obj) {
487
- extractTexts(obj[key], texts);
488
- }
489
- }
490
- return texts;
491
- }
492
-
493
- const requiredTexts = extractTexts(jsonConfig);
494
- const languages = ['de', 'en', 'es', 'fr', 'it', 'nl', 'pl', 'pt', 'ru', 'uk', 'zh-cn'];
495
- let hasErrors = false;
496
-
497
- languages.forEach(lang => {
498
- const translationPath = path.join('admin', 'i18n', lang, 'translations.json');
499
- const translations = JSON.parse(fs.readFileSync(translationPath, 'utf8'));
500
- const translationKeys = new Set(Object.keys(translations));
501
-
502
- const missing = Array.from(requiredTexts).filter(text => !translationKeys.has(text));
503
- const orphaned = Array.from(translationKeys).filter(key => !requiredTexts.has(key));
504
-
505
- console.log(`\n=== ${lang} ===`);
506
- if (missing.length > 0) {
507
- console.error('❌ Missing keys:', missing);
508
- hasErrors = true;
509
- }
510
- if (orphaned.length > 0) {
511
- console.error('❌ Orphaned keys (REMOVE THESE):', orphaned);
512
- hasErrors = true;
513
- }
514
- if (missing.length === 0 && orphaned.length === 0) {
515
- console.log('✅ All keys match!');
516
- }
517
- });
518
-
519
- process.exit(hasErrors ? 1 : 0);
520
- ```
521
-
522
- 4. Run validation: `node scripts/validate-translations.js`
523
- 5. Remove orphaned keys manually from all translation files
524
- 6. Add missing translations in native languages
525
- 7. Run: `npm run lint && npm run test`
526
-
527
- #### Add Validation to package.json
528
-
529
- ```json
530
- {
531
- "scripts": {
532
- "translate": "translate-adapter",
533
- "validate:translations": "node scripts/validate-translations.js",
534
- "pretest": "npm run lint && npm run validate:translations"
535
- }
536
- }
537
- ```
538
-
539
- #### Translation Checklist
540
-
541
- Before committing changes to admin UI or translations:
542
- 1. ✅ Validation script shows "All keys match!" for all 11 languages
543
- 2. ✅ No orphaned keys in any translation file
544
- 3. ✅ All translations in native language
545
- 4. ✅ Keys alphabetically sorted
546
- 5. ✅ `npm run lint` passes
547
- 6. ✅ `npm run test` passes
548
- 7. ✅ Admin UI displays correctly
549
-
550
- ---
551
-
552
- ## Documentation
553
-
554
- ### README Updates
555
-
556
- #### Required Sections
557
- 1. **Installation** - Clear npm/ioBroker admin installation steps
558
- 2. **Configuration** - Detailed configuration options with examples
559
- 3. **Usage** - Practical examples and use cases
560
- 4. **Changelog** - Version history (use "## **WORK IN PROGRESS**" for ongoing changes)
561
- 5. **License** - License information (typically MIT for ioBroker adapters)
562
- 6. **Support** - Links to issues, discussions, community support
563
-
564
- #### Documentation Standards
565
- - Use clear, concise language
566
- - Include code examples for configuration
567
- - Add screenshots for admin interface when applicable
568
- - Maintain multilingual support (minimum English and German)
569
- - Always reference issues in commits and PRs (e.g., "fixes #xx")
570
-
571
- #### Mandatory README Updates for PRs
572
-
573
- For **every PR or new feature**, always add a user-friendly entry to README.md:
574
-
575
- - Add entries under `## **WORK IN PROGRESS**` section
576
- - Use format: `* (author) **TYPE**: Description of user-visible change`
577
- - Types: **NEW** (features), **FIXED** (bugs), **ENHANCED** (improvements), **TESTING** (test additions), **CI/CD** (automation)
578
- - Focus on user impact, not technical details
579
-
580
- **Example:**
581
- ```markdown
582
- ## **WORK IN PROGRESS**
583
-
584
- * (DutchmanNL) **FIXED**: Adapter now properly validates login credentials (fixes #25)
585
- * (DutchmanNL) **NEW**: Added device discovery to simplify initial setup
586
- ```
587
-
588
- ### Changelog Management
589
-
590
- Follow the [AlCalzone release-script](https://github.com/AlCalzone/release-script) standard.
591
-
592
- #### Format Requirements
593
-
594
- ```markdown
595
- # Changelog
596
-
597
- <!--
598
- Placeholder for the next version (at the beginning of the line):
599
- ## **WORK IN PROGRESS**
600
- -->
601
-
602
- ## **WORK IN PROGRESS**
603
-
604
- - (author) **NEW**: Added new feature X
605
- - (author) **FIXED**: Fixed bug Y (fixes #25)
606
-
607
- ## v0.1.0 (2023-01-01)
608
- Initial release
609
- ```
610
-
611
- #### Workflow Process
612
- - **During Development:** All changes go under `## **WORK IN PROGRESS**`
613
- - **For Every PR:** Add user-facing changes to WORK IN PROGRESS section
614
- - **Before Merge:** Version number and date added when merging to main
615
- - **Release Process:** Release-script automatically converts placeholder to actual version
616
-
617
- #### Change Entry Format
618
- - Format: `- (author) **TYPE**: User-friendly description`
619
- - Types: **NEW**, **FIXED**, **ENHANCED**
620
- - Focus on user impact, not technical implementation
621
- - Reference issues: "fixes #XX" or "solves #XX"
622
-
623
- ---
624
-
625
- ## CI/CD & GitHub Actions
626
-
627
- ### Workflow Configuration
628
-
629
- #### GitHub Actions Best Practices
630
-
631
- **Must use ioBroker official testing actions:**
632
- - `ioBroker/testing-action-check@v1` for lint and package validation
633
- - `ioBroker/testing-action-adapter@v1` for adapter tests
634
- - `ioBroker/testing-action-deploy@v1` for automated releases with Trusted Publishing (OIDC)
635
-
636
- **Configuration:**
637
- - **Node.js versions:** Test on 20.x, 22.x, 24.x
638
- - **Platform:** Use ubuntu-22.04
639
- - **Automated releases:** Deploy to npm on version tags (requires NPM Trusted Publishing)
640
- - **Monitoring:** Include Sentry release tracking for error monitoring
641
-
642
- #### Critical: Lint-First Validation Workflow
643
-
644
- **ALWAYS run ESLint checks BEFORE other tests.** Benefits:
645
- - Catches code quality issues immediately
646
- - Prevents wasting CI resources on tests that would fail due to linting errors
647
- - Provides faster feedback to developers
648
- - Enforces consistent code quality
649
-
650
- **Workflow Dependency Configuration:**
651
- ```yaml
652
- jobs:
653
- check-and-lint:
654
- # Runs ESLint and package validation
655
- # Uses: ioBroker/testing-action-check@v1
656
-
657
- adapter-tests:
658
- needs: [check-and-lint] # Wait for linting to pass
659
- # Run adapter unit tests
660
-
661
- integration-tests:
662
- needs: [check-and-lint, adapter-tests] # Wait for both
663
- # Run integration tests
664
- ```
665
-
666
- **Key Points:**
667
- - The `check-and-lint` job has NO dependencies - runs first
668
- - ALL other test jobs MUST list `check-and-lint` in their `needs` array
669
- - If linting fails, no other tests run, saving time
670
- - Fix all ESLint errors before proceeding
671
-
672
- ### Testing Integration
673
-
674
- #### API Testing in CI/CD
675
-
676
- For adapters with external API dependencies:
677
-
678
- ```yaml
679
- demo-api-tests:
680
- if: contains(github.event.head_commit.message, '[skip ci]') == false
681
- runs-on: ubuntu-22.04
682
-
683
- steps:
684
- - name: Checkout code
685
- uses: actions/checkout@v4
686
-
687
- - name: Use Node.js 20.x
688
- uses: actions/setup-node@v4
689
- with:
690
- node-version: 20.x
691
- cache: 'npm'
692
-
693
- - name: Install dependencies
694
- run: npm ci
695
-
696
- - name: Run demo API tests
697
- run: npm run test:integration-demo
698
- ```
699
-
700
- #### Testing Best Practices
701
- - Run credential tests separately from main test suite
702
- - Don't make credential tests required for deployment
703
- - Provide clear failure messages for API issues
704
- - Use appropriate timeouts for external calls (120+ seconds)
705
-
706
- #### Package.json Integration
707
- ```json
708
- {
709
- "scripts": {
710
- "test:integration-demo": "mocha test/integration-demo --exit"
711
- }
712
- }
713
- ```
714
-
715
- ---
716
-
717
- ### Network Service Development (Fakeroku-Specific)
718
-
719
- #### HTTP Server Setup
720
- ```javascript
721
- const http = require('http');
722
-
723
- class FakerokuAdapter extends utils.Adapter {
724
- constructor(options = {}) {
725
- super(options);
726
- this.httpServers = new Map();
727
- }
728
-
729
- async createHttpServer(device) {
730
- const server = http.createServer((req, res) => {
731
- this.handleHttpRequest(req, res, device);
732
- });
733
-
734
- server.listen(device.port, this.config.BIND, () => {
735
- this.log.info(`HTTP server for ${device.name} listening on port ${device.port}`);
736
- });
737
-
738
- this.httpServers.set(device.name, server);
739
- return server;
740
- }
741
-
742
- handleHttpRequest(req, res, device) {
743
- const url = req.url;
744
- this.log.debug(`Received request: ${req.method} ${url} for device ${device.name}`);
745
-
746
- if (url.startsWith('/keypress/')) {
747
- const key = url.substring(10);
748
- this.createKeyState(device, key);
749
- res.writeHead(200);
750
- res.end();
751
- } else if (url === '/query/device-info') {
752
- this.sendDeviceInfo(res, device);
753
- }
754
- }
755
- }
756
- ```
757
-
758
- #### UDP Multicast for Device Discovery
759
- ```javascript
760
- const dgram = require('dgram');
761
-
762
- async setupSSDP() {
763
- this.ssdpSocket = dgram.createSocket({ type: 'udp4', reuseAddr: true });
764
-
765
- this.ssdpSocket.on('message', (message, remote) => {
766
- const msg = message.toString();
767
- if (msg.includes('M-SEARCH') && msg.includes('roku:ecp')) {
768
- this.respondToSSDP(remote);
769
- }
770
- });
771
-
772
- this.ssdpSocket.bind(1900, () => {
773
- this.ssdpSocket.addMembership('239.255.255.250');
774
- this.log.info('SSDP server bound to multicast group');
775
- });
776
- }
777
- ```
778
-
779
- #### State Creation for Commands
780
- ```javascript
781
- async createKeyState(device, key) {
782
- const stateId = `${device.name}.${key}`;
783
-
784
- await this.setObjectNotExistsAsync(stateId, {
785
- type: 'state',
786
- common: {
787
- name: `Key: ${key}`,
788
- type: 'boolean',
789
- role: 'button',
790
- read: true,
791
- write: true,
792
- },
793
- native: {
794
- device: device.name,
795
- key: key
796
- },
797
- });
798
-
799
- await this.setStateAsync(stateId, { val: true, ack: true });
800
-
801
- // Reset after short delay
802
- setTimeout(async () => {
803
- await this.setStateAsync(stateId, { val: false, ack: true });
804
- }, 100);
805
- }
806
- ```
807
-
808
-
809
-
810
- ---
811
-
812
- ### Network Testing Best Practices (Fakeroku-Specific)
813
-
814
- For adapters that create network services like fakeroku:
815
-
816
- #### Mock Network Environment Testing
817
- ```javascript
818
- const { tests } = require('@iobroker/testing');
819
- const http = require('http');
820
- const dgram = require('dgram');
821
-
822
- tests.integration(path.join(__dirname, '..'), {
823
- defineAdditionalTests({ suite }) {
824
- suite('Network Service Testing', (getHarness) => {
825
- let harness;
826
- let mockHarmonyHub;
827
-
828
- before(async () => {
829
- harness = getHarness();
830
-
831
- // Create mock Harmony Hub that sends SSDP requests
832
- mockHarmonyHub = dgram.createSocket('udp4');
833
- });
834
-
835
- after(async () => {
836
- if (mockHarmonyHub) {
837
- mockHarmonyHub.close();
838
- }
839
- });
840
-
841
- it('should respond to Harmony Hub discovery', async function() {
842
- this.timeout(30000);
843
-
844
- // Configure adapter with test device
845
- await harness.changeAdapterConfig('fakeroku', {
846
- native: {
847
- BIND: '127.0.0.1',
848
- devices: [{
849
- name: 'TestRoku',
850
- port: 9093,
851
- uuid: 'test-12345'
852
- }]
853
- }
854
- });
855
-
856
- await harness.startAdapter();
857
- await new Promise(resolve => setTimeout(resolve, 5000));
858
-
859
- // Simulate Harmony Hub discovery request
860
- const discoveryMessage = 'M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: "ssdp:discover"\r\nST: roku:ecp\r\n\r\n';
861
-
862
- return new Promise((resolve, reject) => {
863
- mockHarmonyHub.on('message', (message, remote) => {
864
- const response = message.toString();
865
- if (response.includes('roku:ecp') && response.includes('TestRoku')) {
866
- resolve();
867
- }
868
- });
869
-
870
- mockHarmonyHub.send(discoveryMessage, 1900, '239.255.255.250');
871
-
872
- setTimeout(() => reject(new Error('No SSDP response received')), 10000);
873
- });
874
- });
875
- });
876
- }
877
- });
878
- ```
879
-
880
- #### HTTP Command Testing
881
- ```javascript
882
- it('should handle ECP commands via HTTP', async function() {
883
- this.timeout(20000);
884
-
885
- await harness.startAdapter();
886
- await new Promise(resolve => setTimeout(resolve, 5000));
887
-
888
- // Send keypress command to adapter
889
- const response = await new Promise((resolve, reject) => {
890
- const req = http.request({
891
- hostname: '127.0.0.1',
892
- port: 9093,
893
- path: '/keypress/Home',
894
- method: 'POST'
895
- }, (res) => {
896
- resolve(res);
897
- });
898
-
899
- req.on('error', reject);
900
- req.end();
901
- });
902
-
903
- expect(response.statusCode).toBe(200);
904
-
905
- // Verify state was created
906
- await new Promise(resolve => setTimeout(resolve, 1000));
907
- const homeKeyState = await new Promise((resolve, reject) => {
908
- harness.states.getState('fakeroku.0.TestRoku.Home', (err, state) => {
909
- if (err) return reject(err);
910
- resolve(state);
911
- });
912
- });
913
-
914
- expect(homeKeyState).toBeTruthy();
915
- expect(homeKeyState.val).toBe(true);
916
- });
917
- ```
@@ -1,194 +0,0 @@
1
- # GitHub Action Template: Automated Version Check and Update for ioBroker Copilot Instructions
2
- # Version: 0.4.0
3
- #
4
- # This action automatically checks for template updates and creates issues when updates are available
5
-
6
- name: Check ioBroker Copilot Template Version
7
-
8
- on:
9
- schedule:
10
- - cron: '23 3 * * 0' # Weekly check optimized for off-peak hours (3:23 AM UTC Sunday)
11
- workflow_dispatch: # Allow manual triggering
12
-
13
- jobs:
14
- check-template:
15
- runs-on: ubuntu-latest
16
- permissions:
17
- issues: write
18
- contents: read
19
-
20
- steps:
21
- - name: Checkout repository
22
- uses: actions/checkout@v6
23
-
24
- - name: Dynamic template version check
25
- id: version-check
26
- run: |
27
- echo "🔍 Starting dynamic ioBroker Copilot template version check..."
28
-
29
- # Get current version from local copilot instructions
30
- if [ -f ".github/copilot-instructions.md" ]; then
31
- CURRENT_VERSION=$(awk '/Version:|Template Version:/ {match($0, /([0-9]+(\.[0-9]+)*)/, arr); if (arr[1] != "") print arr[1]}' .github/copilot-instructions.md | head -1)
32
- if [ -z "$CURRENT_VERSION" ]; then CURRENT_VERSION="unknown"; fi
33
- echo "📋 Current local version: $CURRENT_VERSION"
34
- else
35
- CURRENT_VERSION="none"
36
- echo "❌ No .github/copilot-instructions.md file found"
37
- fi
38
-
39
- # Get latest version from centralized metadata
40
- echo "🌐 Fetching latest template version from centralized config..."
41
- LATEST_VERSION=$(curl -s https://raw.githubusercontent.com/DrozmotiX/ioBroker-Copilot-Instructions/main/config/metadata.json | jq -r '.version' 2>/dev/null || echo "unknown")
42
- if [ -z "$LATEST_VERSION" ] || [ "$LATEST_VERSION" = "null" ]; then
43
- LATEST_VERSION="unknown"
44
- fi
45
- echo "📋 Latest available version: $LATEST_VERSION"
46
-
47
- # Determine repository status
48
- COPILOT_INITIALIZED="false"
49
- UPDATE_NEEDED="false"
50
- SETUP_NEEDED="false"
51
-
52
- if [ "$CURRENT_VERSION" = "none" ]; then
53
- SETUP_NEEDED="true"
54
- echo "🆕 Status: Setup needed - no copilot instructions found"
55
- elif [ "$CURRENT_VERSION" = "unknown" ] || [ "$LATEST_VERSION" = "unknown" ]; then
56
- echo "❓ Status: Cannot determine versions - manual check required"
57
- else
58
- # Compare versions (simple string comparison for now)
59
- if [ "$CURRENT_VERSION" != "$LATEST_VERSION" ]; then
60
- UPDATE_NEEDED="true"
61
- COPILOT_INITIALIZED="true"
62
- echo "📈 Status: Update needed - $CURRENT_VERSION → $LATEST_VERSION"
63
- else
64
- COPILOT_INITIALIZED="true"
65
- echo "✅ Status: Up to date - version $CURRENT_VERSION"
66
- fi
67
- fi
68
-
69
- # Set outputs for later steps
70
- echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
71
- echo "latest_version=$LATEST_VERSION" >> $GITHUB_OUTPUT
72
- echo "copilot_initialized=$COPILOT_INITIALIZED" >> $GITHUB_OUTPUT
73
- echo "update_needed=$UPDATE_NEEDED" >> $GITHUB_OUTPUT
74
- echo "setup_needed=$SETUP_NEEDED" >> $GITHUB_OUTPUT
75
-
76
- - name: Check for existing issues
77
- id: issue-check
78
- uses: actions/github-script@v8
79
- with:
80
- script: |
81
- const { data: issues } = await github.rest.issues.listForRepo({
82
- owner: context.repo.owner,
83
- repo: context.repo.repo,
84
- state: 'open',
85
- labels: 'copilot-setup,automation'
86
- });
87
-
88
- const setupIssues = issues.filter(issue =>
89
- issue.title.includes('Setup ioBroker') ||
90
- issue.title.includes('Update ioBroker') ||
91
- issue.title.includes('Copilot')
92
- );
93
-
94
- core.setOutput('has_existing_issue', setupIssues.length > 0);
95
- core.setOutput('existing_count', setupIssues.length);
96
-
97
- if (setupIssues.length > 0) {
98
- console.log(`Found ${setupIssues.length} existing copilot setup/update issue(s)`);
99
- }
100
-
101
- - name: Create initial setup issue
102
- if: steps.version-check.outputs.setup_needed == 'true' && steps.issue-check.outputs.has_existing_issue == 'false'
103
- uses: actions/github-script@v8
104
- with:
105
- script: |
106
- const title = '🤖 Setup ioBroker GitHub Copilot Instructions';
107
- const body = `# Automated ioBroker Copilot Instructions Setup
108
-
109
- **GitHub Copilot**: Please help me set up GitHub Copilot instructions for my ioBroker adapter repository with full automation and validation.
110
-
111
- ## 🚨 Important Notice - Ignore GitHub Copilot's Own Setup Suggestions
112
-
113
- **GitHub Copilot**: If you see suggestions from GitHub Copilot about setting up copilot instructions (like creating \`.github/copilot-instructions.md\` through GitHub's interface), **IGNORE THEM**. This issue handles the complete setup process with ioBroker-specific optimizations.
114
-
115
- ## Setup Process
116
-
117
- This repository needs initial setup of GitHub Copilot instructions. Please:
118
-
119
- 1. **Initialize with Adapter-Specific Context**: Create \`.github/copilot-instructions.md\` with basic ioBroker adapter context
120
- 2. **Enhance with Full Template**: Merge with comprehensive template from https://raw.githubusercontent.com/DrozmotiX/ioBroker-Copilot-Instructions/main/template.md
121
- 3. **Customize Sections**: Populate [CUSTOMIZE] sections with adapter-specific content only
122
-
123
- **Template Version**: ${{ steps.version-check.outputs.latest_version }}
124
- **Detected Status**: No copilot instructions found
125
-
126
- ## Reference Templates
127
-
128
- - **Initial Setup Action**: https://raw.githubusercontent.com/DrozmotiX/ioBroker-Copilot-Instructions/main/templates/ghAction-InitialSetup.yml
129
- - **Full Template**: https://raw.githubusercontent.com/DrozmotiX/ioBroker-Copilot-Instructions/main/template.md
130
- - **Version Check Action**: https://raw.githubusercontent.com/DrozmotiX/ioBroker-Copilot-Instructions/main/templates/ghAction-AutomatedVersionCheckAndUpdate.yml`;
131
-
132
- await github.rest.issues.create({
133
- owner: context.repo.owner,
134
- repo: context.repo.repo,
135
- title: title,
136
- body: body,
137
- labels: ['copilot-setup', 'automation']
138
- });
139
-
140
- - name: Create update issue
141
- if: steps.version-check.outputs.update_needed == 'true' && steps.issue-check.outputs.has_existing_issue == 'false'
142
- uses: actions/github-script@v8
143
- with:
144
- script: |
145
- const title = '🤖 Update ioBroker Copilot Instructions Template';
146
- const body = `# Automated ioBroker Copilot Template Update Request
147
-
148
- **GitHub Copilot**: Please help me validate and update my ioBroker adapter's Copilot instructions template while preserving all custom sections.
149
-
150
- ## Update Required
151
-
152
- - **Current Version**: ${{ steps.version-check.outputs.current_version }}
153
- - **Latest Version**: ${{ steps.version-check.outputs.latest_version }}
154
- - **Status**: Update needed
155
-
156
- ## Update Process
157
-
158
- Please merge the latest ioBroker template while preserving all customizations:
159
-
160
- \`\`\`
161
- Merge the ioBroker template from https://raw.githubusercontent.com/DrozmotiX/ioBroker-Copilot-Instructions/main/template.md with my existing .github/copilot-instructions.md.
162
-
163
- CRITICAL REQUIREMENTS:
164
- 1. Preserve ALL [CUSTOMIZE] sections and their content exactly as they are
165
- 2. Maintain any project-specific context not already covered in the template
166
- 3. Add the latest ioBroker best practices from the new template
167
- 4. Update the version number to ${{ steps.version-check.outputs.latest_version }}
168
- 5. Keep the Template Source reference up-to-date
169
- 6. Ensure no custom content is lost during the merge
170
- 7. REMOVE any duplicate content from [CUSTOMIZE] sections that already exists in the standard template
171
- \`\`\`
172
-
173
- ## Reference Templates
174
-
175
- - **Latest Template**: https://raw.githubusercontent.com/DrozmotiX/ioBroker-Copilot-Instructions/main/template.md
176
- - **Update Template**: https://raw.githubusercontent.com/DrozmotiX/ioBroker-Copilot-Instructions/main/templates/automated-template-update.md
177
- - **Version Check Action**: https://raw.githubusercontent.com/DrozmotiX/ioBroker-Copilot-Instructions/main/templates/ghAction-AutomatedVersionCheckAndUpdate.yml`;
178
-
179
- await github.rest.issues.create({
180
- owner: context.repo.owner,
181
- repo: context.repo.repo,
182
- title: title,
183
- body: body,
184
- labels: ['template-update', 'automation']
185
- });
186
-
187
- - name: Summary
188
- run: |
189
- echo "🎯 Template Version Check Complete"
190
- echo " Current: ${{ steps.version-check.outputs.current_version }}"
191
- echo " Latest: ${{ steps.version-check.outputs.latest_version }}"
192
- echo " Setup needed: ${{ steps.version-check.outputs.setup_needed }}"
193
- echo " Update needed: ${{ steps.version-check.outputs.update_needed }}"
194
- echo " Existing issues: ${{ steps.issue-check.outputs.existing_count }}"