feat: Show the build date on the loading banner of unreleased builds (#2659)
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Vite plugin: writes the date of the build into the card.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Strict length requirement: See below.
|
||||||
|
export const BUILD_DATE_PLACEHOLDER = '__BUILD_DATE_SENTINEL___';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date cannot be handed to the bundler as a substituted name, because the
|
||||||
|
* build configuration is evaluated once and `vite build --watch` reuses it.
|
||||||
|
* As such, every rebuild would report the time the watcher started rather than
|
||||||
|
* the actual build time. Output is generated afresh for each build, so the date
|
||||||
|
* is written here instead.
|
||||||
|
*
|
||||||
|
* @type {() => import('vite').Plugin}
|
||||||
|
*/
|
||||||
|
export const buildDate = () => ({
|
||||||
|
name: 'build-date',
|
||||||
|
|
||||||
|
renderChunk(code) {
|
||||||
|
if (!code.includes(BUILD_DATE_PLACEHOLDER)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const date = new Date().toISOString();
|
||||||
|
if (date.length !== BUILD_DATE_PLACEHOLDER.length) {
|
||||||
|
this.error(
|
||||||
|
'The build date must be exactly as long as the placeholder it replaces.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: code.replaceAll(BUILD_DATE_PLACEHOLDER, date),
|
||||||
|
|
||||||
|
// The replacement is exactly as long as what it replaces, so the existing
|
||||||
|
// sourcemap still describes the code.
|
||||||
|
map: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { execFileSync } from 'node:child_process';
|
import { execFileSync } from 'node:child_process';
|
||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
|
|
||||||
|
import { BUILD_DATE_PLACEHOLDER } from './build-date-plugin.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asks git something or gives back nothing when it cannot be asked.
|
* Asks git something or gives back nothing when it cannot be asked.
|
||||||
*/
|
*/
|
||||||
@@ -23,7 +25,11 @@ const getPackageVersion = () =>
|
|||||||
*
|
*
|
||||||
* `releaseVersion` is the version being released, which only the release
|
* `releaseVersion` is the version being released, which only the release
|
||||||
* workflow knows; a build without one reports the version in `package.json`, or
|
* workflow knows; a build without one reports the version in `package.json`, or
|
||||||
* a development build the commit it was made from.
|
* a development build the commit it was made from. Its presence is what makes a
|
||||||
|
* build a released one.
|
||||||
|
*
|
||||||
|
* The build date is a placeholder here, written in for by the `buildDate`
|
||||||
|
* plugin as each build's output is generated.
|
||||||
*
|
*
|
||||||
* The values are JSON so that a bundler can drop them in as written.
|
* The values are JSON so that a bundler can drop them in as written.
|
||||||
*/
|
*/
|
||||||
@@ -35,10 +41,11 @@ export const getBuildDefines = ({ dev, releaseVersion }) => {
|
|||||||
__ADVANCED_CAMERA_CARD_RELEASE_VERSION__: JSON.stringify(
|
__ADVANCED_CAMERA_CARD_RELEASE_VERSION__: JSON.stringify(
|
||||||
releaseVersion ?? (dev ? developmentVersion : getPackageVersion()),
|
releaseVersion ?? (dev ? developmentVersion : getPackageVersion()),
|
||||||
),
|
),
|
||||||
|
__ADVANCED_CAMERA_CARD_IS_RELEASE_BUILD__: JSON.stringify(!!releaseVersion),
|
||||||
__ADVANCED_CAMERA_CARD_GIT_HASH__: JSON.stringify(gitHash),
|
__ADVANCED_CAMERA_CARD_GIT_HASH__: JSON.stringify(gitHash),
|
||||||
__ADVANCED_CAMERA_CARD_GIT_DATE__: JSON.stringify(
|
__ADVANCED_CAMERA_CARD_GIT_DATE__: JSON.stringify(
|
||||||
askGit('log', '-1', '--format=%cI'),
|
askGit('log', '-1', '--format=%cI'),
|
||||||
),
|
),
|
||||||
__ADVANCED_CAMERA_CARD_BUILD_DATE__: JSON.stringify(new Date().toISOString()),
|
__ADVANCED_CAMERA_CARD_BUILD_DATE__: JSON.stringify(BUILD_DATE_PLACEHOLDER),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import { customElement, property } from 'lit/decorators.js';
|
|||||||
|
|
||||||
import loadingStyle from '../scss/loading.scss?inline';
|
import loadingStyle from '../scss/loading.scss?inline';
|
||||||
import type { EffectName, EffectsManagerInterface } from '../types';
|
import type { EffectName, EffectsManagerInterface } from '../types';
|
||||||
import { getReleaseVersion } from '../utils/build-info.js';
|
import { formatDateAndTime } from '../utils/basic.js';
|
||||||
|
import { getReleaseVersion, getUnreleasedBuildDate } from '../utils/build-info.js';
|
||||||
|
|
||||||
import './icon';
|
import './icon';
|
||||||
|
|
||||||
@@ -80,10 +81,14 @@ export class AdvancedCameraCardLoading extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
const buildDate = getUnreleasedBuildDate();
|
||||||
|
|
||||||
return html`<advanced-camera-card-icon
|
return html`<advanced-camera-card-icon
|
||||||
.icon=${{ icon: 'advanced-camera-card:iris' }}
|
.icon=${{ icon: 'advanced-camera-card:iris' }}
|
||||||
></advanced-camera-card-icon
|
></advanced-camera-card-icon
|
||||||
><span>${getReleaseVersion()}</span>`;
|
><span>${getReleaseVersion()}</span> ${buildDate
|
||||||
|
? html`<span class="build-date">${formatDateAndTime(buildDate, true)}</span>`
|
||||||
|
: ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
|
|||||||
@@ -53,3 +53,8 @@ advanced-camera-card-icon {
|
|||||||
span {
|
span {
|
||||||
font-size: x-large;
|
font-size: x-large;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.build-date {
|
||||||
|
font-size: medium;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
declare const __ADVANCED_CAMERA_CARD_RELEASE_VERSION__: string | undefined;
|
declare const __ADVANCED_CAMERA_CARD_RELEASE_VERSION__: string | undefined;
|
||||||
|
declare const __ADVANCED_CAMERA_CARD_IS_RELEASE_BUILD__: boolean | undefined;
|
||||||
declare const __ADVANCED_CAMERA_CARD_GIT_HASH__: string | undefined;
|
declare const __ADVANCED_CAMERA_CARD_GIT_HASH__: string | undefined;
|
||||||
declare const __ADVANCED_CAMERA_CARD_GIT_DATE__: string | undefined;
|
declare const __ADVANCED_CAMERA_CARD_GIT_DATE__: string | undefined;
|
||||||
declare const __ADVANCED_CAMERA_CARD_BUILD_DATE__: string | undefined;
|
declare const __ADVANCED_CAMERA_CARD_BUILD_DATE__: string | undefined;
|
||||||
@@ -25,6 +26,14 @@ const BUILD_DATE =
|
|||||||
typeof __ADVANCED_CAMERA_CARD_BUILD_DATE__ === 'undefined'
|
typeof __ADVANCED_CAMERA_CARD_BUILD_DATE__ === 'undefined'
|
||||||
? undefined
|
? undefined
|
||||||
: __ADVANCED_CAMERA_CARD_BUILD_DATE__;
|
: __ADVANCED_CAMERA_CARD_BUILD_DATE__;
|
||||||
|
|
||||||
|
const IS_RELEASE_BUILD =
|
||||||
|
typeof __ADVANCED_CAMERA_CARD_IS_RELEASE_BUILD__ === 'undefined'
|
||||||
|
? false
|
||||||
|
: __ADVANCED_CAMERA_CARD_IS_RELEASE_BUILD__;
|
||||||
|
|
||||||
|
const UNRELEASED_BUILD_DATE =
|
||||||
|
!IS_RELEASE_BUILD && BUILD_DATE ? new Date(BUILD_DATE) : null;
|
||||||
/* v8 ignore stop -- @preserve */
|
/* v8 ignore stop -- @preserve */
|
||||||
|
|
||||||
export interface GitInfo {
|
export interface GitInfo {
|
||||||
@@ -34,6 +43,8 @@ export interface GitInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getReleaseVersion = (): string => RELEASE_VERSION;
|
export const getReleaseVersion = (): string => RELEASE_VERSION;
|
||||||
|
export const getUnreleasedBuildDate = (): Date | null => UNRELEASED_BUILD_DATE;
|
||||||
|
|
||||||
export const getGitInfo = (): GitInfo => ({
|
export const getGitInfo = (): GitInfo => ({
|
||||||
hash: GIT_HASH,
|
hash: GIT_HASH,
|
||||||
commitDate: GIT_DATE,
|
commitDate: GIT_DATE,
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
import { getGitInfo, getReleaseVersion } from '../../src/utils/build-info';
|
import {
|
||||||
|
getGitInfo,
|
||||||
|
getReleaseVersion,
|
||||||
|
getUnreleasedBuildDate,
|
||||||
|
} from '../../src/utils/build-info';
|
||||||
|
|
||||||
// As these are running as tests, the won't be build substitutes so this only
|
// As these are running as tests, the won't be build substitutes so this only
|
||||||
// tests default/fallback values.
|
// tests default/fallback values.
|
||||||
@@ -16,3 +20,9 @@ describe('getGitInfo', () => {
|
|||||||
expect(getGitInfo()).toEqual({});
|
expect(getGitInfo()).toEqual({});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getUnreleasedBuildDate', () => {
|
||||||
|
it('should report no build date for an unbuilt card', () => {
|
||||||
|
expect(getUnreleasedBuildDate()).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { visualizer } from 'rollup-plugin-visualizer';
|
import { visualizer } from 'rollup-plugin-visualizer';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
import { buildDate } from './scripts/build-date-plugin.js';
|
||||||
import { getBuildDefines } from './scripts/build-defines.js';
|
import { getBuildDefines } from './scripts/build-defines.js';
|
||||||
import { cleanDist } from './scripts/clean-dist-plugin.js';
|
import { cleanDist } from './scripts/clean-dist-plugin.js';
|
||||||
import { facadeEntry } from './scripts/facade-entry-plugin.js';
|
import { facadeEntry } from './scripts/facade-entry-plugin.js';
|
||||||
@@ -24,6 +25,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
plugins: [
|
plugins: [
|
||||||
cleanDist(),
|
cleanDist(),
|
||||||
svgPath(),
|
svgPath(),
|
||||||
|
buildDate(),
|
||||||
facadeEntry({ publicFileNames: PUBLIC_ENTRIES }),
|
facadeEntry({ publicFileNames: PUBLIC_ENTRIES }),
|
||||||
visualizer({ filename: 'visualizations/treemap.html', template: 'treemap' }),
|
visualizer({ filename: 'visualizations/treemap.html', template: 'treemap' }),
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user