Skip to content
This repository was archived by the owner on Jul 7, 2025. It is now read-only.

Commit f22d3b1

Browse files
Expose dotcom shared components (#557)
* Expose dotcom shared components * Update content/github-staff/github-shared-components.mdx Co-authored-by: Emily Brick <[email protected]> * Change format of shared_components.json * Renaming * Fix link styles; rearrange shared components page * Stop using outdated shared deploy config * Add ListView component to fallback recipe file * Pull data from github master branch * Remove unnecessary console.log; remove unused ToC item * D'oh, fix other ToC link * Stop grouping shared components alphabetically --------- Co-authored-by: Emily Brick <[email protected]>
1 parent ef0b103 commit f22d3b1

File tree

11 files changed

+717
-74541
lines changed

11 files changed

+717
-74541
lines changed

.github/workflows/deploy.yml

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
# Manual deploy
55
workflow_dispatch:
66
# Scheduled deploy
7-
schedule:
7+
schedule:
88
- cron: '0 0 * * *' # Every day at midnight UTC time
99
# Deploy on change to main
1010
push:
@@ -17,13 +17,65 @@ permissions:
1717
id-token: write
1818

1919
jobs:
20-
build_deploy:
20+
build:
21+
name: Build
22+
runs-on: ubuntu-latest
23+
steps:
24+
- id: get-dotcom-access-token
25+
uses: camertron/github-app-installation-auth-action@v1
26+
with:
27+
app-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_ID }}
28+
private-key: ${{ secrets.DOTCOM_SHARED_COMPONENTS_APP_PRIVATE_KEY }}
29+
client-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_CLIENT_ID }}
30+
client-secret: ${{ secrets.DOTCOM_SHARED_COMPONENTS_APP_CLIENT_SECRET }}
31+
installation-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_INSTALLATION_ID }}
32+
33+
- name: Checkout default branch
34+
uses: actions/checkout@v2
35+
with:
36+
version: 16
37+
38+
- name: Set up Node
39+
uses: actions/setup-node@v2
40+
with:
41+
node-version: 16
42+
43+
- name: Cache dependencies
44+
uses: actions/cache@v2
45+
with:
46+
path: ~/.npm
47+
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
48+
restore-keys: |
49+
${{ runner.os }}-node-
50+
51+
- name: Install dependencies
52+
run: yarn
53+
54+
- name: Build
55+
run: yarn build
56+
env:
57+
GITHUB_TOKEN: ${{ steps.get-dotcom-access-token.outputs.access-token }}
58+
59+
- name: Archive build output
60+
run: "tar --dereference --directory public -cvf artifact.tar ."
61+
62+
- name: Upload artifact
63+
uses: actions/upload-artifact@main
64+
with:
65+
name: github-pages
66+
path: artifact.tar
67+
68+
deploy:
2169
if: ${{ github.repository == 'primer/design' }}
22-
name: Production
23-
# SHA for security hardening. Points at last verified HEAD of main branch.
24-
uses: primer/.github/.github/workflows/deploy.yml@0cec9b9914f358846163f2428663b58da41028c9
25-
with:
26-
node_version: 16
27-
install: yarn
28-
build: yarn build
29-
output_dir: public
70+
name: Deploy
71+
runs-on: ubuntu-latest
72+
needs: build
73+
environment:
74+
name: github-pages
75+
url: ${{ steps.deployment.outputs.page_url }}
76+
steps:
77+
- name: Deploy to GitHub Pages
78+
id: deployment
79+
uses: actions/deploy-pages@v1
80+
with:
81+
preview: false

.github/workflows/deploy_preview.yml

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,71 @@ permissions:
99
id-token: write
1010

