Skip to content

Commit

Permalink
Merge branch 'main' into testing-doc
Browse files Browse the repository at this point in the history
  • Loading branch information
sidvishnoi committed Aug 21, 2024
2 parents 13d07b1 + 71373b0 commit c03e2d6
Show file tree
Hide file tree
Showing 62 changed files with 2,837 additions and 3,009 deletions.
9 changes: 5 additions & 4 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:jsx-a11y/recommended",
"plugin:jest/recommended",
"plugin:@typescript-eslint/recommended"
"plugin:jest/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2020,
"ecmaFeatures": { "jsx": true }
"ecmaFeatures": {
"jsx": true
}
},
"plugins": ["html"],
"plugins": [],
"settings": {
"react": {
"version": "detect"
Expand Down
50 changes: 50 additions & 0 deletions .github/actions/bump-manifest-version.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// @ts-check
/* eslint-disable @typescript-eslint/no-var-requires, no-console */
const fs = require('node:fs/promises')

/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ core }) => {
const manifestPath = './src/manifest.json'
const manifestFile = await fs.readFile(manifestPath, 'utf8')
const manifest = JSON.parse(manifestFile)
/**@type {string} */
const existingVersion = manifest.version

const bumpType = /** @type {BumpType} */ (process.env.INPUT_VERSION)
if (!bumpType) {
throw new Error('Missing bump type')
}

const version = bumpVersion(existingVersion, bumpType).join('.')

console.log({ existingVersion, bumpType, version })

manifest.version = version
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2))
core.setOutput('version', version)
}

/**
* @typedef {'build' | 'patch' | 'minor'} BumpType
* @param {string} existingVersion
* @param {BumpType} type
* @return {[major: number, minor: number, patch: number, build: number]}
*/
function bumpVersion(existingVersion, type) {
const parts = existingVersion.split('.').map(Number)
if (parts.length !== 4 || parts.some((e) => !Number.isSafeInteger(e))) {
throw new Error('Existing version does not have right format')
}
const [major, minor, patch, build] = parts

switch (type) {
case 'build':
return [major, minor, patch, build + 1]
case 'patch':
return [major, minor, patch + 1, 0]
case 'minor':
return [major, minor + 1, 0, 0]
default:
throw new Error('Unknown bump type: ' + type)
}
}
9 changes: 8 additions & 1 deletion .github/actions/constants.cjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
// @ts-check

/**
* @typedef {'chrome' | 'firefox'} Browser
*/

