From 1127cbb3a591a0d7bb91de1b9100f06f6b75a8c0 Mon Sep 17 00:00:00 2001 From: Alan B Smith Date: Mon, 4 Mar 2024 10:34:46 -0700 Subject: [PATCH] chore: Add Token Studio sync action (#85) Adding a GH action to sync tokens studio [category:Infrastructure] --- .github/workflows/tokens-studio-sync.yml | 49 ++++++++++++++++++ scripts/tokens-config.ts | 2 + scripts/utils/api-client.ts | 2 +- scripts/utils/create-sync-branch.ts | 65 ++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/tokens-studio-sync.yml create mode 100644 scripts/utils/create-sync-branch.ts diff --git a/.github/workflows/tokens-studio-sync.yml b/.github/workflows/tokens-studio-sync.yml new file mode 100644 index 0000000..5a2eb47 --- /dev/null +++ b/.github/workflows/tokens-studio-sync.yml @@ -0,0 +1,49 @@ +name: Tokens Studio Sync + +on: + workflow_dispatch: + inputs: + token_type: + description: 'Choose which tokens to sync' + type: choice + options: + - 'all' + - 'base' + - 'brand' + - 'system' + default: 'all' + +jobs: + install: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - uses: Workday/canvas-kit-actions/install@v1 + with: + node_version: 18.x + + sync_tokens: + runs-on: ubuntu-latest + needs: install + + steps: + - name: Sync Tokens + shell: bash + working-directory: ./canvas-tokens + run: yarn tokens-config sync ${{ inputs.token_type }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + create_pull_request: + runs-on: ubuntu-latest + needs: sync_tokens + + steps: + - name: Create Sync PR + shell: bash + working-directory: ./canvas-tokens + run: yarn tokens-config create-pull + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/scripts/tokens-config.ts b/scripts/tokens-config.ts index 83c36a4..370f711 100644 --- a/scripts/tokens-config.ts +++ b/scripts/tokens-config.ts @@ -3,6 +3,7 @@ import {syncBaseConfig} from './utils/sync-base-config'; import {syncBrandConfig} from './utils/sync-brand-config'; import {syncSystemConfig} from './utils/sync-sys-config'; import {createSyncPullRequest} from './utils/pull-request'; +import {createSyncBranch} from './utils/create-sync-branch'; const syncTypeArg = new Argument('type', 'Specify which type of tokens to sync') .choices(['all', 'base', 'brand', 'system']) @@ -27,6 +28,7 @@ program .description('Sync Canvas Tokens repo with Tokens Studio config') .addArgument(syncTypeArg) .action(async type => { + await createSyncBranch(); switch (type) { case 'base': await syncBaseConfig(); diff --git a/scripts/utils/api-client.ts b/scripts/utils/api-client.ts index 9ea1502..ea09b92 100644 --- a/scripts/utils/api-client.ts +++ b/scripts/utils/api-client.ts @@ -7,7 +7,7 @@ config(); // Client for GitHub export const ghClient = new Octokit({ auth: process.env.GITHUB_TOKEN, - baseUrl: process.env.GITHUB_BASE_URL, + baseUrl: 'https://api.github.com', }); export const tokensStudioRepoParams = { diff --git a/scripts/utils/create-sync-branch.ts b/scripts/utils/create-sync-branch.ts new file mode 100644 index 0000000..3444b3e --- /dev/null +++ b/scripts/utils/create-sync-branch.ts @@ -0,0 +1,65 @@ +import {canvasTokensRepoParams, ghClient} from './api-client'; +import {RestEndpointMethodTypes} from '@octokit/rest'; + +async function getBranches() { + try { + const {data} = await ghClient.repos.listBranches({ + owner: canvasTokensRepoParams.owner, + repo: canvasTokensRepoParams.repo, + }); + return data; + } catch (error: any) { + console.error('Error: Failed to get branches.', error.message); + } +} + +type CreateBranchParams = RestEndpointMethodTypes['git']['createRef']['parameters']; +type UpdateBranchParams = RestEndpointMethodTypes['git']['updateRef']['parameters']; + +async function createBranch(params: CreateBranchParams) { + try { + await ghClient.git.createRef(params); + } catch (error: any) { + console.error('Error: Failed to create branch.', error.message); + } +} + +async function updateBranch(params: UpdateBranchParams) { + try { + await ghClient.git.updateRef(params); + } catch (error: any) { + console.error('Error: Failed to update branch.', error.message); + } +} + +export async function createSyncBranch() { + const branches = await getBranches(); + if (branches) { + const syncBranch = branches.find(branch => branch.name === canvasTokensRepoParams.syncBranch); + const mainBranch = branches.find( + branch => branch.name === canvasTokensRepoParams.defaultBranch + ); + const syncBranchRef = `refs/heads/${canvasTokensRepoParams.syncBranch}`; + // The main branch should always be available, but TS doesn't know that, so we have this extra conditional. + if (mainBranch) { + // If the sync branch doesn't exist, create it + if (!syncBranch) { + await createBranch({ + owner: canvasTokensRepoParams.owner, + repo: canvasTokensRepoParams.repo, + ref: syncBranchRef, + sha: mainBranch.commit.sha, + }); + } else { + // If the sync branch already exists, force update to ensure it's up-to-date with main + await updateBranch({ + owner: canvasTokensRepoParams.owner, + repo: canvasTokensRepoParams.repo, + ref: syncBranchRef, + sha: mainBranch.commit.sha, + force: true, + }); + } + } + } +}