Skip to content

Commit

Permalink
Fix: auto publish to externals error handling (#391)
Browse files Browse the repository at this point in the history
Co-authored-by: Tushar Mathur <[email protected]>
  • Loading branch information
beelchester and tusharmath authored Jul 26, 2024
1 parent 4a5c974 commit 4a2952c
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 21 deletions.
17 changes: 14 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,26 @@ jobs:
blog/**/*.{md,mdx}
- name: Publish to Hashnode and Dev.to 📝
if: github.ref == 'refs/heads/develop' && steps.changed-markdown-files.outputs.any_changed == 'true'
env:
HASHNODE_PAT: ${{ secrets.HASHNODE_PAT }}
HASHNODE_PUBLICATION_ID: ${{ secrets.HASHNODE_PUBLICATION_ID }}
CHANGED_FILES: ${{ steps.changed-markdown-files.outputs.all_changed_files }}
ADDED_FILES: ${{ steps.changed-markdown-files.outputs.added_files }}
DEVTO_API_KEY: ${{ secrets.DEVTO_API_KEY}}
DEVTO_ORG_ID: ${{secrets.DEVTO_ORG_ID}}
DEVTO_ORG_NAME: ${{secrets.DEVTO_ORG_NAME}}
run: |
cd ./publish-externals
npm run generate
npx --yes tsx ./src/index.ts "$CHANGED_FILES"
if [ "$GITHUB_REF" == "refs/heads/develop" ]; then
npx --yes tsx ./src/index.ts --publish "$ADDED_FILES"
else
npx --yes tsx ./src/index.ts "$ADDED_FILES"
fi
- name: Commit and push changes (on develop)
if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
uses: stefanzweifel/git-auto-commit-action@v5
with:
branch: develop
commit_author: Author <[email protected]>
commit_message: "[ci skip] update snapshot"
1 change: 1 addition & 0 deletions publish-externals/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"dependencies": {
"@apollo/client": "^3.10.8",
"axios": "^1.7.2",
"crypto": "^1.0.1",
"graphql": "^16.9.0",
"gray-matter": "^4.0.3"
},
Expand Down
3 changes: 3 additions & 0 deletions publish-externals/snapshot.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"blogs": {}
}
134 changes: 116 additions & 18 deletions publish-externals/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,133 @@ import path from "path"
import * as hashnode from "./utils/hashnode"
import {extractFrontMatterAndContent} from "./utils/markdown"
import * as devTo from "./utils/devto"
import snapshot from "../snapshot.json"
import fs from "fs"
import {createHash} from "crypto"

const ExternalPublications = [
interface Blog {
file: string
platforms: {
[platform: string]: {
published: boolean
lastUpdatePublished: boolean
lastSuccessfulPublishedAt?: string
}
}
hash?: string
}

interface ExternalPublication {
name: string
handler: (frontMatter: FrontMatter, content: string) => Promise<void>
}

interface FrontMatter {
slug: string
}

const ExternalPublications: ExternalPublication[] = [
{name: "Hashnode", handler: hashnode.handler},
{name: "Dev.to", handler: devTo.handler},
]

const main = async () => {
const changedFiles = process.argv[2].split(" ")
const errors = []
for (const file of changedFiles) {
if (file.startsWith("blog/")) {
const filePath = path.join(__dirname, "../../", file)
const {frontMatter, content} = extractFrontMatterAndContent(filePath)
for (let publication of ExternalPublications) {
console.log(`[${publication.name}] ${frontMatter.slug} ... publishing ⏳`)
try {
await publication.handler(frontMatter, content)
console.log(`[${publication.name}] Success ${frontMatter.slug} ... succeeded ✅`)
} catch (error) {
errors.push(error)
console.error(`[${publication.name}] Failure ${frontMatter.slug} ... failed 💀`)
const args = process.argv.slice(2)
const hasPublishFlag = args.includes("--publish")
const addedFilesArg = args.filter((arg) => arg !== "--publish")[0]
const addedFiles = addedFilesArg ? addedFilesArg.split(" ") : []
const blogs: {[key: string]: Blog} = snapshot.blogs || {}
let toPublish = 0

try {
for (let publication of ExternalPublications) {
for (const file of addedFiles) {
const {frontMatter} = extractFrontMatterAndContent(path.join(__dirname, "../../", file))
const slug = frontMatter.slug
if (file.startsWith("blog/")) {
console.log("Publishing new blog", slug)
toPublish++
hasPublishFlag && (await publish(file, blogs, publication))
}
}

for (const slug in blogs) {
const file = blogs[slug].file
if (!addedFiles.includes(file)) {
const {content} = extractFrontMatterAndContent(path.join(__dirname, "../../", file))
const contentHash = createHash("sha256").update(content).digest("hex")

if (!blogs[slug].hash) {
console.log("Publishing new blog from snapshot", slug)
toPublish++
hasPublishFlag && (await publish(file, blogs, publication))
} else if (blogs[slug].hash !== contentHash) {
console.log("Publishing updated blog", slug)
toPublish++
hasPublishFlag && (await publish(file, blogs, publication))
}
}
}
}
} finally {
if (toPublish === 0) {
console.log("No changes detected. Exiting.")
} else {
hasPublishFlag && (await writeSnapshot(blogs))
}
}
}

const publish = async (file: string, blogs: {[key: string]: Blog}, publication: ExternalPublication) => {
const filePath = path.join(__dirname, "../../", file)
const {frontMatter, content} = extractFrontMatterAndContent(filePath)
const platform = publication.name
const contentHash = createHash("sha256").update(content).digest("hex")
const slug = frontMatter.slug

console.log(`[${platform}] ${frontMatter.slug} ... publishing ⏳`)
try {
await publication.handler(frontMatter, content)

blogs[slug] = blogs[slug] || {
file,
platforms: {},
}
blogs[slug].platforms[platform] = {
published: true,
lastUpdatePublished: true,
lastSuccessfulPublishedAt: new Date().toUTCString(),
}
blogs[slug].hash = contentHash

console.log(`[${platform}] Success ${frontMatter.slug} ... succeeded ✅`)
} catch (error) {
console.error(`[${platform}] Failure ${frontMatter.slug} ... failed 💀`)

if (errors.length !== 0) {
console.error(errors)
throw new Error("Publishing failed because of one or more errors")
blogs[slug] = blogs[slug] || {
file,
platforms: {},
}
blogs[slug].platforms[platform] = {
published: blogs[slug].platforms[platform]?.published || false,
lastUpdatePublished: false,
}
console.log(blogs[slug])
}
}

const writeSnapshot = async (blogs: {[key: string]: Blog}) => {
console.log("Writing Snapshot")
const snapshot = JSON.stringify({blogs}, null, 2)
console.log(snapshot)
try {
fs.writeFile(path.join(__dirname, "../", "snapshot.json"), snapshot, (err) => {
if (err) {
console.error(err)
}
})
} catch (err) {
console.error(err)
}
}

Expand Down

0 comments on commit 4a2952c

Please sign in to comment.