const BADGE =
'<img src="https://img.shields.io/badge/{{ CONCLUSION }}-{{ BADGE_COLOR }}?style=for-the-badge&label={{ BADGE_LABEL }}" alt="Badge" />'
/** @type {Browser[]} */
const BROWSERS = ['chrome', 'firefox']
const COLORS = {
green: '3fb950',
Expand All @@ -8,7 +15,7 @@ const COLORS = {
const TEMPLATE_VARS = {
tableBody: '{{ TABLE_BODY }}',
sha: '{{ SHA }}',
conslusion: '{{ CONCLUSION }}',
conclusion: '{{ CONCLUSION }}',
badgeColor: '{{ BADGE_COLOR }}',
badgeLabel: '{{ BADGE_LABEL }}',
jobLogs: '{{ JOB_LOGS }}'
Expand Down
62 changes: 28 additions & 34 deletions .github/actions/delete-artifacts.cjs
Original file line number Diff line number Diff line change
@@ -1,67 +1,61 @@
/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable no-console */
// @ts-check
/* eslint-disable @typescript-eslint/no-var-requires, no-console */
const { BROWSERS } = require('./constants.cjs')

async function getBrowserArfifacts({ github, owner, repo, name }) {
const artifacts = []
/**
* @param {Pick<import('github-script').AsyncFunctionArguments, 'github' | 'context'>} AsyncFunctionArguments
* @param {string} name
*/
async function getBrowserArtifacts({ github, context }, name) {
const result = await github.rest.actions.listArtifactsForRepo({
owner,
repo,
owner: context.repo.owner,
repo: context.repo.repo,
name
})

for (let i = 0; i < result.data.total_count; i++) {
artifacts.push(result.data.artifacts[i].id)
}

return artifacts
return result.data.artifacts
}

async function getPRArtifacts({ github, owner, repo, prNumber }) {
const promises = []
const artifacts = []

BROWSERS.forEach((browser) =>
promises.push(
getBrowserArfifacts({
github,
owner,
repo,
name: `${prNumber}-${browser}`
})
/**
* @param {Pick<import('github-script').AsyncFunctionArguments, 'github' | 'context'>} AsyncFunctionArguments
* @param {number} prNumber
*/
async function getPRArtifacts({ github, context }, prNumber) {
const data = await Promise.all(
BROWSERS.map((browser) =>
getBrowserArtifacts({ github, context }, `${prNumber}-${browser}`)
)
)

const data = await Promise.all(promises)

/** @type {{id: number}[]} */
const artifacts = []
for (let i = 0; i < data.length; i++) {
// same as `artifacts.push(...data[i])` but it's a bit faster
artifacts.push.apply(artifacts, data[i])
}

return artifacts
}

/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ github, context, core }) => {
if (context.payload.action !== 'closed') {
core.setFailed('This action only works on closed PRs.')
}

const { owner, repo } = context.repo
/** @type {number} */
const prNumber = context.payload.number
const promises = []

const artifacts = await getPRArtifacts({ github, owner, repo, prNumber })
const artifacts = await getPRArtifacts({ github, context }, prNumber)

for (let i = 0; i < artifacts.length; i++) {
promises.push(
await Promise.all(
artifacts.map((artifact) =>
github.rest.actions.deleteArtifact({
owner,
repo,
artifact_id: artifacts[i]
artifact_id: artifact.id
})
)
}
)

await Promise.all(promises)
console.log(`Deleted ${artifacts.length} artifacts for PR #${prNumber}.`)
}
15 changes: 15 additions & 0 deletions .github/actions/get-built-version.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @ts-check
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-var-requires */
const fs = require('node:fs/promises')

/**
* Retrieves the manifest version from the built extension.
* @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments
*/
module.exports = async ({ core }) => {
const manifest = await fs
.readFile('./dist/chrome/manifest.json', 'utf8')
.then(JSON.parse)

core.setOutput('version', manifest.version)
}
41 changes: 29 additions & 12 deletions .github/actions/get-workflow-artifacts.cjs
Original file line number Diff line number Diff line change
@@ -1,27 +1,41 @@
/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable no-console */
// @ts-check
/* eslint-disable @typescript-eslint/no-var-requires, no-console */
const fs = require('node:fs/promises')
const { COLORS, TEMPLATE_VARS, BADGE } = require('./constants.cjs')

/**
* @typedef {import('./constants.cjs').Browser} Browser
*/

/** @type {Record<Browser, {name: string, url: string, size: string}>} */
const ARTIFACTS_DATA = {
chrome: {
name: 'Chrome',
url: null,
size: null
url: '',
size: ''
},
firefox: {
name: 'Firefox',
url: null,
size: null
url: '',
size: ''
}
}

/**
* @param {string} conclusion
* @param {string} badgeColor
* @param {string} badgeLabel
*/
function getBadge(conclusion, badgeColor, badgeLabel) {
return BADGE.replace(TEMPLATE_VARS.conslusion, conclusion)
return BADGE.replace(TEMPLATE_VARS.conclusion, conclusion)
.replace(TEMPLATE_VARS.badgeColor, badgeColor)
.replace(TEMPLATE_VARS.badgeLabel, badgeLabel)
}

/**
* @param {number} bytes
* @param {number} decimals
*/
function formatBytes(bytes, decimals = 2) {
if (!Number(bytes)) return '0B'
const k = 1024
Expand All @@ -31,9 +45,10 @@ function formatBytes(bytes, decimals = 2) {
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))}${sizes[i]}`
}

/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ github, context, core }) => {
const { owner, repo } = context.repo
const baseUrl = context.payload.repository.html_url
const baseUrl = context.payload.repository?.html_url
const suiteId = context.payload.workflow_run.check_suite_id
const runId = context.payload.workflow_run.id
const conclusion = context.payload.workflow_run.conclusion
Expand All @@ -44,6 +59,8 @@ module.exports = async ({ github, context, core }) => {
'./.github/actions/templates/build-status.md',
'utf8'
)

/** @type {string[]} */
const tableRows = []

core.setOutput('conclusion', conclusion)
Expand All @@ -59,15 +76,15 @@ module.exports = async ({ github, context, core }) => {
})

artifacts.data.artifacts.forEach((artifact) => {
const [, key] = artifact.name.split('-')
const key = /** @type {Browser} */ (artifact.name.split('-')[1])
ARTIFACTS_DATA[key].url =
`${baseUrl}/suites/${suiteId}/artifacts/${artifact.id}`
ARTIFACTS_DATA[key].size = formatBytes(artifact.size_in_bytes)
})

Object.keys(ARTIFACTS_DATA).forEach((k) => {
const { name, url, size } = ARTIFACTS_DATA[k]
if (url === null && size === null) {
const { name, url, size } = ARTIFACTS_DATA[/** @type {Browser} */ (k)]
if (!url && !size) {
const badgeUrl = getBadge('failure', COLORS.red, name)
tableRows.push(
`<tr><td align="center">${badgeUrl}</td><td align="center">N/A</td></tr>`
Expand All @@ -82,7 +99,7 @@ module.exports = async ({ github, context, core }) => {

const tableBody = tableRows.join('')
const commentBody = template
.replace(TEMPLATE_VARS.conslusion, conclusion)
.replace(TEMPLATE_VARS.conclusion, conclusion)
.replace(TEMPLATE_VARS.sha, sha)
.replace(TEMPLATE_VARS.jobLogs, `<a href="${jobLogsUrl}">Run #${runId}</a>`)
.replace(TEMPLATE_VARS.tableBody, tableBody)
Expand Down
1 change: 1 addition & 0 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
name: Environment setup
description: Sets up Node and pnpm

runs:
using: 'composite'
Expand Down
40 changes: 40 additions & 0 deletions .github/actions/validate-stable-release.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// @ts-check

/**
* 1. Validate input version.
* 2. Check if given tag/release is already promoted to stable. If so, crash.
* @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments
*/
module.exports = async ({ github, context }) => {
if (context.ref !== 'refs/heads/main') {
throw new Error('This action only works on main branch')
}

const { owner, repo } = context.repo
const previewVersionTag = process.env.INPUT_VERSION
if (!previewVersionTag) {
throw new Error('Missing env.INPUT_VERSION')
}
if (!previewVersionTag.match(/^v[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+-preview$/)) {
throw new Error('Input "version" must match vX.X.X.X-preview')
}

const versionTag = previewVersionTag.replace('-preview', '')
try {
await github.rest.repos.getReleaseByTag({
owner,
repo,
tag: versionTag
})
throw new Error('Release already promoted to stable')
} catch (error) {
if (!error.status) {
throw error
}
if (error.status === 404) {
// do nothing
} else {
throw new Error(`Failed to check: HTTP ${error.status}`, { cause: error })
}
}
}
3 changes: 1 addition & 2 deletions .github/workflows/build-previews.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@ jobs:
id: find-comment
with:
issue-number: ${{ steps.get-workflow-artifacts.outputs.pr_number }}
comment-author: 'raducristianpopa'
comment-author: 'github-actions[bot]'
body-includes: '<!-- __WM_EXTENSION_BUILD_PREVIEWS__ -->'

- name: Add/Update comment
if: ${{ steps.get-workflow-artifacts.outputs.conclusion != 'cancelled' }}
uses: peter-evans/create-or-update-comment@v4
with:
token: ${{ secrets.PAT }}
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ steps.get-workflow-artifacts.outputs.pr_number }}
body: ${{ steps.get-workflow-artifacts.outputs.comment_body }}
Expand Down
Loading

0 comments on commit c03e2d6

Please sign in to comment.