1111
jobs:
12+
build:
13+
name: Build
14+
runs-on: ubuntu-latest
15+
steps:
16+
- id: get-dotcom-access-token
17+
uses: camertron/github-app-installation-auth-action@v1
18+
with:
19+
app-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_ID }}
20+
private-key: ${{ secrets.DOTCOM_SHARED_COMPONENTS_APP_PRIVATE_KEY }}
21+
client-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_CLIENT_ID }}
22+
client-secret: ${{ secrets.DOTCOM_SHARED_COMPONENTS_APP_CLIENT_SECRET }}
23+
installation-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_INSTALLATION_ID }}
24+
25+
- name: Checkout default branch
26+
uses: actions/checkout@v2
27+
with:
28+
version: 16
29+
30+
- name: Set up Node
31+
uses: actions/setup-node@v2
32+
with:
33+
node-version: 16
34+
35+
- name: Cache dependencies
36+
uses: actions/cache@v2
37+
with:
38+
path: ~/.npm
39+
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
40+
restore-keys: |
41+
${{ runner.os }}-node-
42+
43+
- name: Install dependencies
44+
run: yarn
45+
46+
- name: Build
47+
run: yarn build:preview
48+
env:
49+
GITHUB_TOKEN: ${{ steps.get-dotcom-access-token.outputs.access-token }}
50+
51+
- name: Archive build output
52+
run: "tar --dereference --directory public -cvf artifact.tar ."
53+
54+
- name: Upload artifact
55+
uses: actions/upload-artifact@main
56+
with:
57+
name: github-pages
58+
path: artifact.tar
59+
1260
deploy-preview:
13-
if: ${{ github.event.pull_request.head.repo.full_name == 'primer/design' }}
61+
if: ${{ github.repository == 'primer/design' }}
1462
name: Preview
15-
# SHA for security hardening. Points at last verified HEAD of main branch.
16-
uses: primer/.github/.github/workflows/deploy_preview.yml@0cec9b9914f358846163f2428663b58da41028c9
17-
secrets:
18-
gh_token: ${{ secrets.GITHUB_TOKEN }}
19-
with:
20-
node_version: 16
21-
install: yarn
22-
build: yarn build:preview
23-
output_dir: public
63+
runs-on: ubuntu-latest
64+
needs: build
65+
environment:
66+
name: github-pages
67+
url: ${{ steps.deployment.outputs.page_url }}
68+
permissions:
69+
contents: read
70+
pages: write
71+
id-token: write
72+
outputs:
73+
deployment_url: ${{ steps.deployment.outputs.page_url }}
74+
steps:
75+
- name: Deploy to GitHub Pages
76+
id: deployment
77+
uses: actions/deploy-pages@v1
78+
with:
79+
preview: true

content/github-staff/github-shared-components.mdx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,24 @@ title: GitHub shared components
33
description: Application-specific components that are shared by GitHub feature teams but are not in Primer.
44
---
55

6+
import DotcomSharedComponentsLayout from '~/src/layouts/dotcom-shared-components-layout'
7+
export default DotcomSharedComponentsLayout
8+
69
<Note>This information is only relevant to GitHub staff.</Note>
710

8-
These components are shared design patterns by GitHub feature teams developing application-specific components. We encourage relying only on Primer components where possible, and not all patterns will be upstreamed to Primer.
11+
These components are shared design patterns by GitHub feature teams developing application-specific components. We encourage relying only on Primer components where possible, and not all patterns will be upstreamed to Primer.
912

1013
They're shared with other teams by developing them as React components within the `ui/packages/` monorepo. This monorepo, along with the larger monolith, provides a solid foundation with baseline configurations for linting, accessibility scanning using Axe, and Storybook previews.
1114

