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

feat: use devcard V2 and download the png image over stream #404

Merged
merged 18 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 6 additions & 11 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ jobs:
name: Checkout code
uses: actions/checkout@v4

-
name: Enable Corepack
run: corepack enable

-
uses: actions/[email protected]
with:
Expand All @@ -39,7 +43,7 @@ jobs:
name: Install dependencies
if: steps.cache-node_modules.outputs.cache-hit != 'true'
run: |
yarn install --frozen-lockfile
yarn install --immutable

-
name: Lint
Expand All @@ -51,20 +55,11 @@ jobs:
run: |
yarn build

-
name: devcard.svg
uses: ./
with:
devcard_id: 0b156485612243bfa39092f30071e276
commit_filename: devcard.svg
commit_branch: main
dryrun: true

-
name: devcard.png
uses: ./
with:
devcard_id: 0b156485612243bfa39092f30071e276
devcard_id: XDCZD-PHG
commit_filename: devcard.png
commit_branch: main
dryrun: true
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ jobs:

- uses: chainguard-dev/actions/setup-gitsign@main

-
name: Enable Corepack
run: corepack enable

-
uses: actions/[email protected]
with:
Expand All @@ -49,7 +53,7 @@ jobs:
name: Install dependencies
if: steps.cache-node_modules.outputs.cache-hit != 'true'
run: |
yarn install --frozen-lockfile
yarn install --immutable

- name: Setup git
run: |
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v16
v20
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@ jobs:

### Required

