This repository has been archived by the owner on Nov 26, 2024. It is now read-only.
generated from MetaMask/metamask-module-template
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding circle ci and storybook builds to each PR
- Loading branch information
1 parent
0246771
commit a0ce79e
Showing
8 changed files
with
638 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
version: 2.1 | ||
|
||
executors: | ||
node-browsers: | ||
docker: | ||
- image: circleci/node:14-browsers | ||
|
||
workflows: | ||
storybook: | ||
jobs: | ||
- prep-deps | ||
- prep-build-storybook: | ||
requires: | ||
- prep-deps | ||
- job-announce-storybook: | ||
requires: | ||
- prep-build-storybook | ||
- job-publish-storybook: | ||
filters: | ||
branches: | ||
only: main | ||
requires: | ||
- prep-build-storybook | ||
|
||
jobs: | ||
prep-deps: | ||
executor: node-browsers | ||
steps: | ||
- checkout | ||
- restore_cache: | ||
key: dependency-cache-v1-{{ checksum "yarn.lock" }} | ||
- run: | ||
name: Install deps | ||
command: | | ||
yarn install | ||
- save_cache: | ||
key: dependency-cache-v1-{{ checksum "yarn.lock" }} | ||
paths: | ||
- node_modules/ | ||
- run: | ||
name: Postinstall | ||
command: | | ||
yarn setup | ||
- persist_to_workspace: | ||
root: . | ||
paths: | ||
- node_modules | ||
|
||
prep-build-storybook: | ||
executor: node-browsers | ||
steps: | ||
- checkout | ||
- attach_workspace: | ||
at: . | ||
- run: | ||
name: build:storybook | ||
command: yarn build-storybook | ||
- persist_to_workspace: | ||
root: . | ||
paths: | ||
- storybook-static | ||
|
||
job-announce-storybook: | ||
executor: node-browsers | ||
steps: | ||
- checkout | ||
- attach_workspace: | ||
at: . | ||
- store_artifacts: | ||
path: storybook-static | ||
destination: storybook | ||
- run: | ||
name: build:announce | ||
command: ./.circleci/scripts/metamaskbot-build-announce.js | ||
|
||
job-publish-storybook: | ||
executor: node-browsers | ||
steps: | ||
- add_ssh_keys: | ||
fingerprints: | ||
- '3d:49:29:f4:b2:e8:ea:af:d1:32:eb:2a:fc:15:85:d8' | ||
- checkout | ||
- attach_workspace: | ||
at: . | ||
- run: | ||
name: storybook:deploy | ||
command: | | ||
git remote add storybook [email protected]:MetaMask/metamask-storybook.git | ||
yarn storybook:deploy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
### highlights | ||
|
||
the purpose of this directory is to house utilities for generating "highlight" messages for the metamaskbot comment based on changes included in the PR |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
const { promisify } = require('util'); | ||
const exec = promisify(require('child_process').exec); | ||
const storybook = require('./storybook.js'); | ||
|
||
module.exports = { getHighlights }; | ||
|
||
async function getHighlights({ artifactBase }) { | ||
let highlights = ''; | ||
// here we assume the PR base branch ("target") is `develop` in lieu of doing | ||
// a query against the github api which requires an access token | ||
// see https://discuss.circleci.com/t/how-to-retrieve-a-pull-requests-base-branch-name-github/36911 | ||
const changedFiles = await getChangedFiles({ target: 'develop' }); | ||
console.log(`detected changed files vs develop:`); | ||
for (const filename of changedFiles) { | ||
console.log(` ${filename}`); | ||
} | ||
const announcement = await storybook.getHighlightAnnouncement({ | ||
changedFiles, | ||
artifactBase, | ||
}); | ||
if (announcement) { | ||
highlights += announcement; | ||
} | ||
return highlights; | ||
} | ||
|
||
async function getChangedFiles({ target }) { | ||
const { stdout } = await exec(`git diff --name-only ${target}...HEAD`); | ||
const changedFiles = stdout.split('\n').slice(0, -1); | ||
return changedFiles; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
const path = require('path'); | ||
const { promisify } = require('util'); | ||
const exec = promisify(require('child_process').exec); | ||
const dependencyTree = require('dependency-tree'); | ||
|
||
const cwd = process.cwd(); | ||
const resolutionCache = {}; | ||
|
||
// 1. load stories | ||
// 2. load list per story | ||
// 3. filter against files | ||
module.exports = { | ||
getHighlights, | ||
getHighlightAnnouncement, | ||
}; | ||
|
||
async function getHighlightAnnouncement({ changedFiles, artifactBase }) { | ||
const highlights = await getHighlights({ changedFiles }); | ||
if (!highlights.length) { | ||
return null; | ||
} | ||
const highlightsBody = highlights | ||
.map((entry) => `\n- [${entry}](${urlForStoryFile(entry, artifactBase)})`) | ||
.join(''); | ||
const announcement = `<details> | ||
<summary>storybook</summary> | ||
${highlightsBody} | ||
</details>\n\n`; | ||
return announcement; | ||
} | ||
|
||
async function getHighlights({ changedFiles }) { | ||
const highlights = []; | ||
const storyFiles = await getAllStories(); | ||
// check each story file for dep graph overlap with changed files | ||
for (const storyFile of storyFiles) { | ||
const list = await getLocalDependencyList(storyFile); | ||
if (list.some((entry) => changedFiles.includes(entry))) { | ||
highlights.push(storyFile); | ||
} | ||
} | ||
return highlights; | ||
} | ||
|
||
async function getAllStories() { | ||
const { stdout } = await exec('find ui -name "*.stories.js"'); | ||
const matches = stdout.split('\n').slice(0, -1); | ||
return matches; | ||
} | ||
|
||
async function getLocalDependencyList(filename) { | ||
const list = dependencyTree | ||
.toList({ | ||
filename, | ||
// not sure what this does but its mandatory | ||
directory: cwd, | ||
webpackConfig: `.storybook/main.js`, | ||
// skip all dependencies | ||
filter: (entry) => !entry.includes('node_modules'), | ||
// for memoization across trees: 30s -> 5s | ||
visited: resolutionCache, | ||
}) | ||
.map((entry) => path.relative(cwd, entry)); | ||
return list; | ||
} | ||
|
||
function urlForStoryFile(filename, artifactBase) { | ||
const storyId = sanitize(filename); | ||
return `${artifactBase}/storybook/index.html?path=/story/${storyId}`; | ||
} | ||
|
||
/** | ||
* Remove punctuation and illegal characters from a story ID. | ||
* See: | ||
* https://gist.github.com/davidjrice/9d2af51100e41c6c4b4a | ||
* https://github.com/ComponentDriven/csf/blame/7ac941eee85816a4c567ca85460731acb5360f50/src/index.ts | ||
* | ||
* @param {string} string - The string to sanitize. | ||
* @returns The sanitized string. | ||
*/ | ||
function sanitize(string) { | ||
return ( | ||
string | ||
.toLowerCase() | ||
// eslint-disable-next-line no-useless-escape | ||
.replace(/[ ’–—―′¿'`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/giu, '-') | ||
.replace(/-+/gu, '-') | ||
.replace(/^-+/u, '') | ||
.replace(/-+$/u, '') | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#!/usr/bin/env node | ||
const { promises: fs } = require('fs'); | ||
const path = require('path'); | ||
const fetch = require('node-fetch'); | ||
const { getHighlights } = require('./highlights'); | ||
|
||
start().catch(console.error); | ||
|
||
async function start() { | ||
const { GITHUB_COMMENT_TOKEN, CIRCLE_PULL_REQUEST } = process.env; | ||
console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST); | ||
const { CIRCLE_SHA1 } = process.env; | ||
console.log('CIRCLE_SHA1', CIRCLE_SHA1); | ||
const { CIRCLE_BUILD_NUM } = process.env; | ||
console.log('CIRCLE_BUILD_NUM', CIRCLE_BUILD_NUM); | ||
const { CIRCLE_WORKFLOW_JOB_ID } = process.env; | ||
console.log('CIRCLE_WORKFLOW_JOB_ID', CIRCLE_WORKFLOW_JOB_ID); | ||
|
||
if (!CIRCLE_PULL_REQUEST) { | ||
console.warn(`No pull request detected for commit "${CIRCLE_SHA1}"`); | ||
return; | ||
} | ||
|
||
const CIRCLE_PR_NUMBER = CIRCLE_PULL_REQUEST.split('/').pop(); | ||
const SHORT_SHA1 = CIRCLE_SHA1.slice(0, 7); | ||
const BUILD_LINK_BASE = `https://output.circle-artifacts.com/output/job/${CIRCLE_WORKFLOW_JOB_ID}/artifacts/0`; | ||
|
||
const storybookUrl = `${BUILD_LINK_BASE}/storybook/index.html`; | ||
const storybookLink = `<a href="${storybookUrl}">Storybook</a>`; | ||
|
||
// link to artifacts | ||
const allArtifactsUrl = `https://circleci.com/gh/MetaMask/metamask-extension/${CIRCLE_BUILD_NUM}#artifacts/containers/0`; | ||
|
||
const contentRows = [ | ||
`storybook: ${storybookLink}`, | ||
`<a href="${allArtifactsUrl}">all artifacts</a>`, | ||
]; | ||
const hiddenContent = `<ul>${contentRows | ||
.map((row) => `<li>${row}</li>`) | ||
.join('\n')}</ul>`; | ||
const exposedContent = `Builds ready [${SHORT_SHA1}]`; | ||
const artifactsBody = `<details><summary>${exposedContent}</summary>${hiddenContent}</details>\n\n`; | ||
|
||
try { | ||
const highlights = await getHighlights({ artifactBase: BUILD_LINK_BASE }); | ||
if (highlights) { | ||
const highlightsBody = `### highlights:\n${highlights}\n`; | ||
commentBody += highlightsBody; | ||
} | ||
} catch (error) { | ||
console.error(`Error constructing highlight results: '${error}'`); | ||
} | ||
|
||
const JSON_PAYLOAD = JSON.stringify({ body: commentBody }); | ||
const POST_COMMENT_URI = `https://api.github.com/repos/metamask/design-tokens/issues/${CIRCLE_PR_NUMBER}/comments`; | ||
console.log(`Announcement:\n${commentBody}`); | ||
console.log(`Posting to: ${POST_COMMENT_URI}`); | ||
|
||
const response = await fetch(POST_COMMENT_URI, { | ||
method: 'POST', | ||
body: JSON_PAYLOAD, | ||
headers: { | ||
'User-Agent': 'metamaskbot', | ||
Authorization: `token ${GITHUB_COMMENT_TOKEN}`, | ||
}, | ||
}); | ||
if (!response.ok) { | ||
throw new Error(`Post comment failed with status '${response.statusText}'`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,3 +72,6 @@ node_modules/ | |
.yarn/build-state.yml | ||
.yarn/install-state.gz | ||
.pnp.* | ||
|
||
# Storybook build folder | ||
storybook-static |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.