[CI] Build and publish storybooks (#87701) (#91917)

Co-authored-by: Brian Seeders <brian.seeders@elastic.co>
This commit is contained in:
Kibana Machine 2021-02-18 16:26:10 -05:00 committed by GitHub
parent 8537f25996
commit 854e833cf0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 171 additions and 9 deletions

28
.ci/.storybook/main.js Normal file
View file

@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
const config = require('@kbn/storybook').defaultConfig;
const aliases = require('../../src/dev/storybook/aliases.ts').storybookAliases;
config.refs = {};
for (const alias of Object.keys(aliases).filter((a) => a !== 'ci_composite')) {
// snake_case -> Title Case
const title = alias
.replace(/_/g, ' ')
.split(' ')
.map((n) => n[0].toUpperCase() + n.slice(1))
.join(' ');
config.refs[alias] = {
title: title,
url: `${process.env.STORYBOOK_BASE_URL}/${alias}`,
};
}
module.exports = config;

View file

@ -15,6 +15,7 @@ node_modules
target
snapshots.js
!/.ci
!/.eslintrc.js
!.storybook

View file

@ -14,4 +14,11 @@ export const defaultConfig: StorybookConfig = {
typescript: {
reactDocgen: false,
},
webpackFinal: (config, options) => {
if (process.env.CI) {
config.parallelism = 4;
config.cache = true;
}
return config;
},
};

View file

@ -16,12 +16,12 @@
<!-- Added for Kibana shared dependencies -->
<script>
window.__kbnPublicPath__ = { 'kbn-ui-shared-deps': '/' };
window.__kbnPublicPath__ = { 'kbn-ui-shared-deps': '.' };
</script>
<script src="/kbn-ui-shared-deps.@elastic.js"></script>
<script src="/kbn-ui-shared-deps.js"></script>
<link href="/kbn-ui-shared-deps.css" rel="stylesheet" />
<link href="/kbn-ui-shared-deps.v7.light.css" rel="stylesheet" />
<script src="kbn-ui-shared-deps.@elastic.js"></script>
<script src="kbn-ui-shared-deps.js"></script>
<link href="kbn-ui-shared-deps.css" rel="stylesheet" />
<link href="kbn-ui-shared-deps.v7.light.css" rel="stylesheet" />
<!-- -->
<% if (typeof headHtmlSnippet !== 'undefined') { %> <%= headHtmlSnippet %> <% } %> <%

View file

@ -6,10 +6,12 @@
* Side Public License, v 1.
*/
// Please also add new aliases to test/scripts/jenkins_storybook.sh
export const storybookAliases = {
apm: 'x-pack/plugins/apm/.storybook',
canvas: 'x-pack/plugins/canvas/storybook',
codeeditor: 'src/plugins/kibana_react/public/code_editor/.storybook',
ci_composite: '.ci/.storybook',
url_template_editor: 'src/plugins/kibana_react/public/url_template_editor/.storybook',
dashboard: 'src/plugins/dashboard/.storybook',
dashboard_enhanced: 'x-pack/plugins/dashboard_enhanced/.storybook',

View file

@ -0,0 +1,23 @@
#!/usr/bin/env bash
source src/dev/ci_setup/setup_env.sh
cd "$XPACK_DIR/plugins/canvas"
node scripts/storybook --dll
cd "$KIBANA_DIR"
# yarn storybook --site apm # TODO re-enable after being fixed
yarn storybook --site canvas
yarn storybook --site ci_composite
yarn storybook --site url_template_editor
yarn storybook --site codeeditor
yarn storybook --site dashboard
yarn storybook --site dashboard_enhanced
yarn storybook --site data_enhanced
yarn storybook --site embeddable
yarn storybook --site infra
yarn storybook --site security_solution
yarn storybook --site ui_actions_enhanced
yarn storybook --site observability
yarn storybook --site presentation

View file

@ -41,13 +41,15 @@ def trackBuild(commit, context, Closure closure) {
}
// state: error|failure|pending|success
def create(sha, state, description, context) {
def create(sha, state, description, context, targetUrl = null) {
targetUrl = targetUrl ?: env.BUILD_URL
withGithubCredentials {
return githubApi.post("repos/elastic/kibana/statuses/${sha}", [
state: state,
description: description,
context: context,
target_url: env.BUILD_URL
target_url: targetUrl.toString()
])
}
}

View file

@ -169,12 +169,18 @@ def getNextCommentMessage(previousCommentInfo = [:], isFinal = false) {
? getBuildStatusIncludingMetrics()
: buildUtils.getBuildStatus()
def storybooksUrl = buildState.get('storybooksUrl')
def storybooksMessage = storybooksUrl ? "* [Storybooks Preview](${storybooksUrl})" : "* Storybooks not built"
if (!isFinal) {
storybooksMessage = storybooksUrl ? storybooksMessage : "* Storybooks not built yet"
def failuresPart = status != 'SUCCESS' ? ', with failures' : ''
messages << """
## :hourglass_flowing_sand: Build in-progress${failuresPart}
* [continuous-integration/kibana-ci/pull-request](${env.BUILD_URL})
* Commit: ${getCommitHash()}
${storybooksMessage}
* This comment will update when the build is complete
"""
} else if (status == 'SUCCESS') {
@ -182,6 +188,7 @@ def getNextCommentMessage(previousCommentInfo = [:], isFinal = false) {
## :green_heart: Build Succeeded
* [continuous-integration/kibana-ci/pull-request](${env.BUILD_URL})
* Commit: ${getCommitHash()}
${storybooksMessage}
${getDocsChangesLink()}
"""
} else if(status == 'UNSTABLE') {
@ -189,6 +196,7 @@ def getNextCommentMessage(previousCommentInfo = [:], isFinal = false) {
## :yellow_heart: Build succeeded, but was flaky
* [continuous-integration/kibana-ci/pull-request](${env.BUILD_URL})
* Commit: ${getCommitHash()}
${storybooksMessage}
${getDocsChangesLink()}
""".stripIndent()
@ -204,6 +212,7 @@ def getNextCommentMessage(previousCommentInfo = [:], isFinal = false) {
## :broken_heart: Build Failed
* [continuous-integration/kibana-ci/pull-request](${env.BUILD_URL})
* Commit: ${getCommitHash()}
${storybooksMessage}
* [Pipeline Steps](${env.BUILD_URL}flowGraphTable) (look for red circles / failed steps)
* [Interpreting CI Failures](https://www.elastic.co/guide/en/kibana/current/interpreting-ci-failures.html)
${getDocsChangesLink()}

View file

@ -443,6 +443,7 @@ def allCiTasks() {
tasks.test()
tasks.functionalOss()
tasks.functionalXpack()
tasks.storybooksCi()
}
},
jest: {

83
vars/storybooks.groovy Normal file
View file

@ -0,0 +1,83 @@
def getStorybooksBucket() {
return "ci-artifacts.kibana.dev/storybooks"
}
def getDestinationDir() {
return env.ghprbPullId ? "pr-${env.ghprbPullId}" : buildState.get('checkoutInfo').branch.replace("/", "__")
}
def getUrl() {
return "https://${getStorybooksBucket()}/${getDestinationDir()}"
}
def getUrlLatest() {
return "${getUrl()}/latest"
}
def getUrlForCommit() {
return "${getUrl()}/${buildState.get('checkoutInfo').commit}"
}
def upload() {
dir("built_assets/storybook") {
sh "mv ci_composite composite"
def storybooks = sh(
script: 'ls -1d */',
returnStdout: true
).trim()
.split('\n')
.collect { it.replace('/', '') }
.findAll { it != 'composite' }
def listHtml = storybooks.collect { """<li><a href="${getUrlForCommit()}/${it}">${it}</a></li>""" }.join("\n")
def html = """
<html>
<body>
<h1>Storybooks</h1>
<p><a href="${getUrlForCommit()}/composite">Composite Storybook</a></p>
<h2>All</h2>
<ul>
${listHtml}
</ul>
</body>
</html>
"""
writeFile(file: 'index.html', text: html)
withGcpServiceAccount.fromVaultSecret('secret/kibana-issues/dev/ci-artifacts-key', 'value') {
kibanaPipeline.bash("""
gsutil -q -m cp -r -z js,css,html,json,map,txt,svg '*' 'gs://${getStorybooksBucket()}/${getDestinationDir()}/${buildState.get('checkoutInfo').commit}/'
gsutil -h "Cache-Control:no-cache, max-age=0, no-transform" cp -z html 'index.html' 'gs://${getStorybooksBucket()}/${getDestinationDir()}/latest/'
""", "Upload Storybooks to GCS")
}
buildState.set('storybooksUrl', getUrlForCommit())
}
}
def build() {
withEnv(["STORYBOOK_BASE_URL=${getUrlForCommit()}"]) {
kibanaPipeline.bash('test/scripts/jenkins_storybook.sh', 'Build Storybooks')
}
}
def buildAndUpload() {
def sha = buildState.get('checkoutInfo').commit
def context = 'Build and Publish Storybooks'
githubCommitStatus.create(sha, 'pending', 'Building Storybooks', context)
try {
build()
upload()
githubCommitStatus.create(sha, 'success', 'Storybooks built', context, getUrlForCommit())
} catch(ex) {
githubCommitStatus.create(sha, 'error', 'Building Storybooks failed', context)
throw ex
}
}
return this

View file

@ -124,4 +124,10 @@ def functionalXpack(Map params = [:]) {
}
}
def storybooksCi() {
task {
storybooks.buildAndUpload()
}
}
return this

View file

@ -2,5 +2,5 @@
This file is looked for by Storybook and included in the HEAD element
if it exists. This is how we load the DLL content into the Storybook UI.
-->
<script src="/dll.js"></script>
<link href="/dll.css" rel="stylesheet" />
<script src="dll.js"></script>
<link href="dll.css" rel="stylesheet" />