[release-11 4.8] backport build fixes (#109468)

* [release-11.6.5] Update npm build in daggerbuild & revert some script changes (#109352)

* update daggerbuild/frontend/npm.go

* combine lerna commands

* revert scripts changes

(cherry picked from commit 2d2d6d1ad5)

* [release-11.6.5] update nx (#109400)

* update nx

(cherry picked from commit b065bf1fd9bd355614a2d3acd1eba3864267d042)

* set some NX env variables

* add make to cypress container

* update cypress image

* also install gcc

* Also add g++

* upgrade lerna too

(cherry picked from commit 7d067d343a)

* upgrade lerna

* try to not update nx but just fix packages build?

* undo webpack changes
This commit is contained in:
Kevin Minehart
2025-08-11 13:44:57 -05:00
committed by GitHub
parent cc4a103944
commit 4f8cc402f6
15 changed files with 67 additions and 149 deletions
@@ -6,12 +6,14 @@ import (
)
func CypressImage(version string) string {
return "cypress/included:13.1.0"
return "cypress/included:13.10.0"
}
// CypressContainer returns a docker container with everything set up that is needed to build or run e2e tests.
func CypressContainer(d *dagger.Client, base string) *dagger.Container {
container := d.Container().From(base).WithEntrypoint([]string{})
container := d.Container().From(base).WithEntrypoint([]string{}).
WithExec([]string{"apt-get", "update", "-yq"}).
WithExec([]string{"apt-get", "install", "-yq", "make", "gcc", "g++"})
return container
}
@@ -30,6 +30,8 @@ func Builder(d *dagger.Client, platform dagger.Platform, src *dagger.Directory,
},
},
).
WithEnvVariable("NX_ISOLATE_PLUGINS", "false").
WithEnvVariable("NX_DAEMON", "false").
WithWorkdir("/src")
// TODO: Should figure out exactly what we can include without all the extras so we can take advantage of caching better.
+1 -9
View File
@@ -12,22 +12,14 @@ import (
// NPMPackages versions and packs the npm packages into tarballs into `npm-packages` directory.
// It then returns the npm-packages directory as a dagger.Directory.
func NPMPackages(builder *dagger.Container, d *dagger.Client, log *slog.Logger, src *dagger.Directory, ersion string) (*dagger.Directory, error) {
// Check if the version of Grafana uses lerna or nx to manage package versioning.
var (
out = fmt.Sprintf("/src/npm-packages/%%s-%v.tgz", "v"+ersion)
lernaBuild = fmt.Sprintf("yarn run packages:build && yarn lerna version %s --exact --no-git-tag-version --no-push --force-publish -y", ersion)
lernaPack = fmt.Sprintf("yarn lerna exec --no-private -- yarn pack --out %s", out)
nxBuild = fmt.Sprintf("yarn run packages:build && yarn nx release version %s --no-git-commit --no-git-tag --no-stage-changes --group grafanaPackages", ersion)
nxPack = fmt.Sprintf("yarn nx exec --projects=$(cat nx.json | jq -r '.release.groups.grafanaPackages.projects | join(\",\")') -- yarn pack --out %s", out)
)
return builder.WithExec([]string{"mkdir", "npm-packages"}).
WithEnvVariable("SHELL", "/bin/bash").
WithExec([]string{"yarn", "install", "--immutable"}).
WithExec([]string{"/bin/bash", "-c", fmt.Sprintf("if [ -f lerna.json ]; then %s; else %s; fi", lernaBuild, nxBuild)}).
WithExec([]string{"/bin/bash", "-c", fmt.Sprintf("if [ -f lerna.json ]; then %s; else %s; fi", lernaPack, nxPack)}).
WithExec([]string{"/bin/bash", "-c", fmt.Sprintf("yarn run packages:build && yarn lerna version %s --exact --no-git-tag-version --no-push --force-publish -y && yarn lerna exec --no-private -- yarn pack --out %s", ersion, out)}).
Directory("./npm-packages"), nil
}
+10 -32
View File
@@ -30,8 +30,6 @@ const config: ConfigFile = {
'getDashboardByUid',
'getLibraryElementByUid',
'getResourceDependencies',
],
},
'../public/app/features/preferences/api/user/endpoints.gen.ts': {
@@ -41,45 +39,25 @@ const config: ConfigFile = {
apiImport: 'baseAPI',
filterEndpoints: ['getUserPreferences', 'updateUserPreferences', 'patchUserPreferences'],
},
'../public/app/api/clients/iam/v0alpha1/endpoints.gen.ts': {
'../public/app/features/iam/api/endpoints.gen.ts': {
schemaFile: '../data/openapi/iam.grafana.app-v0alpha1.json',
apiFile: '../public/app/api/clients/iam/v0alpha1/baseAPI.ts',
apiFile: '../public/app/features/iam/api/api.ts',
apiImport: 'iamApi',
filterEndpoints: ['getDisplayMapping'],
exportName: 'generatedIamApi',
flattenArg: false,
tag: true,
},
'../public/app/api/clients/provisioning/v0alpha1/endpoints.gen.ts': {
apiFile: '../public/app/api/clients/provisioning/v0alpha1/baseAPI.ts',
'../public/app/features/provisioning/api/endpoints.gen.ts': {
apiFile: '../public/app/features/provisioning/api/baseAPI.ts',
schemaFile: '../data/openapi/provisioning.grafana.app-v0alpha1.json',
apiImport: 'baseAPI',
filterEndpoints,
argSuffix: 'Arg',
responseSuffix: 'Response',
tag: true,
hooks: true,
},
'../public/app/api/clients/folder/v1beta1/endpoints.gen.ts': {
apiFile: '../public/app/api/clients/folder/v1beta1/baseAPI.ts',
schemaFile: '../data/openapi/folder.grafana.app-v1beta1.json',
tag: true,
},
'../public/app/api/clients/advisor/v0alpha1/endpoints.gen.ts': {
apiFile: '../public/app/api/clients/advisor/v0alpha1/baseAPI.ts',
schemaFile: '../data/openapi/advisor.grafana.app-v0alpha1.json',
filterEndpoints: [
'createCheck',
'getCheck',
'listCheck',
'deleteCheck',
'updateCheck',
'listCheckType',
'updateCheckType',
],
tag: true,
},
'../public/app/api/clients/playlist/v0alpha1/endpoints.gen.ts': {
apiFile: '../public/app/api/clients/playlist/v0alpha1/baseAPI.ts',
schemaFile: '../data/openapi/playlist.grafana.app-v0alpha1.json',
filterEndpoints: ['listPlaylist', 'getPlaylist', 'createPlaylist', 'deletePlaylist', 'replacePlaylist'],
tag: true,
},
// PLOP_INJECT_API_CLIENT - Used by the API client generator
},
};
+1 -10
View File
@@ -5,13 +5,7 @@ content_security_policy_template = """require-trusted-types-for 'script'; script
enable_frontend_sandbox_for_plugins = sandbox-app-test,sandbox-test-datasource,sandbox-test-panel
[feature_toggles]
publicDashboards=true
grafanaAPIServer=true
queryLibrary=true
queryService=true
[environment]
stack_id = 12345
enable = publicDashboards
[plugins]
allow_loading_unsigned_plugins=grafana-extensionstest-app,grafana-extensionexample1-app,grafana-extensionexample2-app,grafana-extensionexample3-app,grafana-e2etest-datasource
@@ -25,6 +19,3 @@ max_open_conn = 2
[smtp]
enabled = true
host = localhost:7777
[cloud_migration]
developer_mode = true ; Enable developer mode to use in-memory implementations of 3rdparty services needed.
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
. scripts/grafana-server/variables
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
set -eo pipefail
. scripts/grafana-server/variables
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
DEFAULT_RUNDIR=scripts/grafana-server/tmp
RUNDIR=${RUNDIR:-$DEFAULT_RUNDIR}
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
set -eo pipefail
. scripts/grafana-server/variables
+10 -16
View File
@@ -1,5 +1,6 @@
import PackageJson from '@npmcli/package-json';
import { mkdir } from 'node:fs/promises';
import { join, dirname } from 'node:path';
const cwd = process.cwd();
@@ -7,17 +8,18 @@ try {
const pkgJson = await PackageJson.load(cwd);
const cjsIndex = pkgJson.content.publishConfig?.main ?? pkgJson.content.main;
const esmIndex = pkgJson.content.publishConfig?.module ?? pkgJson.content.module;
const typesIndex = pkgJson.content.publishConfig?.types ?? pkgJson.content.types;
const cjsTypes = pkgJson.content.publishConfig?.types ?? pkgJson.content.types;
const esmTypes = `./${join(dirname(esmIndex), 'index.d.mts')}`;
const exports = {
'./package.json': './package.json',
'.': {
import: {
types: typesIndex,
types: esmTypes,
default: esmIndex,
},
require: {
types: typesIndex,
types: cjsTypes,
default: cjsIndex,
},
},
@@ -31,17 +33,9 @@ try {
};
}
// Fix for @grafana/i18n so eslint-plugin can be imported by consumers
if (pkgJson.content.name === '@grafana/i18n') {
exports['./eslint-plugin'] = {
import: './dist/eslint/index.cjs',
require: './dist/eslint/index.cjs',
};
}
pkgJson.update({
main: cjsIndex,
types: typesIndex,
types: cjsTypes,
module: esmIndex,
exports,
});
@@ -58,12 +52,12 @@ try {
...pkgJson.content.exports,
[`./${aliasName}`]: {
import: {
types: typesIndex.replace('index', aliasName),
types: esmTypes.replace('index', aliasName),
default: esmIndex.replace('index', aliasName),
},
require: {
types: typesIndex.replace('index', aliasName),
default: cjsIndex.replace('index', aliasName),
types: cjsTypes.replace('index', aliasName),
default: cjsTypes.replace('index', aliasName),
},
},
},
@@ -86,7 +80,7 @@ async function createAliasPackageJsonFiles(packageJsonContent, aliasName) {
const pkgJson = await PackageJson.create(pkgJsonPath, {
data: {
name: pkgName,
types: `../dist/types/${aliasName}.d.ts`,
types: `../dist/cjs/${aliasName}.d.cts`,
main: `../dist/cjs/${aliasName}.cjs`,
module: `../dist/esm/${aliasName}.mjs`,
},
+6 -10
View File
@@ -1,4 +1,3 @@
// @ts-check
const { parse } = require('ini');
const { readFileSync, existsSync } = require('node:fs');
const path = require('path');
@@ -19,17 +18,14 @@ const getEnvConfig = () => {
const custom = parse(customSettings);
const merged = { ...defaults.frontend_dev, ...custom.frontend_dev };
// Take all frontend keys from the ini file and prefix with `frontend_dev_`,
// so they can be added to `process.env` elsewhere
/** @type {Record<string, unknown>} */
const env = {};
for (const [key, value] of Object.entries(merged)) {
env[`frontend_dev_${key}`] = value;
}
return env;
return Object.entries(merged).reduce((acc, [key, value]) => {
return {
...acc,
[`frontend_dev_${key}`]: value,
};
}, {});
};
module.exports = getEnvConfig;
+3 -11
View File
@@ -5,14 +5,10 @@ const path = require('path');
module.exports = function (options) {
return {
test: /\.(sa|sc|c)ss$/,
test: /\.scss$/,
exclude: /node_modules/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: './',
},
},
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
@@ -34,10 +30,6 @@ module.exports = function (options) {
loader: 'sass-loader',
options: {
sourceMap: options.sourceMap,
sassOptions: {
// silencing these warnings since we're planning to remove sass when angular is gone
silenceDeprecations: ['import', 'global-builtin'],
},
},
},
],
+18 -13
View File
@@ -1,4 +1,3 @@
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
@@ -10,10 +9,6 @@ module.exports = {
app: './public/app/index.ts',
swagger: './public/swagger/index.tsx',
},
experiments: {
// Required to load WASM modules.
asyncWebAssembly: true,
},
output: {
clean: true,
path: path.resolve(__dirname, '../../public/build'),
@@ -27,6 +22,9 @@ module.exports = {
// some of data source plugins use global Prism object to add the language definition
// we want to have same Prism object in core and in grafana/ui
prismjs: require.resolve('prismjs'),
// some sub-dependencies use a different version of @emotion/react and generate warnings
// in the browser about @emotion/react loaded twice. We want to only load it once
'@emotion/react': require.resolve('@emotion/react'),
// due to our webpack configuration not understanding package.json `exports`
// correctly we must alias this package to the correct file
// the alternative to this alias is to copy-paste the file into our
@@ -69,14 +67,6 @@ module.exports = {
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
}),
new CopyWebpackPlugin({
patterns: [
{
from: 'public/img',
to: 'img',
},
],
}),
],
module: {
rules: [
@@ -106,11 +96,20 @@ module.exports = {
},
],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/,
type: 'asset/resource',
generator: { filename: 'static/img/[name].[hash:8][ext]' },
},
// for pre-caching SVGs as part of the JS bundles
{
test: /(unicons|mono|custom|solid)[\\/].*\.svg$/,
type: 'asset/source',
},
{
// Required for msagl library (used in Nodegraph panel) to work
test: /\.m?js$/,
@@ -127,6 +126,12 @@ module.exports = {
chunks: 'all',
minChunks: 1,
cacheGroups: {
unicons: {
test: /[\\/]node_modules[\\/]@iconscout[\\/]react-unicons[\\/].*[jt]sx?$/,
chunks: 'initial',
priority: 20,
enforce: true,
},
moment: {
test: /[\\/]node_modules[\\/]moment[\\/].*[jt]sx?$/,
chunks: 'initial',
+7 -33
View File
@@ -4,12 +4,10 @@ const browserslist = require('browserslist');
const { resolveToEsbuildTarget } = require('esbuild-plugin-browserslist');
const ESLintPlugin = require('eslint-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const fs = require('fs');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require('path');
const { DefinePlugin, EnvironmentPlugin } = require('webpack');
const WebpackAssetsManifest = require('webpack-assets-manifest');
const LiveReloadPlugin = require('webpack-livereload-plugin');
const { merge } = require('webpack-merge');
const WebpackBar = require('webpackbar');
@@ -30,21 +28,6 @@ function getDecoupledPlugins() {
return packages.filter((pkg) => pkg.dir.includes('plugins/datasource')).map((pkg) => `${pkg.dir}/**`);
}
// When linking scenes for development, resolve the path to the src directory for sourcemaps
function scenesModule() {
const scenesPath = path.resolve('./node_modules/@grafana/scenes');
try {
const status = fs.lstatSync(scenesPath);
if (status.isSymbolicLink()) {
console.log(`scenes is linked to local scenes repo`);
return path.resolve(scenesPath + '/src');
}
} catch (error) {
console.error(`Error checking scenes path: ${error.message}`);
}
return scenesPath;
}
const envConfig = getEnvConfig();
module.exports = (env = {}) => {
@@ -68,10 +51,14 @@ module.exports = (env = {}) => {
// Packages linked for development need react to be resolved from the same location
react: path.resolve('./node_modules/react'),
// Also Grafana packages need to be resolved from the same location so they share
// the same singletons
'@grafana/runtime': path.resolve(__dirname, '../../packages/grafana-runtime'),
'@grafana/data': path.resolve(__dirname, '../../packages/grafana-data'),
// This is required to correctly resolve react-router-dom when linking with
// local version of @grafana/scenes
'react-router-dom': path.resolve('./node_modules/react-router-dom'),
'@grafana/scenes': scenesModule(),
},
},
@@ -87,7 +74,7 @@ module.exports = (env = {}) => {
},
require('./sass.rule.js')({
sourceMap: false,
preserveUrl: true,
preserveUrl: false,
}),
],
},
@@ -118,24 +105,13 @@ module.exports = (env = {}) => {
},
plugins: [
...(parseInt(env.liveReload, 10)
? [
new LiveReloadPlugin({
appendScriptTag: true,
useSourceHash: true,
hostname: 'localhost',
protocol: 'http',
port: 35750,
}),
]
: []),
parseInt(env.noTsCheck, 10)
? new DefinePlugin({}) // bogus plugin to satisfy webpack API
: new ForkTsCheckerWebpackPlugin({
async: true, // don't block webpack emit
typescript: {
mode: 'write-references',
memoryLimit: 5096,
memoryLimit: 4096,
diagnosticOptions: {
semantic: true,
syntactic: true,
@@ -148,7 +124,6 @@ module.exports = (env = {}) => {
cache: true,
lintDirtyModulesOnly: true, // don't lint on start, only lint changed files
extensions: ['.ts', '.tsx'],
configType: 'flat',
}),
new MiniCssExtractPlugin({
filename: 'grafana.[name].[contenthash].css',
@@ -161,7 +136,6 @@ module.exports = (env = {}) => {
new WebpackAssetsManifest({
entrypoints: true,
integrity: true,
integrityHashes: ['sha384', 'sha512'],
publicPath: true,
}),
new WebpackBar({
+1 -9
View File
@@ -10,10 +10,8 @@ const { EnvironmentPlugin } = require('webpack');
const WebpackAssetsManifest = require('webpack-assets-manifest');
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const { merge } = require('webpack-merge');
const { SubresourceIntegrityPlugin } = require('webpack-subresource-integrity');
const getEnvConfig = require('./env-util.js');
const FeatureFlaggedSRIPlugin = require('./plugins/FeatureFlaggedSriPlugin');
const common = require('./webpack.common.js');
const esbuildTargets = resolveToEsbuildTarget(browserslist(), { printUnknownTargets: false });
@@ -49,13 +47,10 @@ module.exports = (env = {}) =>
},
require('./sass.rule.js')({
sourceMap: false,
preserveUrl: true,
preserveUrl: false,
}),
],
},
output: {
crossOriginLoading: 'anonymous',
},
optimization: {
nodeEnv: 'production',
minimize: parseInt(env.noMinify, 10) !== 1,
@@ -75,8 +70,6 @@ module.exports = (env = {}) =>
new MiniCssExtractPlugin({
filename: 'grafana.[name].[contenthash].css',
}),
new SubresourceIntegrityPlugin(),
new FeatureFlaggedSRIPlugin(),
/**
* I know we have two manifest plugins here.
* WebpackManifestPlugin was only used in prod before and does not support integrity hashes
@@ -84,7 +77,6 @@ module.exports = (env = {}) =>
new WebpackAssetsManifest({
entrypoints: true,
integrity: true,
integrityHashes: ['sha384', 'sha512'],
publicPath: true,
}),
new WebpackManifestPlugin({