- `devcard_id`: this is the unique hash of the devcard, it can be found in the URL of the devcard.
- e.g. `https://api.daily.dev/devcards/0b156485612243bfa39092.3.171e276.png` where the devcard_id is `0b156485612243bfa39092.3.171e276`
- Can be found at [https://app.daily.dev/devcard](https://app.daily.dev/devcard)
- `devcard_id`: this is the unique id of the devcard, it can be found in the URL of the devcard or [here](https://app.daily.dev/api/id).
- e.g. `https://api.daily.dev/devcards/v2/0b156485612243bfa39092.3.171e276.png` where the devcard_id is `0b156485612243bfa39092.3.171e276`
- Can be found at [https://app.daily.dev/api/id](https://app.daily.dev/api/id)

### Optional

- `token`: GitHub Token used to commit the devcard
- `commit_branch`: The branch to commit the devcard to. Defaults to the branch of the action.
- `commit_message`: The commit message to use when committing the devcard. Defaults to `Update ${filename}`.
- You can use `${filename}` in the message to refer to the filename of the devcard.
- `commit_filename`: The filename to commit the devcard to. Defaults to `devcard.svg`.
- If you want to save the devcard as a PNG, you can use `devcard.png` instead, or any other filename ending in `.png`.
- `commit_filename`: The filename to commit the devcard to. Defaults to `devcard.png`.
- You can also use any other filename ending in `.png`.
- `committer_email`: The committer email used in commit. Defaults to `[email protected]`.
- `committer_name`: The committer name used in commit. Defaults to `github-actions[bot]`.
- `dryrun`: If set to `true`, the action will run as normal, but not actually commit the devcard
Expand Down
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ inputs:

commit_filename:
description: Filename to save devcard to
default: devcard.svg
default: devcard.png
required: false

committer_email:
Expand Down
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
{
"name": "Ole-Martin Bratteng",
"email": "[email protected]"
},
{
"name": "Milan Freml",
"email": "[email protected]"
}
],
"scripts": {
Expand All @@ -24,17 +28,12 @@
"dependencies": {
"@actions/core": "^1.10.1",
"@actions/github": "^6.0.0",
"jsdom": "^22.1.0",
"node-fetch": "^3.3.2",
"sharp": "^0.32.6",
"simple-git": "^3.20.0",
"uuid": "^9.0.1"
"simple-git": "^3.20.0"
},
"devDependencies": {
"@types/jsdom": "21.x",
"@types/node": "20.x",
"@types/sharp": "0.32.x",
"@types/uuid": "9.x",
"@typescript-eslint/eslint-plugin": "^6.9.1",
"@typescript-eslint/parser": "^6.20.0",
"@vercel/ncc": "0.38.1",
Expand All @@ -44,5 +43,6 @@
"eslint-plugin-prettier": "^5.1.3",
"prettier": "^3.2.4",
"typescript": "^5.3.3"
}
},
"packageManager": "[email protected]"
}
83 changes: 21 additions & 62 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,23 @@
import * as core from '@actions/core'
import * as github from '@actions/github'
import type { GraphQlQueryResponseData } from '@octokit/graphql'
import fetch from 'node-fetch'

import { finished } from 'stream/promises'

import sgit from 'simple-git'
import fetch from 'node-fetch'
import fs from 'fs/promises'
import path from 'path'
import jsdom from 'jsdom'
import sharp from 'sharp'
import { validate } from 'uuid'

process.on('unhandledRejection', (error) => {
throw error
})

const convertImageToBase64 = async (url: string): Promise<string> => {
const resp = await fetch(url)
const contentType = resp.headers.get('content-type')

return `data:${contentType};base64,${(await resp.buffer()).toString('base64')}`
}

const fetchImagesFromSVG = async (svg: string): Promise<Record<string, string>> => {
const dom = new jsdom.JSDOM(svg)

dom.serialize()

const images: Record<string, string> = {}

dom.window.document.querySelectorAll('image').forEach((image) => {
const src = image.getAttribute('xlink:href')
src && (images[src] = src)
})

return images
}

const devcardURL = (devcard_id: string): string =>
`https://api.daily.dev/devcards/${devcard_id}.svg?r=${new Date().valueOf()}&ref=action`

const validateDevcardIdAsUUID = (devcard_id: string): boolean => {
// An UUIDv4 regex without hyphens
const uuid4Regex = /^([0-9A-F]{8})([0-9A-F]{4})(4[0-9A-F]{3})([89AB][0-9A-F]{3})([0-9A-F]{12})$/i
return validate(devcard_id.replace(uuid4Regex, '$1-$2-$3-$4-$5'))
}
`https://api.daily.dev/devcards/v2/${devcard_id}.png?r=${new Date().valueOf()}&ref=action`

;(async function () {
try {
let devCardContent = ''

const devcard_id = core.getInput('devcard_id')
const token = core.getInput('token')
const branch = core.getInput('commit_branch')
Expand All @@ -63,38 +32,25 @@ const validateDevcardIdAsUUID = (devcard_id: string): boolean => {
throw new Error('Filename is required')
}

if (!validateDevcardIdAsUUID(devcard_id)) {
throw new Error(`Invalid devcard_id: ${devcard_id}`)
}

console.log(`Dryrun`, dryrun)

// Fetch the latest devcard
try {
const res = await fetch(devcardURL(devcard_id))
devCardContent = await res.text()
const images = await fetchImagesFromSVG(devCardContent)

for (const image in images) {
if (Object.prototype.hasOwnProperty.call(images, image)) {
devCardContent = devCardContent.replace(image, await convertImageToBase64(images[image]))
}
}

await fs.mkdir(path.dirname(path.join(`/tmp`, filename)), { recursive: true })
await fs.writeFile(path.join(`/tmp`, filename), devCardContent)

if (filename.endsWith('.png')) {
await sharp(path.join(`/tmp`, filename))
.png({
quality: 100,
})
.toFile(path.join(`/tmp`, `_${filename}`))

await fs.rename(path.join(`/tmp`, `_${filename}`), path.join(`/tmp`, filename))
console.log('Converted devcard to PNG', 'ok')
const { body } = await fetch(devcardURL(devcard_id))
if (body === null) {
const message = `Empty response from devcard URL: ${devcardURL(devcard_id)}`
core.setFailed(message)
console.debug(message)
process.exit(1)
}

await fs.mkdir(path.dirname(path.join(`/tmp`, filename)), {
recursive: true,
})
const file = await fs.open(path.join(`/tmp`, filename), 'w')
const stream = file.createWriteStream()
await finished(body.pipe(stream))
await file.close()
console.log(`Saved to ${path.join(`/tmp`, filename)}`, 'ok')
} catch (error) {
console.debug(error)
Expand All @@ -121,7 +77,10 @@ const validateDevcardIdAsUUID = (devcard_id: string): boolean => {

//Create head branch if needed
try {
await octokit.rest.git.getRef({ ...github.context.repo, ref: `heads/${committer.branch}` })
await octokit.rest.git.getRef({
...github.context.repo,
ref: `heads/${committer.branch}`,
})
console.log('Committer head branch status', 'ok')
} catch (error) {
if (/not found/i.test(`${error}`)) {
Expand Down
Loading