Commit 38fc55e0 by Dominik Prokop Committed by GitHub

Merge pull request #15561 from grafana/tooling/npm-scripts

@grafana/ui publishing scripts
parents 5054e841 167a18f1
......@@ -78,3 +78,9 @@ debug.test
/scripts/build/release_publisher/release_publisher
*.patch
# Ignoring frontend packages specifics
/packages/**/dist
/packages/**/compiled
/packages/**/.rpt2_cache
......@@ -22,6 +22,7 @@
"@types/commander": "^2.12.2",
"@types/d3": "^4.10.1",
"@types/enzyme": "^3.1.13",
"@types/inquirer": "^0.0.43",
"@types/jest": "^23.3.2",
"@types/jquery": "^1.10.35",
"@types/node": "^8.0.31",
......@@ -47,6 +48,7 @@
"enzyme-to-json": "^3.3.4",
"es6-promise": "^3.0.2",
"es6-shim": "^0.35.3",
"execa": "^1.0.0",
"expect.js": "~0.2.0",
"expose-loader": "^0.7.3",
"file-loader": "^1.1.11",
......@@ -70,6 +72,7 @@
"html-webpack-harddisk-plugin": "^0.2.0",
"html-webpack-plugin": "^3.2.0",
"husky": "^1.3.1",
"inquirer": "^6.2.2",
"jest": "^23.6.0",
"jest-date-mock": "^1.0.6",
"lint-staged": "^8.1.3",
......@@ -83,6 +86,7 @@
"node-sass": "^4.11.0",
"npm": "^5.4.2",
"optimize-css-assets-webpack-plugin": "^4.0.2",
"ora": "^3.1.0",
"phantomjs-prebuilt": "^2.1.15",
"postcss-browser-reporter": "^0.5.0",
"postcss-loader": "^2.0.6",
......@@ -92,8 +96,10 @@
"react-test-renderer": "^16.5.0",
"redux-mock-store": "^1.5.3",
"regexp-replace-loader": "^1.0.1",
"rimraf": "^2.6.3",
"sass-lint": "^1.10.2",
"sass-loader": "^7.0.1",
"semver": "^5.6.0",
"sinon": "1.17.6",
"style-loader": "^0.21.0",
"systemjs": "0.20.19",
......@@ -129,7 +135,9 @@
"api-tests": "jest --notify --watch --config=tests/api/jest.js",
"storybook": "cd packages/grafana-ui && yarn storybook",
"themes:generate": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/generateSassVariableFiles.ts",
"prettier:check": "prettier --list-different \"**/*.{ts,tsx,scss}\""
"prettier:check": "prettier --list-different \"**/*.{ts,tsx,scss}\"",
"gui:build": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts --build",
"gui:release": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts --release"
},
"husky": {
"hooks": {
......
# 1.0.0-alpha.0 (2019-02-21)
First public release
# Grafana (WIP) shared component library
# Grafana UI components library
Used by internal & external plugins.
@grafana/ui is a collection of components used by [Grafana](https://github.com/grafana/grafana)
Our goal is to deliver Grafana's common UI elements for plugins developers and contributors.
See [package source](https://github.com/grafana/grafana/tree/master/packages/grafana-ui) for more details.
## Installation
`yarn add @grafana/ui`
`npm install @grafana/ui`
'use strict'
if (process.env.NODE_ENV === 'production') {
module.exports = require('./index.production.js');
} else {
module.exports = require('./index.development.js');
}
{
"name": "@grafana/ui",
"version": "1.0.0",
"description": "",
"version": "0.0.0",
"description": "Grafana Components Library",
"keywords": [
"typescript",
"react",
"react-component"
],
"main": "src/index.ts",
"scripts": {
"tslint": "tslint -c tslint.json --project tsconfig.json",
"typecheck": "tsc --noEmit",
"storybook": "start-storybook -p 9001 -c .storybook -s ../../public"
"storybook": "start-storybook -p 9001 -c .storybook -s ../../public",
"clean": "rimraf ./dist ./compiled",
"build": "rollup -c rollup.config.ts"
},
"author": "Grafana Labs",
"license": "Apache-2.0",
......@@ -53,6 +60,13 @@
"react-docgen-typescript-loader": "^3.0.0",
"react-docgen-typescript-webpack-plugin": "^1.1.0",
"react-test-renderer": "^16.7.0",
"rollup": "^1.1.2",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-sourcemaps": "^0.4.2",
"rollup-plugin-terser": "^4.0.4",
"rollup-plugin-typescript2": "^0.19.2",
"rollup-plugin-visualizer": "^0.9.2",
"typescript": "^3.2.2"
},
"resolutions": {
......
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import sourceMaps from 'rollup-plugin-sourcemaps';
import { terser } from 'rollup-plugin-terser';
const pkg = require('./package.json');
const libraryName = pkg.name;
const buildCjsPackage = ({ env }) => {
return {
input: `compiled/index.js`,
output: [
{
file: `dist/index.${env}.js`,
name: libraryName,
format: 'cjs',
sourcemap: true,
exports: 'named',
globals: {
react: 'React',
'prop-types': 'PropTypes',
},
},
],
external: ['react', 'react-dom'],
plugins: [
commonjs({
include: /node_modules/,
namedExports: {
'../../node_modules/lodash/lodash.js': [
'flatten',
'find',
'upperFirst',
'debounce',
'isNil',
'isNumber',
'flattenDeep',
'map',
'chunk',
'sortBy',
'uniqueId',
'zip',
],
'../../node_modules/react-color/lib/components/common': ['Saturation', 'Hue', 'Alpha'],
},
}),
resolve(),
sourceMaps(),
env === 'production' && terser(),
],
};
};
export default [buildCjsPackage({ env: 'development' }), buildCjsPackage({ env: 'production' })];
import React from 'react';
import { ColorPickerProps } from './ColorPicker';
import { ColorPickerProps } from './ColorPickerPopover';
import tinycolor from 'tinycolor2';
import { debounce } from 'lodash';
import debounce from 'lodash/debounce';
interface ColorInputState {
previousColor: string;
......
import React, { Component, createRef } from 'react';
import { PopperController } from '../Tooltip/PopperController';
import { Popper } from '../Tooltip/Popper';
import { ColorPickerPopover } from './ColorPickerPopover';
import { Themeable } from '../../types';
import { ColorPickerPopover, ColorPickerProps, ColorPickerChangeHandler } from './ColorPickerPopover';
import { getColorFromHexRgbOrName } from '../../utils/namedColorsPalette';
import { SeriesColorPickerPopover } from './SeriesColorPickerPopover';
import propDeprecationWarning from '../../utils/propDeprecationWarning';
import { withTheme } from '../../themes/ThemeContext';
type ColorPickerChangeHandler = (color: string) => void;
export interface ColorPickerProps extends Themeable {
color: string;
onChange: ColorPickerChangeHandler;
/**
* @deprecated Use onChange instead
*/
onColorChange?: ColorPickerChangeHandler;
enableNamedColors?: boolean;
children?: JSX.Element;
}
export const warnAboutColorPickerPropsDeprecation = (componentName: string, props: ColorPickerProps) => {
const { onColorChange } = props;
if (onColorChange) {
propDeprecationWarning(componentName, 'onColorChange', 'onChange');
}
};
import { withTheme } from '../../themes/ThemeContext';
export const colorPickerFactory = <T extends ColorPickerProps>(
popover: React.ComponentType<T>,
......
......@@ -3,7 +3,7 @@ import { mount, ReactWrapper } from 'enzyme';
import { ColorPickerPopover } from './ColorPickerPopover';
import { getColorDefinitionByName, getNamedColorPalette } from '../../utils/namedColorsPalette';
import { ColorSwatch } from './NamedColorsGroup';
import { flatten } from 'lodash';
import flatten from 'lodash/flatten';
import { GrafanaThemeType } from '../../types';
import { getTheme } from '../../themes';
......
import React from 'react';
import { NamedColorsPalette } from './NamedColorsPalette';
import { getColorName, getColorFromHexRgbOrName } from '../../utils/namedColorsPalette';
import { ColorPickerProps, warnAboutColorPickerPropsDeprecation } from './ColorPicker';
import { PopperContentProps } from '../Tooltip/PopperController';
import SpectrumPalette from './SpectrumPalette';
import { GrafanaThemeType } from '../../types/theme';
import { GrafanaThemeType, Themeable } from '../../types/theme';
import { warnAboutColorPickerPropsDeprecation } from './warnAboutColorPickerPropsDeprecation';
export type ColorPickerChangeHandler = (color: string) => void;
export interface ColorPickerProps extends Themeable {
color: string;
onChange: ColorPickerChangeHandler;
/**
* @deprecated Use onChange instead
*/
onColorChange?: ColorPickerChangeHandler;
enableNamedColors?: boolean;
children?: JSX.Element;
}
export interface Props<T> extends ColorPickerProps, PopperContentProps {
customPickers?: T;
}
type PickerType = 'palette' | 'spectrum';
interface CustomPickersDescriptor {
export interface CustomPickersDescriptor {
[key: string]: {
tabComponent: React.ComponentType<ColorPickerProps>;
name: string;
};
}
interface State<T> {
activePicker: PickerType | keyof T;
}
......
......@@ -2,7 +2,8 @@ import React, { FunctionComponent } from 'react';
import { Themeable } from '../../types';
import { ColorDefinition, getColorForTheme } from '../../utils/namedColorsPalette';
import { Color } from 'csstype';
import { find, upperFirst } from 'lodash';
import upperFirst from 'lodash/upperFirst';
import find from 'lodash/find';
import { selectThemeVariant } from '../../themes/selectThemeVariant';
type ColorChangeHandler = (color: ColorDefinition) => void;
......
import React, { FunctionComponent } from 'react';
import { ColorPickerPopover } from './ColorPickerPopover';
import { ColorPickerProps } from './ColorPicker';
import { ColorPickerPopover, ColorPickerProps } from './ColorPickerPopover';
import { PopperContentProps } from '../Tooltip/PopperController';
import { Switch } from '../Switch/Switch';
import { withTheme } from '../../themes/ThemeContext';
......
import propDeprecationWarning from '../../utils/propDeprecationWarning';
import { ColorPickerProps } from './ColorPickerPopover';
export const warnAboutColorPickerPropsDeprecation = (componentName: string, props: ColorPickerProps) => {
const { onColorChange } = props;
if (onColorChange) {
propDeprecationWarning(componentName, 'onColorChange', 'onChange');
}
};
import React, { PureComponent } from 'react';
import _ from 'lodash';
import isNil from 'lodash/isNil';
import classNames from 'classnames';
import Scrollbars from 'react-custom-scrollbars';
......@@ -41,7 +41,7 @@ export class CustomScrollbar extends PureComponent<Props> {
updateScroll() {
const ref = this.ref.current;
if (ref && !_.isNil(this.props.scrollTop)) {
if (ref && !isNil(this.props.scrollTop)) {
if (this.props.scrollTop > 10000) {
ref.scrollToBottom();
} else {
......
import React, { InputHTMLAttributes, FunctionComponent } from 'react';
import { FormLabel } from '..';
import { FormLabel } from '../FormLabel/FormLabel';
export interface Props extends InputHTMLAttributes<HTMLInputElement> {
label: string;
......
import React, { PureComponent } from 'react';
import $ from 'jquery';
import { ValueMapping, Threshold, BasicGaugeColor, GrafanaThemeType } from '../../types';
import { getMappedValue } from '../../utils/valueMappings';
import { getColorFromHexRgbOrName, getValueFormat } from '../../utils';
import { Themeable } from '../../index';
import { getColorFromHexRgbOrName } from '../../utils/namedColorsPalette';
import { Themeable, GrafanaThemeType } from '../../types/theme';
import { ValueMapping, Threshold, BasicGaugeColor } from '../../types/panel';
import { getValueFormat } from '../../utils/valueFormats/valueFormats';
type TimeSeriesValue = string | number | null;
......
......@@ -16,7 +16,7 @@ import SelectOptionGroup from './SelectOptionGroup';
import IndicatorsContainer from './IndicatorsContainer';
import NoOptionsMessage from './NoOptionsMessage';
import resetSelectStyles from './resetSelectStyles';
import { CustomScrollbar } from '..';
import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
export interface SelectOptionItem {
label?: string;
......
import React, { PureComponent } from 'react';
import _ from 'lodash';
import uniqueId from 'lodash/uniqueId';
export interface Props {
label: string;
......@@ -17,7 +17,7 @@ export interface State {
export class Switch extends PureComponent<Props, State> {
state = {
id: _.uniqueId('check-'),
id: uniqueId(),
};
internalOnChange = (event: React.FormEvent<HTMLInputElement>) => {
......
import React, { ChangeEvent, PureComponent } from 'react';
import { MappingType, ValueMapping } from '../../types';
import { FormField, FormLabel, Select } from '..';
import { Select } from '../Select/Select';
import { FormField } from '../FormField/FormField';
import { FormLabel } from '../FormLabel/FormLabel';
export interface Props {
valueMapping: ValueMapping;
......
......@@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
import MappingRow from './MappingRow';
import { MappingType, ValueMapping } from '../../types';
import { PanelOptionsGroup } from '..';
import { PanelOptionsGroup } from '../PanelOptionsGroup/PanelOptionsGroup';
export interface Props {
valueMappings: ValueMapping[];
......
......@@ -2,4 +2,3 @@ export * from './components';
export * from './types';
export * from './utils';
export * from './themes';
export * from './themes/ThemeContext';
import React from 'react';
import { GrafanaThemeType, Themeable } from '../types';
import { getTheme } from './index';
import { getTheme } from './getTheme';
import { GrafanaThemeType, Themeable } from '../types/theme';
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
type Subtract<T, K> = Omit<T, keyof K>;
......
import darkTheme from './dark';
import lightTheme from './light';
import { GrafanaTheme } from '../types/theme';
let themeMock: ((name?: string) => GrafanaTheme) | null;
export const getTheme = (name?: string) =>
(themeMock && themeMock(name)) || (name === 'light' ? lightTheme : darkTheme);
export const mockTheme = (mock: (name?: string) => GrafanaTheme) => {
themeMock = mock;
return () => {
themeMock = null;
};
};
import darkTheme from './dark';
import lightTheme from './light';
import { GrafanaTheme } from '../types/theme';
import { ThemeContext, withTheme } from './ThemeContext';
import { getTheme, mockTheme } from './getTheme';
let themeMock: ((name?: string) => GrafanaTheme) | null;
export let getTheme = (name?: string) => (themeMock && themeMock(name)) || (name === 'light' ? lightTheme : darkTheme);
export const mockTheme = (mock: (name?: string) => GrafanaTheme) => {
themeMock = mock;
return () => {
themeMock = null;
};
};
export { ThemeContext, withTheme, mockTheme, getTheme };
import _ from 'lodash';
import map from 'lodash/map';
import sortBy from 'lodash/sortBy';
import flattenDeep from 'lodash/flattenDeep';
import chunk from 'lodash/chunk';
import zip from 'lodash/zip';
import tinycolor from 'tinycolor2';
export const PALETTE_ROWS = 4;
......@@ -69,16 +73,16 @@ export const colors = [
];
function sortColorsByHue(hexColors: string[]) {
const hslColors = _.map(hexColors, hexToHsl);
const hslColors = map(hexColors, hexToHsl);
const sortedHSLColors = _.sortBy(hslColors, ['h']);
const chunkedHSLColors = _.chunk(sortedHSLColors, PALETTE_ROWS);
const sortedChunkedHSLColors = _.map(chunkedHSLColors, chunk => {
return _.sortBy(chunk, 'l');
const sortedHSLColors = sortBy(hslColors, ['h']);
const chunkedHSLColors = chunk(sortedHSLColors, PALETTE_ROWS);
const sortedChunkedHSLColors = map(chunkedHSLColors, chunk => {
return sortBy(chunk, 'l');
});
const flattenedZippedSortedChunkedHSLColors = _.flattenDeep(_.zip(...sortedChunkedHSLColors));
const flattenedZippedSortedChunkedHSLColors = flattenDeep(zip(...sortedChunkedHSLColors));
return _.map(flattenedZippedSortedChunkedHSLColors, hslToHex);
return map(flattenedZippedSortedChunkedHSLColors, hslToHex);
}
function hexToHsl(color: string) {
......
import { flatten } from 'lodash';
import { GrafanaThemeType } from '../types';
import flatten from 'lodash/flatten';
import { GrafanaThemeType } from '../types/theme';
import tinycolor from 'tinycolor2';
type Hue = 'green' | 'yellow' | 'red' | 'blue' | 'orange' | 'purple';
......
// Libraries
import _ from 'lodash';
import isNumber from 'lodash/isNumber';
import { colors } from './colors';
......@@ -75,7 +75,7 @@ export function processTimeSeries({ timeSeries, nullValueMode }: Options): TimeS
}
if (currentValue !== null) {
if (_.isNumber(currentValue)) {
if (isNumber(currentValue)) {
total += currentValue;
allIsNull = false;
nonNulls++;
......
......@@ -2,7 +2,7 @@ import React from 'react';
import { RenderFunction } from '@storybook/react';
import { ThemeContext } from '../../themes/ThemeContext';
import { select } from '@storybook/addon-knobs';
import { getTheme } from '../../themes';
import { getTheme } from '../../themes/index';
import { GrafanaThemeType } from '../../types';
const ThemableStory: React.FunctionComponent<{}> = ({ children }) => {
......
{
"extends": "./tsconfig.json",
"exclude": [
"dist",
"node_modules",
"src/utils/storybook",
"**/*.test.ts",
"**/*.test.tsx",
"**/*.story.tsx",
"**/*.tmpl.ts"
]
}
......@@ -5,13 +5,15 @@
"compilerOptions": {
"rootDirs": [".", "stories"],
"module": "esnext",
"outDir": "dist",
"outDir": "compiled",
"declaration": true,
"declarationDir": "dist",
"strict": true,
"alwaysStrict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"typeRoots": ["./node_modules/@types", "types"],
"skipLibCheck": true // Temp workaround for Duplicate identifier tsc errors
"skipLibCheck": true, // Temp workaround for Duplicate identifier tsc errors,
"removeComments": false
}
}
......@@ -11,7 +11,7 @@ import { colors } from '@grafana/ui';
import TableModel, { mergeTablesIntoModel } from 'app/core/table_model';
// Types
import { RawTimeRange, IntervalValues, DataQuery, DataSourceApi } from '@grafana/ui/src/types';
import { RawTimeRange, IntervalValues, DataQuery, DataSourceApi } from '@grafana/ui';
import TimeSeries from 'app/core/time_series2';
import {
ExploreUrlState,
......
export type Task<T> = (options: T) => Promise<void>;
import program from 'commander';
import { startTask } from './start';
import chalk from 'chalk';
import { execTask } from './utils/execTask';
export type Task<T> = (options: T) => Promise<void>;
// TODO: Refactor to commander commands
// This will enable us to have command scoped options and limit the ifs below
program
.option('-h, --hot', 'Runs front-end with hot reload enabled')
.option('-t, --theme', 'Watches for theme changes and regenerates variables.scss files')
.option('-d, --depreciate <scripts>', 'Inform about npm script deprecation', v => v.split(','))
.option('-b, --build', 'Created @grafana/ui build')
.option('-r, --release', 'Releases @grafana/ui to npm')
.parse(process.argv);
if (program.depreciate && program.depreciate.length === 2) {
console.log(
chalk.yellow.bold(
`[NPM script depreciation] ${program.depreciate[0]} is deprecated! Use ${program.depreciate[1]} instead!`
)
);
if (program.build) {
execTask('grafanaui.build');
} else if (program.release) {
execTask('grafanaui.release');
} else {
if (program.depreciate && program.depreciate.length === 2) {
console.log(
chalk.yellow.bold(
`[NPM script depreciation] ${program.depreciate[0]} is deprecated! Use ${program.depreciate[1]} instead!`
)
);
}
execTask('core.start', {
watchThemes: !!program.theme,
hot: !!program.hot,
});
}
startTask({
watchThemes: !!program.theme,
hot: !!program.hot,
});
import concurrently from 'concurrently';
import { Task } from '..';
export const startTask = async ({ watchThemes, hot }: { watchThemes: boolean; hot: boolean }) => {
interface StartTaskOptions {
watchThemes: boolean;
hot: boolean;
}
const startTask: Task<StartTaskOptions> = async ({ watchThemes, hot }) => {
const jobs = [];
if (watchThemes) {
jobs.push({
command: 'nodemon -e ts -w ./packages/grafana-ui/src/themes -x yarn run themes:generate',
......@@ -30,3 +37,5 @@ export const startTask = async ({ watchThemes, hot }: { watchThemes: boolean; ho
process.exit(1);
}
};
export default startTask;
import execa from 'execa';
import fs from 'fs';
import { Task } from '..';
import { changeCwdToGrafanaUi, restoreCwd } from '../utils/cwd';
import chalk from 'chalk';
import { startSpinner } from '../utils/startSpinner';
let distDir, cwd;
const clean = async () => {
const spinner = startSpinner('Cleaning');
try {
await execa('npm', ['run', 'clean']);
spinner.succeed();
} catch (e) {
spinner.fail();
throw e;
}
};
const compile = async () => {
const spinner = startSpinner('Compiling sources');
try {
await execa('tsc', ['-p', './tsconfig.build.json']);
spinner.succeed();
} catch (e) {
console.log(e);
spinner.fail();
}
};
const rollup = async () => {
const spinner = startSpinner('Bundling');
try {
await execa('npm', ['run', 'build']);
spinner.succeed();
} catch (e) {
spinner.fail();
}
};
export const savePackage = async (path, pkg) => {
const spinner = startSpinner('Updating package.json');
return new Promise((resolve, reject) => {
fs.writeFile(path, JSON.stringify(pkg, null, 2), err => {
if (err) {
spinner.fail();
console.error(err);
reject(err);
return;
}
spinner.succeed();
resolve();
});
});
};
const preparePackage = async pkg => {
pkg.main = 'index.js';
pkg.types = 'index.d.ts';
await savePackage(`${cwd}/dist/package.json`, pkg);
};
const moveFiles = async () => {
const files = ['README.md', 'CHANGELOG.md', 'index.js'];
const spinner = startSpinner(`Moving ${files.join(', ')} files`);
const promises = files.map(file => {
return fs.copyFile(`${cwd}/${file}`, `${distDir}/${file}`, err => {
if (err) {
console.error(err);
return;
}
});
});
try {
await Promise.all(promises);
spinner.succeed();
} catch (e) {
spinner.fail();
}
};
const buildTask: Task<void> = async () => {
cwd = changeCwdToGrafanaUi();
distDir = `${cwd}/dist`;
const pkg = require(`${cwd}/package.json`);
console.log(chalk.yellow(`Building ${pkg.name} @ ${pkg.version}`));
await clean();
await compile();
await rollup();
await preparePackage(pkg);
await moveFiles();
restoreCwd();
};
export default buildTask;
import execa from 'execa';
import { Task } from '..';
import { execTask } from '../utils/execTask';
import { changeCwdToGrafanaUiDist, changeCwdToGrafanaUi } from '../utils/cwd';
import semver from 'semver';
import inquirer from 'inquirer';
import chalk from 'chalk';
import { startSpinner } from '../utils/startSpinner';
import { savePackage } from './grafanaui.build';
type VersionBumpType = 'patch' | 'minor' | 'major';
const promptBumpType = async () => {
return inquirer.prompt<{ type: VersionBumpType }>([
{
type: 'list',
message: 'Select version bump',
name: 'type',
choices: ['patch', 'minor', 'major'],
validate: answer => {
if (answer.length < 1) {
return 'You must choose something';
}
return true;
},
},
]);
};
const promptPrereleaseId = async () => {
return inquirer.prompt<{ id: string }>([
{
type: 'list',
message: 'Is this a prerelease?',
name: 'id',
choices: ['no', 'alpha', 'beta'],
validate: answer => {
if (answer.length < 1) {
return 'You must choose something';
}
return true;
},
},
]);
};
const promptConfirm = async (message?: string) => {
return inquirer.prompt<{ confirmed: boolean }>([
{
type: 'confirm',
message: message || 'Is that correct?',
name: 'confirmed',
default: false,
},
]);
};
const bumpVersion = async (version: string) => {
const spinner = startSpinner(`Saving version ${version} to package.json`);
changeCwdToGrafanaUi();
try {
await execa('npm', ['version', version]);
spinner.succeed();
} catch (e) {
console.log(e);
spinner.fail();
}
changeCwdToGrafanaUiDist();
const pkg = require(`${process.cwd()}/package.json`);
pkg.version = version;
await savePackage(`${process.cwd()}/package.json`, pkg);
};
const publishPackage = async (name: string, version: string) => {
changeCwdToGrafanaUiDist();
console.log(chalk.yellowBright.bold(`\nReview dist package.json before proceeding!\n`));
const { confirmed } = await promptConfirm('Are you ready to publish to npm?');
if (!confirmed) {
process.exit();
}
const spinner = startSpinner(`Publishing ${name} @ ${version} to npm registry...`);
try {
await execa('npm', ['publish', '--access', 'public']);
spinner.succeed();
} catch (e) {
console.log(e);
spinner.fail();
process.exit(1);
}
};
const releaseTask: Task<void> = async () => {
await execTask('grafanaui.build');
let releaseConfirmed = false;
let nextVersion;
changeCwdToGrafanaUiDist();
const pkg = require(`${process.cwd()}/package.json`);
console.log(`Current version: ${pkg.version}`);
do {
const { type } = await promptBumpType();
const { id } = await promptPrereleaseId();
if (id !== 'no') {
nextVersion = semver.inc(pkg.version, `pre${type}`, id);
} else {
nextVersion = semver.inc(pkg.version, type);
}
console.log(chalk.yellowBright.bold(`You are going to release a new version of ${pkg.name}`));
console.log(chalk.green(`Version bump: ${pkg.version} ->`), chalk.bold.yellowBright(`${nextVersion}`));
const { confirmed } = await promptConfirm();
releaseConfirmed = confirmed;
} while (!releaseConfirmed);
await bumpVersion(nextVersion);
await publishPackage(pkg.name, nextVersion);
console.log(chalk.green(`\nVersion ${nextVersion} of ${pkg.name} succesfully released!`));
console.log(chalk.yellow(`\nUpdated @grafana/ui/package.json with version bump created - COMMIT THIS FILE!`));
};
export default releaseTask;
const cwd = process.cwd();
export const changeCwdToGrafanaUi = () => {
process.chdir(`${cwd}/packages/grafana-ui`);
return process.cwd();
};
export const changeCwdToGrafanaUiDist = () => {
process.chdir(`${cwd}/packages/grafana-ui/dist`);
};
export const restoreCwd = () => {
process.chdir(cwd);
};
import { Task } from '..';
export const execTask = async <T>(taskName, options?: T) => {
const task = await import(`${__dirname}/../tasks/${taskName}.ts`);
return task.default(options) as Task<T>;
};
import ora from 'ora';
export const startSpinner = (label: string) => {
const spinner = new ora(label);
spinner.start();
return spinner;
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment