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

Automated plugin releases #3093

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
90906fd
Browser plugin preview (#2748)
macintoshhelper Jul 26, 2024
2a5e1c1
create automated releases readme
macintoshhelper Aug 21, 2024
c96985e
Browser plugin preview (#2748)
macintoshhelper Jul 26, 2024
af9caad
add yarn.lock
macintoshhelper Aug 22, 2024
f706c99
Merge branch 'dx' into feat/2708-automated-releases
macintoshhelper Oct 3, 2024
e85b714
[WIP] add bundle and changesets parsing for releases
macintoshhelper Oct 7, 2024
9241751
Merge branch 'feat/2708-automated-releases' of github.com:tokens-stud…
macintoshhelper Oct 7, 2024
0469fef
[WIP] split bundle script into release/beta
macintoshhelper Oct 16, 2024
b762bed
[WIP] add release bundle upload for publish script
macintoshhelper Oct 18, 2024
66386c4
Merge branch 'main' into dx
macintoshhelper Oct 21, 2024
a308f61
update web preview script docs
macintoshhelper Oct 21, 2024
5682bfa
Merge branch 'dx' of github.com:tokens-studio/figma-plugin into dx
macintoshhelper Oct 22, 2024
1449483
fix: updateStyles error from merge conflict
macintoshhelper Oct 22, 2024
6f3903e
lint: remove comments and cleanup
macintoshhelper Oct 22, 2024
abef936
fix: language switch on startup for new preview startup
macintoshhelper Oct 22, 2024
ac0b74a
lint: remove more comments from preview files
macintoshhelper Oct 22, 2024
57d3589
Merge branch 'main' into dx
macintoshhelper Oct 22, 2024
30acdc7
lint: fix indentation error because of prettier conflict
macintoshhelper Oct 22, 2024
b78a643
Merge branch 'dx' of github.com:tokens-studio/figma-plugin into dx
macintoshhelper Oct 22, 2024
7b7bfcc
Merge branch 'dx' into feat/2708-automated-releases
macintoshhelper Oct 22, 2024
31fade3
finish setup for automated releases github actions/scripts
macintoshhelper Oct 23, 2024
ed330fe
Merge branch 'main' into feat/2708-automated-releases
macintoshhelper Oct 24, 2024
f8ba0bf
Merge branch 'main' into feat/2708-automated-releases
macintoshhelper Nov 14, 2024
01f721d
add yarn.lock
macintoshhelper Nov 14, 2024
7ad4f6e
fix: revert yarn.lock and turbo upgrade
macintoshhelper Nov 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,47 @@ jobs:
# Generate the release automatically in Github. This should not result in a publish to npm
# We should disable this if doing beta releases
- name: Create Release
if: ${{ inputs.createRelease }}
id: changesets
uses: changesets/action@v1
with:
version: npm run version
publish: npx @changesets/cli tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish Figma plugin
if: steps.changesets.outputs.published == 'true'
run: npm run release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FIGMA_WEB_AUTHN_TOKEN: ${{ secrets.FIGMA_WEB_AUTHN_TOKEN }}
- name: Prepare Figma release
if: steps.changesets.outputs.pullRequestNumber != ''
run: npm run bundle
# Store artifact for later use
- name: Store Artifact
id: "store_artifact"
if: steps.changesets.outputs.pullRequestNumber != ''
uses: actions/upload-artifact@v4
with:
name: package
path: dist/bundle.zip
path: |
packages/plugin/dist/bundle.zip
packages/plugin/dist/release.zip
# Post link to artifact
- name: Find artifact comment
uses: peter-evans/find-comment@v3
if: steps.changesets.outputs.pullRequestNumber != ''
id: find_artifact_comment
with:
issue-number: ${{ steps.changesets.outputs.pullRequestNumber }}
comment-author: 'github-actions[bot]'
body-includes: The artifact was successfully created
- name: Create or update artifact comment
uses: peter-evans/create-or-update-comment@v4
if: steps.changesets.outputs.pullRequestNumber != ''
with:
comment-id: ${{ steps.find_artifact_comment.outputs.comment-id }}
issue-number: ${{ steps.changesets.outputs.pullRequestNumber }}
body: |
⤵️ 📦 ✨ The artifact was successfully created! Want to test it? [Download it here](${{steps.store_artifact.outputs.artifact-url}}) 👀 🎁
edit-mode: replace
43 changes: 43 additions & 0 deletions developer-knowledgebase/automated-releases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Automated Releases

For automated releases, `figcd` is used. https://github.com/opral/parrot-figcd

## Instructions

Make sure that app-based MFA/TOTP is enabled for Figma, as it is necessary for publishing plugin releases.

**Creating a Figma authentication token locally**

```sh
npx figcd auth
```

> Enter your Figma email

> Enter your Figma password

> Enter your Figma TOTP token

**Copy and paste the Terminal output**

Example:

```sh
FIGMA_WEB_AUTHN_TOKEN=%7B%2figtkn.123.authn.456%22%7D
```

**Configure the secret on GitHub**

> Repo Settings > Security > Secrets and Variables > Actions > Environment secrets

```sh
FIGMA_WEB_AUTHN_TOKEN
```

### Release Command

```sh
npx figcd release
```


5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
"private": true,
"scripts": {
"bundle": "ts-node ./scripts/bundle.ts",
"bundle": "npx turbo run bundle",
"build": "npx turbo run build",
"start": "npx turbo run start",
"lint": "npx turbo run lint",
"test": "npx turbo run test",
"test:watch": "npx turbo run test:watch",
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
"release": "changeset publish",
"release": "npx turbo run release",
"version": "changeset version && npx turbo run version",
"changeset": "changeset"
},
"devDependencies": {
Expand Down
11 changes: 9 additions & 2 deletions packages/tokens-studio-for-figma/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"license": "MIT",
"private": true,
"scripts": {
"bundle": "ts-node ./scripts/bundle.ts",
"bundle": "node scripts/bundle.mjs",
"watch-transform": "webpack --mode=development --watch --config webpack-transform.config.js",
"build": "cross-env NODE_ENV=production webpack --mode=production",
"build:dev": "cross-env NODE_ENV=development webpack --mode=development",
Expand All @@ -31,6 +31,9 @@
"serve": "serve dist -p 58630",
"serve:preview": "serve preview -p 58630",
"changeset": "changeset",
"release": "node scripts/release.mjs",
"version": "node scripts/version.mjs",
"publish": "changeset tag && npm run release",
"translate": "node ./scripts/translate.mjs",
"lint": "eslint . --quiet --fix",
"lint:nofix": "eslint .",
Expand Down Expand Up @@ -208,6 +211,7 @@
"eslint-plugin-react-hooks": "^4.4.0",
"eslint-plugin-validate-jsx-nesting": "^0.1.1",
"express": "^4.19.2",
"figcd": "^0.0.16",
"figma-api-stub": "^0.0.56",
"figma-plugin-ds": "^1.0.1",
"file-loader": "^6.2.0",
Expand Down Expand Up @@ -263,5 +267,8 @@
"prettier --write",
"git add"
]
},
"figma": {
"version": "177"
}
}
}
47 changes: 47 additions & 0 deletions packages/tokens-studio-for-figma/scripts/bundle.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import JSZip from 'jszip';
import path from 'path';
import { readFile, writeFile } from 'fs/promises';
import * as url from 'url';

