Skip to content

Commit

Permalink
build: Add changelog to storybook. Fix link issues. (#47)
Browse files Browse the repository at this point in the history
* Update lerna.

* Fix storybook links.

* Add changelog.

* Add rimraf for cleaning.
  • Loading branch information
milesj authored Apr 26, 2019
1 parent 4a09ab9 commit 5af9e54
Show file tree
Hide file tree
Showing 12 changed files with 283 additions and 115 deletions.
35 changes: 33 additions & 2 deletions .storybook/addons/props/About.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,37 @@ import getImportPath from './getImportPath';
import getSourcePath from './getSourcePath';
import PathBar from './PathBar';
import PropTable from './PropTable';
import LogTable from './LogTable';

const Wrapper = styled.div({
padding: 16,
fontSize: 14,
});

const Header = styled.h2({
marginBottom: 16,
marginTop: 24,
});

const SubHeader = styled.h4(({ theme }) => ({
float: 'right',
color: theme.color.mediumdark,
margin: 0,
marginTop: 16,
}));

const Description = styled.div({
marginBottom: 16,
});

export default class About extends React.Component {
static defaultProps = {
changelog: [],
metadata: {},
};

render() {
const { name, metadata, storyPath } = this.props;
const { changelog, name, metadata, storyPath } = this.props;

if (!metadata) {
return <Placeholder>No component information found for {name}.</Placeholder>;
Expand Down Expand Up @@ -57,7 +75,20 @@ export default class About extends React.Component {
</Description>
)}

{props.length > 0 && <PropTable props={props} />}
{changelog.length > 0 && (
<>
<SubHeader>Past 1 month</SubHeader>
<Header>Changelog</Header>
<LogTable logs={changelog} />
</>
)}

{props.length > 0 && (
<>
<Header>Props</Header>
<PropTable props={props} />
</>
)}
</Wrapper>
);
}
Expand Down
65 changes: 65 additions & 0 deletions .storybook/addons/props/LogTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from 'react';
import { Link } from '@storybook/components';
import Table from './Table';

function TypeLabel({ type }) {
const labels = {
break: '💥 Breaking',
release: '🎉 Release',
new: '🚀 New',
update: '🚀 Update',
feature: '🚀 Feature',
fix: '🐞 Fix',
deps: '📘 Docs',
docs: '🎉 Release',
style: '🎨 Styles',
security: '🔑 Security',
revert: '⚙️ Reverts',
ci: '🛠 Internals (CI)',
build: '🛠 Internals (Build)',
test: '🛠 Internals (Test)',
internal: '🛠 Internals',
};

if (labels[type]) {
return <span>{labels[type]}</span>;
}

return <span>📋 Misc</span>;
}

export default function LogTable({ logs }) {
return (
<Table>
<thead>
<tr>
<th>Commit</th>
<th>Type</th>
<th>Date</th>
<th>Hash</th>
</tr>
</thead>
<tbody>
{logs.map((log, i) => (
<tr key={i}>
<td>{log.message}</td>
<td>
<TypeLabel type={log.type} />
</td>
<td>{new Date(log.date * 1000).toDateString()}</td>
<td>
<Link
cancel
onClick={() => {
window.open(`https://github.com/airbnb/lunar/commit/${log.hash}`);
}}
>
{log.hash}
</Link>
</td>
</tr>
))}
</tbody>
</Table>
);
}
11 changes: 9 additions & 2 deletions .storybook/addons/props/Panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ import Tabs from '@storybook/addon-a11y/dist/components/Tabs';
import About from './About';

export default class Panel extends React.Component {
static defaultProps = {
active: false,
};

state = {
components: {},
componentChangelogs: {},
componentMetadata: {},
section: '',
storyPath: '',
Expand All @@ -19,16 +24,17 @@ export default class Panel extends React.Component {
this.props.channel.removeListener('SET_PROPS_DATA', this.handleSetData);
}

handleSetData = ({ componentMetadata, ...data }) => {
handleSetData = ({ componentChangelogs, componentMetadata, ...data }) => {
this.setState({
componentChangelogs: JSON.parse(componentChangelogs),
componentMetadata: JSON.parse(componentMetadata),
...data,
});
};

render() {
const { active } = this.props;
const { components, componentMetadata, section, storyPath } = this.state;
const { components, componentChangelogs, componentMetadata, section, storyPath } = this.state;

if (!active) {
return null;
Expand All @@ -45,6 +51,7 @@ export default class Panel extends React.Component {
name={name}
component={component}
storyPath={storyPath}
changelog={componentChangelogs[name]}
metadata={Object.values(componentMetadata).find(
meta => meta.name === name && meta.path.includes(section),
)}
Expand Down
4 changes: 2 additions & 2 deletions .storybook/addons/props/PathBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ export default function PathBar({ sourcePath, storyPath, importPath }) {
return (
<Wrapper>
<RightAlign>
<Button href={sourcePath} isLink secondary small>
<Button href={sourcePath} target="_blank" isLink secondary small>
View source
</Button>

<Button href={storyPath} isLink secondary small>
<Button href={storyPath} target="_blank" isLink secondary small>
View story
</Button>
</RightAlign>
Expand Down
22 changes: 1 addition & 21 deletions .storybook/addons/props/PropTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import Markdown from 'markdown-to-jsx';
import { styled } from '@storybook/theming';
import getTypeName from './getTypeName';
import Table from './Table';

const Type = styled.span(({ theme }) => ({
color: theme.color.secondary,
Expand All @@ -15,27 +16,6 @@ const Required = styled.span(({ theme }) => ({
color: theme.color.negative,
}));

const Table = styled.table(({ theme }) => ({
width: '100%',
maxWidth: '100%',
margin: 0,
padding: 0,
border: `1px solid ${theme.appBorderColor}`,
borderCollapse: 'collapse',
borderSpacing: 0,
borderRadius: theme.appBorderRadius,

'& th': {
textAlign: 'left',
backgroundColor: theme.barBg,
},

'& td, & th': {
border: `1px solid ${theme.appBorderColor}`,
padding: 8,
},
}));

function Row({ prop }) {
return (
<tr>
Expand Down
22 changes: 22 additions & 0 deletions .storybook/addons/props/Table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { styled } from '@storybook/theming';

export default styled.table(({ theme }) => ({
width: '100%',
maxWidth: '100%',
margin: 0,
padding: 0,
border: `1px solid ${theme.appBorderColor}`,
borderCollapse: 'collapse',
borderSpacing: 0,
borderRadius: theme.appBorderRadius,

'& th': {
textAlign: 'left',
backgroundColor: theme.barBg,
},

'& td, & th': {
border: `1px solid ${theme.appBorderColor}`,
padding: 8,
},
}));
6 changes: 3 additions & 3 deletions .storybook/addons/props/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ export const withProps = makeDecorator({
components[stripHOCs(component.displayName || component.name)] = component;
});

// We need to cast globals to JSON, otherwise the data is lost
addons.getChannel().emit('SET_PROPS_DATA', {
components,
// If we dont cast to JSON, a ton of data is lost by being set to undefined.
// I have no idea why this happens, but JSON persists it.
componentMetadata: JSON.stringify(global.STORYBOOK_REACT_CLASSES),
componentChangelogs: JSON.stringify(COMPONENT_CHANGELOGS),
componentMetadata: JSON.stringify(STORYBOOK_REACT_CLASSES),
section: kebabCase(context.kind.split('/')[0]),
storyPath: context.parameters.fileName,
});
Expand Down
52 changes: 52 additions & 0 deletions .storybook/helpers/getChangelogFromGitHistory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const execa = require('execa');
const checkCommitFormat = require('conventional-changelog-beemo/lib/checkCommitFormat').default;

module.exports = function getChangelogFromGitHistory() {
const format = {
subject: '%s',
hash: '%h',
date: '%ct',
};
const history = execa.sync('git', [
'log',
`--pretty=format:${JSON.stringify(format)},`,
'--since=1.month',
]).stdout;
const components = {};

JSON.parse(`[${history.slice(0, -1)}]`).forEach(row => {
const { subject, hash, date } = row;

if (!subject || subject.includes('[ci skip]')) {
return;
}

const commit = checkCommitFormat(subject);

if (!commit || !commit.scope) {
return;
}

const message = subject
.replace(`${commit.type}(${commit.scope}):`, '')
.replace(/(\(#\d+\))/, '')
.trim();

commit.scope.split(',').forEach(scope => {
const name = scope.trim();

if (!components[name]) {
components[name] = [];
}

components[name].push({
date,
hash,
message,
type: commit.type,
});
});
});

return components;
};
12 changes: 12 additions & 0 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const path = require('path');
const glob = require('fast-glob');
const webpack = require('webpack');
const getChangelogFromGitHistory = require('./helpers/getChangelogFromGitHistory');
const tsConfig = require('../tsconfig.options.json');

module.exports = async ({ config }) => {
Expand Down Expand Up @@ -36,6 +38,16 @@ module.exports = async ({ config }) => {
// Add custom Webpack aliases
config.resolve.alias[':storybook'] = __dirname;

// Use named modules so we have accurate file paths
config.optimization.moduleIds = 'named';

// Extract our git history for changelog purposes
config.plugins.push(
new webpack.DefinePlugin({
COMPONENT_CHANGELOGS: JSON.stringify(getChangelogFromGitHistory()),
}),
);

// Use source files so we don't have duplicate and or stale components
glob.sync(path.join(__dirname, '../packages/*/package.json')).forEach(filePath => {
const { name } = require(filePath);
Expand Down
Loading

0 comments on commit 5af9e54

Please sign in to comment.