Skip to content

Commit 8cbe7c1

Browse files
committed
hashnode uploads
1 parent 1d6c789 commit 8cbe7c1

File tree

3 files changed

+173
-0
lines changed

3 files changed

+173
-0
lines changed

.github/workflows/syndicate.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,53 @@ jobs:
4848
- uses: stefanzweifel/git-auto-commit-action@v4
4949
with:
5050
commit_message: main-devto updates
51+
- uses: stefanzweifel/git-auto-commit-action@v4
52+
with:
53+
commit_message: dev-devto updates
54+
branch: dev
55+
hashnode:
56+
environment: main
57+
runs-on: ubuntu-latest
58+
steps:
59+
- uses: actions/checkout@v3
60+
with:
61+
token: ${{ secrets.PAT }}
62+
- uses: actions/setup-node@v4
63+
name: Install node
64+
with:
65+
node-version: 18
66+
- uses: pnpm/action-setup@v2
67+
name: Install pnpm
68+
with:
69+
version: 8
70+
run_install: false
71+
- name: Get pnpm store directory
72+
shell: bash
73+
run: |
74+
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
75+
- uses: actions/cache@v3
76+
name: Setup pnpm cache
77+
with:
78+
path: ${{ env.STORE_PATH }}
79+
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
80+
restore-keys: |
81+
${{ runner.os }}-pnpm-store-
82+
- name: Install dependencies
83+
working-directory: ./apps/codingcatdev
84+
run: pnpm i
85+
- name: syndicate:post-hashnode
86+
working-directory: ./apps/codingcatdev/scripts
87+
run: node post-hashnode.js
88+
env:
89+
PRIVATE_DEVTO: ${{ secrets.PRIVATE_DEVTO }}
90+
- name: syndicate:podcast-hashnode
91+
working-directory: ./apps/codingcatdev/scripts
92+
run: node podcast-hashnode.js
93+
env:
94+
PRIVATE_DEVTO: ${{ secrets.PRIVATE_DEVTO }}
95+
- uses: stefanzweifel/git-auto-commit-action@v4
96+
with:
97+
commit_message: main-devto updates
5198
- uses: stefanzweifel/git-auto-commit-action@v4
5299
with:
53100
commit_message: dev-devto updates
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* You can test this using act
3+
* run act -s PRIVATE_DEVTO=yourapikey
4+
*/
5+
6+
import { Glob } from 'glob';
7+
import matter from 'gray-matter';
8+
import fs from 'fs';
9+
10+
const TYPE = 'post';
11+
const BASE = `../src/routes/(content-single)/(non-course)/${TYPE}/`;
12+
const g = new Glob(`${BASE}**/*.md`, {});
13+
14+
const delay = async (ms) => new Promise((res) => setTimeout(res, ms));
15+
16+
const addArticle = async (input) => {
17+
return fetch('https://api.hashnode.com/', {
18+
method: 'POST',
19+
headers: {
20+
authorization: '2b02d999-9e2d-409a-a2b4-7a1bcbbc58d5',
21+
'Content-Type': 'application/json'
22+
},
23+
body: JSON.stringify({
24+
operationName: 'createPublication',
25+
query: `mutation createPublication($input: CreateStoryInput!) {
26+
createPublicationStory(
27+
publicationId: "60242f8180da6c44eadf775b"
28+
input: $input
29+
) {
30+
message
31+
post {
32+
_id
33+
title
34+
slug
35+
}
36+
}
37+
}
38+
`,
39+
variables: {
40+
input: {
41+
isPartOfPublication: {
42+
publicationId: '60242f8180da6c44eadf775b'
43+
},
44+
...input
45+
}
46+
}
47+
})
48+
});
49+
};
50+
51+
for await (const file of g) {
52+
const mdFile = fs.readFileSync(file, { encoding: 'utf8', flag: 'r' });
53+
const { data, content } = await matter(mdFile); // data has frontmatter, code is html
54+
const fm = data;
55+
if (!fm) continue;
56+
// TODO: We might need to add a check on cononical if this page is already in dev.to
57+
if (
58+
fm?.slug &&
59+
fm?.title &&
60+
fm?.cover &&
61+
fm?.published === 'published' &&
62+
new Date(fm?.start) < new Date() &&
63+
!fm?.hasnode
64+
) {
65+
console.log('Adding', { slug: fm?.slug, hashnode: fm?.hasnode });
66+
67+
try {
68+
console.log('addArticle to hasnode');
69+
70+
// const response = await addArticle(
71+
72+
const finalContent = `
73+
Original: https://codingcat.dev/${TYPE}/${fm.slug}
74+
${fm?.spotify ? '%[' + fm.spotify + ']' : ''}
75+
${fm?.youtube ? '%[' + fm.youtube + ']' : ''}
76+
${content}`;
77+
const response = await addArticle({
78+
title: fm.title,
79+
subtitle: fm?.excerpt || '',
80+
slug: `${TYPE}-${fm.slug}`,
81+
contentMarkdown: finalContent,
82+
coverImageURL: fm.cover,
83+
isRepublished: {
84+
originalArticleURL: `https://codingcat.dev/${TYPE}/${fm.slug}`
85+
},
86+
tags: [
87+
{
88+
_id: '56744721958ef13879b94cad',
89+
name: 'JavaScript',
90+
slug: 'javascript'
91+
},
92+
{
93+
_id: '56744722958ef13879b94f1b',
94+
name: 'Web Development',
95+
slug: 'web-development'
96+
},
97+
{
98+
_id: '56744723958ef13879b955a9',
99+
name: 'Beginner Developers',
100+
slug: 'beginners'
101+
}
102+
]
103+
});
104+
105+
console.log('addArticle result:', response.status);
106+
if (response?.error) console.error('error', response.error);
107+
// Get new devto url and update
108+
if (response.status === 201) {
109+
const json = await response.json();
110+
if (json?.url) {
111+
console.log('Updating', file, { devto: json.url });
112+
const newMdFile = matter.stringify(content, {
113+
...data,
114+
devto: json.url
115+
});
116+
fs.writeFileSync(file, newMdFile, { encoding: 'utf8' });
117+
}
118+
}
119+
// Avoid 429
120+
await delay(process.env?.SYNDICATE_DELAY ? Integer(process.env.SYNDICATE_DELAY) : 10000);
121+
} catch (error) {
122+
console.error(error);
123+
}
124+
}
125+
}

apps/codingcatdev/src/routes/(content-single)/(non-course)/post/angular-17-cypress-testing/+page.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ excerpt: How you can easily test Angular 17 components with Cypress
99
hashnode:
1010
published: published
1111
start: November 11, 2023
12+
slug: angular-17-cypress-testing
1213
title: How to test Angular 17 using Cypress.io
1314
youtube: https://youtu.be/w3smSGP4w1M
1415
---

0 commit comments

Comments
 (0)