Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose dotcom shared components #557

Merged
merged 12 commits into from
Sep 1, 2023
72 changes: 62 additions & 10 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
# Manual deploy
workflow_dispatch:
# Scheduled deploy
schedule:
schedule:
- cron: '0 0 * * *' # Every day at midnight UTC time
# Deploy on change to main
push:
Expand All @@ -17,13 +17,65 @@ permissions:
id-token: write

jobs:
build_deploy:
build:
name: Build
runs-on: ubuntu-latest
steps:
- id: get-dotcom-access-token
uses: camertron/github-app-installation-auth-action@v1
with:
app-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_ID }}
private-key: ${{ secrets.DOTCOM_SHARED_COMPONENTS_APP_PRIVATE_KEY }}
client-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_CLIENT_ID }}
client-secret: ${{ secrets.DOTCOM_SHARED_COMPONENTS_APP_CLIENT_SECRET }}
installation-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_INSTALLATION_ID }}

- name: Checkout default branch
uses: actions/checkout@v2
with:
version: 16

- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: 16

- name: Cache dependencies
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

- name: Install dependencies
run: yarn

- name: Build
run: yarn build
env:
GITHUB_TOKEN: ${{ steps.get-dotcom-access-token.outputs.access-token }}

- name: Archive build output
run: "tar --dereference --directory public -cvf artifact.tar ."

- name: Upload artifact
uses: actions/upload-artifact@main
with:
name: github-pages
path: artifact.tar

deploy:
if: ${{ github.repository == 'primer/design' }}
name: Production
# SHA for security hardening. Points at last verified HEAD of main branch.
uses: primer/.github/.github/workflows/deploy.yml@0cec9b9914f358846163f2428663b58da41028c9
with:
node_version: 16
install: yarn
build: yarn build
output_dir: public
name: Deploy
runs-on: ubuntu-latest
needs: build
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
with:
preview: false
76 changes: 66 additions & 10 deletions .github/workflows/deploy_preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,71 @@ permissions:
id-token: write

jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- id: get-dotcom-access-token
uses: camertron/github-app-installation-auth-action@v1
with:
app-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_ID }}
private-key: ${{ secrets.DOTCOM_SHARED_COMPONENTS_APP_PRIVATE_KEY }}
client-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_CLIENT_ID }}
client-secret: ${{ secrets.DOTCOM_SHARED_COMPONENTS_APP_CLIENT_SECRET }}
installation-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_INSTALLATION_ID }}

- name: Checkout default branch
uses: actions/checkout@v2
with:
version: 16

- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: 16

- name: Cache dependencies
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

- name: Install dependencies
run: yarn

- name: Build
run: yarn build:preview
env:
GITHUB_TOKEN: ${{ steps.get-dotcom-access-token.outputs.access-token }}

- name: Archive build output
run: "tar --dereference --directory public -cvf artifact.tar ."

- name: Upload artifact
uses: actions/upload-artifact@main
with:
name: github-pages
path: artifact.tar

deploy-preview:
if: ${{ github.event.pull_request.head.repo.full_name == 'primer/design' }}
if: ${{ github.repository == 'primer/design' }}
name: Preview
# SHA for security hardening. Points at last verified HEAD of main branch.
uses: primer/.github/.github/workflows/deploy_preview.yml@0cec9b9914f358846163f2428663b58da41028c9
secrets:
gh_token: ${{ secrets.GITHUB_TOKEN }}
with:
node_version: 16
install: yarn
build: yarn build:preview
output_dir: public
runs-on: ubuntu-latest
needs: build
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
permissions:
contents: read
pages: write
id-token: write
outputs:
deployment_url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
with:
preview: true
17 changes: 10 additions & 7 deletions content/github-staff/github-shared-components.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,24 @@ title: GitHub shared components
description: Application-specific components that are shared by GitHub feature teams but are not in Primer.
---

import DotcomSharedComponentsLayout from '~/src/layouts/dotcom-shared-components-layout'
export default DotcomSharedComponentsLayout

<Note>This information is only relevant to GitHub staff.</Note>

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.
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.

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.

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).

## Finding these components