const __dirname = url.fileURLToPath(new URL('.', import.meta.url));

async function readJSONFile(filePath) {
const absoluteFilePath = path.join(__dirname, filePath);
const data = await readFile(absoluteFilePath, 'utf8');
return JSON.parse(data);
}

async function createZipBundle(isRelease) {
const zip = new JSZip();

const packageJson = await readJSONFile('../package.json');
const manifest = await readJSONFile('../manifest.json');

const main = await readFile(path.join(__dirname, '..', manifest.main), 'utf8');
const ui = await readFile(path.join(__dirname, '..', manifest.ui), 'utf8');

await zip.file(manifest.main, main);
await zip.file(manifest.ui, ui);
await zip.file(
'manifest.json',
JSON.stringify({
...manifest,
name: isRelease ? 'Tokens Studio for Figma' : `Tokens Studio for Figma: Beta - ${packageJson.version}`,
}),
);
await zip.file('package.json', JSON.stringify(packageJson));

const file = await zip.generateAsync({ type: 'nodebuffer' });
return await writeFile(isRelease ? 'dist/release.zip' : 'dist/bundle.zip', file);
}

async function bundle() {
try {
await createZipBundle();
await createZipBundle(true);
} catch (err) {
console.log(err);
}
}

bundle();
31 changes: 31 additions & 0 deletions packages/tokens-studio-for-figma/scripts/changeset.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export async function publishChangeset(version, _title, content) {
const tkn = process.env.FEATUREBASE_TOKEN;

const title = _title || version;
const url = 'https://do.featurebase.app/v2/changelog';
const data = {
title: title,
markdownContent: Array.isArray(content) ? content.join('\n') : content,
// changelogCategories: ['New', 'Fixed', 'Improved'],
state: 'draft',
// featuredImage: 'http://example.com/image.png',
};

const res = await fetch(url, {
method: 'POST',
headers: {
'X-API-Key': tkn,
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});

try {
const resJson = await res.json();
if (resJson.success && resJson.results.slug) {
return `https://feedback.tokens.studio/changelog/${resJson.results.slug}`;
}
} catch (err) {
console.log(err);
}
}
37 changes: 37 additions & 0 deletions packages/tokens-studio-for-figma/scripts/parse-changeset.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import fs from 'fs';
import path from 'path';
import * as url from 'url';

const __dirname = url.fileURLToPath(new URL('.', import.meta.url));

function extractChanges(markdown, packageName, version) {
const packageRegex = new RegExp(`# ${packageName}`, 'i');
const versionRegex = new RegExp(`## ${version}`, 'i');

const sections = markdown.split('\n# ');

const packageSection = sections.find((section) => packageRegex.test(`# ${section}`));
if (!packageSection) {
console.log(`Package ${packageName} not found in the markdown.`);
return [];
}

const versionSection = packageSection.split('\n## ').find((section) => versionRegex.test(`## ${section}`));
if (!versionSection) {
console.log(`Version ${version} not found for package ${packageName}.`);
return [];
}

const patchChanges = versionSection.split('\n### Patch Changes\n')[1];

return patchChanges ? patchChanges.trim().split('\n') : [];
}

const markdownFilePath = '../CHANGELOG.md'; // Path to the markdown file
const markdown = fs.readFileSync(path.join(__dirname, markdownFilePath), 'utf-8');

export function extractChangeset(packageName = '@elemental-figma/json-to-figma', version) {
const changes = extractChanges(markdown, packageName, version);

return changes;
}
86 changes: 86 additions & 0 deletions packages/tokens-studio-for-figma/scripts/prepare.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { readFile, writeFile } from 'fs/promises';
// import * as fs from 'fs-extra';
import * as url from 'url';
import path from 'path';
import figmaHelper from 'figcd/src/figma-helper.js';

const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
const __filename = url.fileURLToPath(import.meta.url);






async function updatePackageVersion(packageFile, minorVersion) {
const packageDataRaw = await readFile(packageFile, 'utf8');
const packageData = JSON.parse(packageDataRaw);
const version = packageData?.figma?.version || '0';
const versionParts = version.split('.');
versionParts[versionParts.length - 1] = minorVersion.toString();
const updatedVersion = versionParts.join('.');
await writeFile(packageFile, JSON.stringify({
...packageData,
figma: {
...packageData.figma,
version: updatedVersion
}
}, null, 2), 'utf8');
}

const serializeCookies = (cookies, custom) => {
if (custom) {
return `${Object.keys(cookies).reduce((acc, k) => {
acc += `${k}=${cookies[k]};`
return acc;
}, '')}; ${custom}`;
}
return Object.keys(cookies).reduce((acc, k) => {
acc += `${k}=${cookies[k]};`
return acc;
}, '');
}

export const getPluginVersion = async () => {
const authNToken = process.env.FIGMA_WEB_AUTHN_TOKEN;
if (!authNToken) {
throw new Error('No Figma auth token found');
}
try {
const pluginInfo = await figmaHelper.getPluginInfo(path.join(__dirname, '../manifest.json'), authNToken)
return pluginInfo.currentVersionNumber;
} catch(err) {
// if (err.message.includes('does not have access')) {
console.log(err.message)

const manifestDataRaw = await readFile(path.join(__dirname, '../manifest.json'), 'utf8');
const manifestData = JSON.parse(manifestDataRaw);
const pluginsResponse = await fetch('https://www.figma.com/api/search/extensions?query=tokens%20studio%20for%20figmа&editor_type=figma&max_num_results=20', {
"headers": {
"accept": "application/json",
"content-type": "application/json",
"cookie": serializeCookies({
"__Host-figma.authn": authNToken,
}, null),
"user-agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
"Referer": "https://www.figma.com/",
"Referrer-Policy": "origin-when-cross-origin"
},
"method": 'GET'
});
const publishRequestJson = await pluginsResponse.json();
const pluginModel = publishRequestJson.meta.results.public.find(({ model }) => model.id === manifestData.id).model;
const version = pluginModel.versions[pluginModel.current_plugin_version_id].version;
return version;
}
}

export async function prepare() {
const packageFile = path.join(__dirname, '../package.json');
const currentVersionNumber = Number(await getPluginVersion());
if (!currentVersionNumber || isNaN(currentVersionNumber)) {
throw new Error('Failed to get current plugin version');
}
await updatePackageVersion(packageFile, currentVersionNumber + 1)
console.log('Minor Version in '+ packageFile + ' updated to '+ (currentVersionNumber + 1))
}
Loading
Loading