1215
Engineers building UI components should refer to the guidance on The Hub: [Building reusable UI Components](https://thehub.github.com/epd/engineering/dev-practicals/frontend/common-components/) (only available to GitHub staff).
1316

14-
## Finding these components
15-
16-
GitHub shared components are documented in a private Storybook instance: [ui/packages/ Storybook](https://gh.io/storybook) (only available to GitHub staff).
17-
18-
Please note that these components are **owned by the feature teams**, and will not exist in our Figma component library, [Primer Web](https://www.figma.com/file/GCvY3Qv8czRgZgvl1dG6lp/Primer-Web?type=design&node-id=1406%3A0&mode=design&t=Qi8hXoRhKLLrDhgf-1), unless they have been upstreamed into Primer.
19-
2017
## Related reading
2118

2219
- [Handling new patterns](/guides/contribute/handling-new-patterns)
2320
- [Upstreaming to Primer](/guides/contribute/adding-new-components#upstreaming-to-primer)
21+
22+
## Shared components
23+
24+
GitHub shared components are documented in a private Storybook instance: [ui/packages/ Storybook](https://gh.io/storybook) (only available to GitHub staff).
25+
26+
Please note that these components are **owned by the feature teams**, and will not exist in our Figma component library, [Primer Web](https://www.figma.com/file/GCvY3Qv8czRgZgvl1dG6lp/Primer-Web?type=design&node-id=1406%3A0&mode=design&t=Qi8hXoRhKLLrDhgf-1), unless they have been upstreamed into Primer.

gatsby-node.esm.js

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import * as path from 'path'
22
import * as fs from 'fs'
33
import * as defines from './babel-defines'
44
import fetch from 'node-fetch'
5+
import GithubSlugger from 'github-slugger'
56
import { latestStatusFrom } from './src/rails-status'
7+
import { Octokit } from '@octokit/rest'
8+
import JSZip from 'jszip'
69

710
exports.onCreateWebpackConfig = ({actions, plugins, getConfig}) => {
811
const config = getConfig()
@@ -32,6 +35,141 @@ exports.sourceNodes = async ({actions, createNodeId, createContentDigest}) => {
3235
await sourcePrimerRailsData({actions, createNodeId, createContentDigest})
3336
await sourceOcticonData({actions, createNodeId, createContentDigest})
3437
await sourceFigmaData({actions, createNodeId, createContentDigest})
38+
await sourceDotcomSharedComponentsData({actions, createNodeId, createContentDigest})
39+
}
40+
41+
exports.createSchemaCustomization = ({ actions }) => {
42+
const { createTypes } = actions
43+
const typeDefs = `
44+
type SharedComponent implements Node {
45+
component: String!
46+
storyIds: [String!]
47+
status: String!
48+
path: String!
49+
}
50+
`
51+
createTypes(typeDefs)
52+
}
53+
54+
async function sourceDotcomSharedComponentsData({actions, createNodeId, createContentDigest}) {
55+
const sharedComponents = await getSharedComponentsData()
56+
const slugger = new GithubSlugger()
57+
58+
for (const sharedComponent of sharedComponents) {
59+
const {component: name} = sharedComponent
60+
61+
const newNode = {
62+
component: sharedComponent.component,
63+
storyIds: sharedComponent.storyIds,
64+
status: sharedComponent.meta.status,
65+
path: sharedComponent.meta.path,
66+
id: createNodeId(`dotcom-shared-${name}`),
67+
internal: {
68+
type: 'SharedComponent',
69+
contentDigest: createContentDigest(sharedComponent),
70+
},
71+
}
72+
73+
actions.createNode(newNode)
74+
75+
const sharedComponentsPath = '/github-staff/github-shared-components'
76+
const componentPath = `${sharedComponentsPath}/${slugger.slug(name)}`
77+
78+
actions.createRedirect({
79+
fromPath: componentPath,
80+
toPath: `${sharedComponentsPath}#${name[0].toLowerCase()}`,
81+
redirectInBrowser: true,
82+
force: true
83+
})
84+
85+
const searchDoc = {
86+
title: name,
87+
path: componentPath,
88+
rawBody: name
89+
}
90+
91+
const searchNode = {
92+
...searchDoc,
93+
id: createNodeId(`shared-component-search-doc-${name}`),
94+
internal: {
95+
type: 'CustomSearchDoc',
96+
contentDigest: createContentDigest(searchDoc)
97+
}
98+
}
99+
100+
actions.createNode(searchNode)
101+
}
102+
}
103+
104+
async function getSharedComponentsData() {
105+
if (!process.env.GITHUB_TOKEN) {
106+
console.log('No GITHUB_TOKEN in environment, falling back to using recipe_metadata.json')
107+
return JSON.parse(fs.readFileSync('recipe_metadata.json', 'utf8'))
108+
}
109+
110+
const client = new Octokit({
111+
auth: process.env.GITHUB_TOKEN
112+
})
113+
114+
console.log('Listing dotcom workflow runs...')
115+
116+
const workflowRuns = await client.rest.actions.listWorkflowRuns({
117+
owner: 'github',
118+
repo: 'github',
119+
workflow_id: 'preview-pages-build.yml',
120+
branch: 'master',
121+
status: 'success',
122+
per_page: 1
123+
})
124+
125+
if (workflowRuns.data.workflow_runs.length == 0) {
126+
console.log('No workflow runs found 🤔')
127+
return
128+
}
129+
130+
const workflowRunId = workflowRuns.data.workflow_runs[0].id
131+
console.log(`Workflow run ${workflowRunId} found`)
132+
133+
console.log('Listing workflow run artifacts...')
134+
const artifacts = await client.rest.actions.listWorkflowRunArtifacts({
135+
owner: 'github',
136+
repo: 'github',
137+
run_id: workflowRunId
138+
})
139+
140+
const artifactId = (() => {
141+
for (const artifact of artifacts.data.artifacts) {
142+
if (artifact.name == 'recipe-metadata') {
143+
return artifact.id
144+
}
145+
}
146+
147+
return null
148+
})()
149+
150+
if (artifactId) {
151+
console.log(`Found artifact ${artifactId}`)
152+
} else {
153+
console.log('No artifacts found for workflow run 🤯')
154+
return
155+
}
156+
157+
console.log('Downloading artifact...')
158+
const artifactContents = await client.rest.actions.downloadArtifact({
159+
owner: 'github',
160+
repo: 'github',
161+
artifact_id: artifactId,
162+
archive_format: 'zip'
163+
})
164+
165+
console.log('Extracting artifact...')
166+
167+
const zip = new JSZip();
168+
const zipData = await zip.loadAsync(artifactContents.data)
169+
const manifestRaw = await zipData.file('recipe_metadata.json').async('string')
170+
const manifest = JSON.parse(manifestRaw)
171+
172+
return manifest
35173
}
36174

37175
async function sourcePrimerRailsData({actions, createNodeId, createContentDigest}) {

0 commit comments

Comments
 (0)