GitHub shared components are documented in a private Storybook instance: [ui/packages/ Storybook](https://gh.io/storybook) (only available to GitHub staff).

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.

## Related reading

- [Handling new patterns](/guides/contribute/handling-new-patterns)
- [Upstreaming to Primer](/guides/contribute/adding-new-components#upstreaming-to-primer)

## Shared components
camertron marked this conversation as resolved.
Show resolved Hide resolved
camertron marked this conversation as resolved.
Show resolved Hide resolved
camertron marked this conversation as resolved.
Show resolved Hide resolved

GitHub shared components are documented in a private Storybook instance: [ui/packages/ Storybook](https://gh.io/storybook) (only available to GitHub staff).

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.
138 changes: 138 additions & 0 deletions gatsby-node.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import * as path from 'path'
import * as fs from 'fs'
import * as defines from './babel-defines'
import fetch from 'node-fetch'
import GithubSlugger from 'github-slugger'
import { latestStatusFrom } from './src/rails-status'
import { Octokit } from '@octokit/rest'
import JSZip from 'jszip'

exports.onCreateWebpackConfig = ({actions, plugins, getConfig}) => {
const config = getConfig()
Expand Down Expand Up @@ -32,6 +35,141 @@ exports.sourceNodes = async ({actions, createNodeId, createContentDigest}) => {
await sourcePrimerRailsData({actions, createNodeId, createContentDigest})
await sourceOcticonData({actions, createNodeId, createContentDigest})
await sourceFigmaData({actions, createNodeId, createContentDigest})
await sourceDotcomSharedComponentsData({actions, createNodeId, createContentDigest})
}

exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions
const typeDefs = `
type SharedComponent implements Node {
component: String!
storyIds: [String!]
status: String!
path: String!
}
`
createTypes(typeDefs)
}

async function sourceDotcomSharedComponentsData({actions, createNodeId, createContentDigest}) {
const sharedComponents = await getSharedComponentsData()
const slugger = new GithubSlugger()

for (const sharedComponent of sharedComponents) {
const {component: name} = sharedComponent

const newNode = {
component: sharedComponent.component,
storyIds: sharedComponent.storyIds,
status: sharedComponent.meta.status,
path: sharedComponent.meta.path,
id: createNodeId(`dotcom-shared-${name}`),
internal: {
type: 'SharedComponent',
contentDigest: createContentDigest(sharedComponent),
},
}

actions.createNode(newNode)

const sharedComponentsPath = '/github-staff/github-shared-components'
const componentPath = `${sharedComponentsPath}/${slugger.slug(name)}`

actions.createRedirect({
fromPath: componentPath,
toPath: `${sharedComponentsPath}#${name[0].toLowerCase()}`,
redirectInBrowser: true,
force: true
})

const searchDoc = {
title: name,
path: componentPath,
rawBody: name
}

const searchNode = {
...searchDoc,
id: createNodeId(`shared-component-search-doc-${name}`),
internal: {
type: 'CustomSearchDoc',
contentDigest: createContentDigest(searchDoc)
}
}

actions.createNode(searchNode)
}
}

async function getSharedComponentsData() {
if (!process.env.GITHUB_TOKEN) {
console.log('No GITHUB_TOKEN in environment, falling back to using recipe_metadata.json')
return JSON.parse(fs.readFileSync('recipe_metadata.json', 'utf8'))
}

const client = new Octokit({
auth: process.env.GITHUB_TOKEN
})

console.log('Listing dotcom workflow runs...')

const workflowRuns = await client.rest.actions.listWorkflowRuns({
owner: 'github',
repo: 'github',
workflow_id: 'preview-pages-build.yml',
branch: 'master',
status: 'success',
per_page: 1
})

if (workflowRuns.data.workflow_runs.length == 0) {
console.log('No workflow runs found 🤔')
return
}

const workflowRunId = workflowRuns.data.workflow_runs[0].id
console.log(`Workflow run ${workflowRunId} found`)

console.log('Listing workflow run artifacts...')
const artifacts = await client.rest.actions.listWorkflowRunArtifacts({
owner: 'github',
repo: 'github',
run_id: workflowRunId
})

const artifactId = (() => {
for (const artifact of artifacts.data.artifacts) {
if (artifact.name == 'recipe-metadata') {
return artifact.id
}
}

return null
})()

if (artifactId) {
console.log(`Found artifact ${artifactId}`)
} else {
console.log('No artifacts found for workflow run 🤯')
return
}

console.log('Downloading artifact...')
const artifactContents = await client.rest.actions.downloadArtifact({
owner: 'github',
repo: 'github',
artifact_id: artifactId,
archive_format: 'zip'
})

console.log('Extracting artifact...')

const zip = new JSZip();
const zipData = await zip.loadAsync(artifactContents.data)
const manifestRaw = await zipData.file('recipe_metadata.json').async('string')
const manifest = JSON.parse(manifestRaw)

return manifest
}

async function sourcePrimerRailsData({actions, createNodeId, createContentDigest}) {
Expand Down
Loading
Loading