Skip to content

fix(ignore): general cleanup #26595

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 37 additions & 30 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
let watchdogDelays = [2000, 60000, 300000, 900000, 1800000, 3600000];

if (watchdog && process.env.Z2M_WATCHDOG !== 'default') {
if (/^(?:(?:[0-9]*[.])?[0-9]+)+(?:,?(?:[0-9]*[.])?[0-9]+)*$/.test(process.env.Z2M_WATCHDOG)) {
if (/^\d+(.\d+)?(,\d+(.\d+)?)*$/.test(process.env.Z2M_WATCHDOG)) {
watchdogDelays = process.env.Z2M_WATCHDOG.split(',').map((v) => parseFloat(v) * 60000);
} else {
console.log(`Invalid watchdog delays (must use number-only CSV format representing minutes, example: 'Z2M_WATCHDOG=1,5,15,30,60'.`);
Expand Down Expand Up @@ -58,10 +58,16 @@
}

async function currentHash() {
const git = require('git-last-commit');
return await new Promise((resolve) => {
exec('git rev-parse --short=8 HEAD', (error, stdout) => {
const commitHash = stdout.trim();

return new Promise((resolve) => {
git.getLastCommit((err, commit) => (err ? resolve('unknown') : resolve(commit.shortHash)));
if (error || commitHash === '') {
resolve('unknown');
} else {
resolve(commitHash);
}
});
});
}

Expand All @@ -72,10 +78,10 @@
}

async function build(reason) {
return new Promise((resolve, reject) => {
process.stdout.write(`Building Zigbee2MQTT... (${reason})`);
rimrafSync('dist');
process.stdout.write(`Building Zigbee2MQTT... (${reason})`);
rimrafSync('dist');

return await new Promise((resolve, reject) => {
const env = {...process.env};
const _600mb = 629145600;

Expand Down Expand Up @@ -107,8 +113,9 @@
await build('initial build');
}

const distHash = fs.readFileSync(hashFile, 'utf-8');
const distHash = fs.readFileSync(hashFile, 'utf8');
const hash = await currentHash();

if (hash !== 'unknown' && distHash !== hash) {
await build('hash changed');
}
Expand All @@ -118,41 +125,41 @@
console.log(`Starting Zigbee2MQTT ${watchdog ? `with watchdog (${watchdogDelays})` : `without watchdog`}.`);
await checkDist();

const version = engines.node;
// gc
{
const version = engines.node;

if (!semver.satisfies(process.version, version)) {
console.log(`\t\tZigbee2MQTT requires node version ${version}, you are running ${process.version}!\n`);
}
if (!semver.satisfies(process.version, version)) {
console.log(`\t\tZigbee2MQTT requires node version ${version}, you are running ${process.version}!\n`);
}

// Validate settings
const settings = require('./dist/util/settings');
// Validate settings
const settings = require('./dist/util/settings');

settings.reRead();
settings.reRead();

// gc
{
const settingsMigration = require('./dist/util/settingsMigration');

settingsMigration.migrateIfNecessary();
}

const errors = settings.validate();
const errors = settings.validate();

if (errors.length > 0) {
unsolicitedStop = false;
if (errors.length > 0) {
unsolicitedStop = false;

console.log(`\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`);
console.log(' READ THIS CAREFULLY\n');
console.log(`Refusing to start because configuration is not valid, found the following errors:`);
console.log(`\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`);
console.log(' READ THIS CAREFULLY\n');
console.log(`Refusing to start because configuration is not valid, found the following errors:`);

for (const error of errors) {
console.log(`- ${error}`);
}
for (const error of errors) {
console.log(`- ${error}`);
}

console.log(`\nIf you don't know how to solve this, read https://www.zigbee2mqtt.io/guide/configuration`);
console.log(`\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n`);
console.log(`\nIf you don't know how to solve this, read https://www.zigbee2mqtt.io/guide/configuration`);
console.log(`\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n`);

return exit(1);
return exit(1);
}
}

const {Controller} = require('./dist/controller');
Expand Down
2 changes: 1 addition & 1 deletion lib/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ declare global {
serial: {
disable_led: boolean;
port?: string;
adapter?: 'deconz' | 'zstack' | 'ezsp' | 'zigate' | 'ember';
adapter?: 'deconz' | 'zstack' | 'ezsp' | 'zigate' | 'ember' | 'zboss';
baudrate?: number;
rtscts?: boolean;
};
Expand Down
21 changes: 8 additions & 13 deletions lib/util/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {Zigbee2MQTTAPI, Zigbee2MQTTResponse, Zigbee2MQTTResponseEndpoints, Zigbee2MQTTScene} from 'lib/types/api';
import type * as zhc from 'zigbee-herdsman-converters';

import {exec} from 'child_process';
import assert from 'node:assert';
import crypto from 'node:crypto';
import fs from 'node:fs';
Expand Down Expand Up @@ -50,32 +51,26 @@ function capitalize(s: string): string {
}

async function getZigbee2MQTTVersion(includeCommitHash = true): Promise<{commitHash?: string; version: string}> {
const git = await import('git-last-commit');
const packageJSON = await import('../..' + '/package.json');
const packageJSON = await import('../../package.json');
const version = packageJSON.version;
let commitHash: string | undefined;

if (!includeCommitHash) {
return {version: packageJSON.version, commitHash: undefined};
return {version, commitHash};
}

return await new Promise((resolve) => {
const version = packageJSON.version;
exec('git rev-parse --short=8 HEAD', (error, stdout) => {
commitHash = stdout.trim();

git.getLastCommit((err: Error, commit: {shortHash: string}) => {
let commitHash = undefined;

if (err) {
if (error || commitHash === '') {
try {
commitHash = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', '.hash'), 'utf-8');
/* v8 ignore start */
} catch {
commitHash = 'unknown';
}
/* v8 ignore stop */
} else {
commitHash = commit.shortHash;
}

commitHash = commitHash.trim();
resolve({commitHash, version});
});
});
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
"express-static-gzip": "^2.2.0",
"fast-deep-equal": "^3.1.3",
"finalhandler": "^1.3.1",
"git-last-commit": "^1.0.1",
"humanize-duration": "^3.32.1",
"js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
Expand Down
8 changes: 0 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 38 additions & 9 deletions test/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import {exec} from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';

import utils from '../lib/util/utils';

const mockGetLastCommit = vi.fn<() => [boolean, {shortHash: string} | null]>(() => [false, {shortHash: '123'}]);

vi.mock('git-last-commit', () => ({
getLastCommit: vi.fn((cb) => cb(...mockGetLastCommit())),
}));
// keep the implementations, just spy
vi.mock('node:child_process', {spy: true});

describe('Utils', () => {
it('Object is empty', () => {
Expand All @@ -20,13 +18,44 @@ describe('Utils', () => {
expect(utils.objectHasProperties({a: 1, b: 2, c: 3}, ['a', 'b', 'd'])).toBeFalsy();
});

it('git last commit', async () => {
it('get Z2M version', async () => {
const readFileSyncSpy = vi.spyOn(fs, 'readFileSync');
const version = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')).version;

expect(await utils.getZigbee2MQTTVersion()).toStrictEqual({commitHash: '123', version: version});
expect(await utils.getZigbee2MQTTVersion()).toStrictEqual({commitHash: expect.stringMatching(/^(?!unknown)[a-z0-9]{8}$/), version});
expect(exec).toHaveBeenCalledTimes(1);

// @ts-expect-error mock spy
exec.mockImplementationOnce((cmd, cb) => {
cb(null, 'abcd1234');
});
expect(await utils.getZigbee2MQTTVersion()).toStrictEqual({commitHash: 'abcd1234', version});

// @ts-expect-error mock spy
exec.mockImplementationOnce((cmd, cb) => {
cb(null, '');
});
// hash file may or may not be present during testing, don't failing matching if not
expect(await utils.getZigbee2MQTTVersion()).toStrictEqual({commitHash: expect.stringMatching(/^(unknown|([a-z0-9]{8}))$/), version});

readFileSyncSpy.mockImplementationOnce(() => {
throw new Error('no hash file');
});
// @ts-expect-error mock spy
exec.mockImplementationOnce((cmd, cb) => {
cb(null, '');
});
expect(await utils.getZigbee2MQTTVersion()).toStrictEqual({commitHash: 'unknown', version});

mockGetLastCommit.mockReturnValueOnce([true, null]);
expect(await utils.getZigbee2MQTTVersion()).toStrictEqual({commitHash: expect.any(String), version: version});
readFileSyncSpy.mockImplementationOnce(() => {
throw new Error('no hash file');
});
// @ts-expect-error mock spy
exec.mockImplementationOnce((cmd, cb) => {
cb(new Error('invalid'), '');
});
expect(await utils.getZigbee2MQTTVersion()).toStrictEqual({commitHash: 'unknown', version});
expect(exec).toHaveBeenCalledTimes(5);
});

it('Check dependency version', async () => {
Expand Down