※ 본 포스팅은 lourcode 님의 글을 참고하였습니다.(원본링크 : [https://lourcode.kr/posts/Jekyll-기반-Github-Pages와-Notion-Page-연동/](https://lourcode.kr/posts/Jekyll-%EA%B8%B0%EB%B0%98-Github-Pages%EC%99%80-Notion-Page-%EC%97%B0%EB%8F%99/))
### 1. API 키 설정
1-1. 아래 주소 클릭
https://www.notion.so/my-integrations
1-2. 새 API 통합 클릭
1-3. 연결된 워크스페이스를 확인하고 이름을 만들어주고 '제출' 버튼 클릭
1-4. 시크릿키가 생성되면 표시 → 복사 를 순서대로 클릭하여 키값을 복사한다.
※ 시크릿키값은 secret_* 의 형태로 되어있다.
## 2. 노션에서 사용/연동 할 데이터베이스 생성
2-1. 아래와 같이 샘플용으로 만들어본다.(공유링크 : https://asteriskos.notion.site/Blog-DB-85109cf911b74a62a5041f6047d5792d?pvs=4)
2-2. 테이블에 마우스를 가져가 되면 옆에 더보기(::)가 표시되는데 클릭한다.
2-3. 링크복사를 누른다
https://www.notion.so/asteriskos/de2dcf74aff44030954dbd4d991c559b?v=1f7e542c866341c1a8d68c9c328c3faf&pvs=4
굵게 표시한 부분이 데이터베이스의 ID 이다. 기억해둔다.
## 3. 데이터베이스 페이지에 API연동
3-1. 데이터베이스 생성한 페이지 우측상단에 더보기(…) 를 클릭하여 API를 연동한다.
3-2. 연결할거냐는 팝업이뜨는데, '확인' 버튼을 눌러 연결됨을 확인하자.
## 4. 깃허브 파일 설정
4-1. Settings → Secrets and variables → Actions 를 눌러 키를 생성해야한다.
4-1-1. '1-4' 에서 확보한 노션토큰을 'NOTION_TOKEN'으로 저장한다.
4-1-2. '2-3' 에서 확보한 DB ID를 'DATABASE_ID' 로 저장한다.
4-1-2. '깃허브 personalKey'를 'GH_TOKEN' 으로 저장한다.
4-2. root 폴더에 ‘_scripts’ 폴더를 생성하고, 생성한 폴더 안에 ‘**notion-import.js**’ 파일을 만들고 아래 내용을 입력한다.
const { Client } = require("@notionhq/client");
const { NotionToMarkdown } = require("notion-to-md");
const moment = require("moment");
const path = require("path");
const fs = require("fs");
const axios = require("axios");
const notion = new Client({
auth: process.env.NOTION_TOKEN,
});
function escapeCodeBlock(body) {
const regex = /```([\s\S]*?)```/g
return body.replace(regex, function (match, htmlBlock) {
return "{% raw %}\n```\n" + htmlBlock + "\n```\n{% endraw %}";
})
}
function replaceTitleOutsideRawBlocks(body) {
const rawBlocks = [];
const placeholder = "%%RAW_BLOCK%%";
body = body.replace(/{% raw %}[\s\S]*?{% endraw %}/g, (match) => {
rawBlocks.push(match);
return placeholder;
});
const regex = /\n#[^\n]+\n/g;
body = body.replace(regex, function (match) {
return "\n" + match.replace("\n#", "\n##");
});
rawBlocks.forEach(block => {
body = body.replace(placeholder, block);
});
return body;
}
// passing notion client to the option
const n2m = new NotionToMarkdown({ notionClient: notion });
(async () => {
// ensure directory exists
const root = "_posts";
fs.mkdirSync(root, { recursive: true });
const databaseId = process.env.DATABASE_ID;
let response = await notion.databases.query({
database_id: databaseId,
filter: {
property: "배포",
checkbox: {
equals: true,
},
},
});
const pages = response.results;
while (response.has_more) {
const nextCursor = response.next_cursor;
response = await notion.databases.query({
database_id: databaseId,
start_cursor: nextCursor,
filter: {
property: "배포",
checkbox: {
equals: true,
},
},
});
pages.push(...response.results);
}
for (const r of pages) {
const id = r.id;
// date
let date = moment(r.created_time).format("YYYY-MM-DD");
let pdate = r.properties?.["날짜"]?.["date"]?.["start"];
if (pdate) {
date = moment(pdate).format("YYYY-MM-DD");
}
// title
let title = id;
let ptitle = r.properties?.["게시물"]?.["title"];
if (ptitle?.length > 0) {
title = ptitle[0]?.["plain_text"];
}
// tags
let tags = [];
let ptags = r.properties?.["태그"]?.["multi_select"];
for (const t of ptags) {
const n = t?.["name"];
if (n) {
tags.push(n);
}
}
// categories
let cats = [];
let pcats = r.properties?.["카테고리"]?.["multi_select"];
for (const t of pcats) {
const n = t?.["name"];
if (n) {
cats.push(n);
}
}
// frontmatter
let fmtags = "";
let fmcats = "";
let fmassrtmnt = "";
if (tags.length > 0) {
fmtags += "[";
for (const t of tags) {
fmtags += t + ", ";
}
fmtags += "]";
}
if (assrtmnt.length > 0) {
fmassrtmnt += "[";
for (const t of assrtmnt) {
fmassrtmnt += t ;
}
fmassrtmnt += "]";
}
const fm = `---
title: "${title}"
excerpt: ""
header: ""
categories:
- ${fmcats}
tags:
- ${fmtags}
last_modified_at: ${date}
---
<br><br>
`;
const mdblocks = await n2m.pageToMarkdown(id);
let body = n2m.toMarkdownString(mdblocks)["parent"];
if (body === "") {
continue;
}
body = escapeCodeBlock(body);
body = replaceTitleOutsideRawBlocks(body);
const ftitle = `${date}-${title.replaceAll(" ", "_")}.md`;
let index = 0;
let edited_md = body.replace(
/!\[(.*?)\]\((.*?)\)/g,
function (match, p1, p2, p3) {
// const dirname = path.join("assets/img", ftitle);
const dirname = path.join("upload", ftitle);
if (!fs.existsSync(dirname)) {
fs.mkdirSync(dirname, { recursive: true });
}
const filename = path.join(dirname, `${index}.png`);
axios({
method: "get",
url: p2,
responseType: "stream",
})
.then(function (response) {
let file = fs.createWriteStream(`${filename}`);
response.data.pipe(file);
})
.catch(function (error) {
console.log(error);
});
let res;
if (p1 === "") res = "";
else res = `_${p1}_`;
return `![${index++}](/${filename})${res}`;
}
);
//writing to file
fs.writeFile(path.join(root, ftitle), fm + edited_md, (err) => {
if (err) {
console.log(err);
}
});
}
})();
4-3. 위 JavaScript 파일(**notion-import.js**)에 대한 dependencies 설정을 위해 'package.json' 파일 하단에 아래 내용을 입력 해 준다.
## yaml
name: "Build and Deploy"
on:
repository_dispatch:
types: [RUN_WORKFLOW_DISPATCH]
permissions:
contents: write
pages: write
id-token: write
# Allow one concurrent deployment
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
importer:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/setup-node@v3
with:
node-version: "17"
- run: npm install
- run: node _scripts/notion-import.js
env:
NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
DATABASE_ID: ${{ secrets.DATABASE_ID }}
- uses: stefanzweifel/git-auto-commit-action@v4
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
with:
commit_message: "[BOT] Commit & Deploy from Notion"
branch: main
commit_user_name: morimin-bot 🤖
commit_user_email: morimin@github.com
commit_author: morimin-bot 🤖 <morimin@github.com>
build:
needs: importer
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: main
fetch-depth: 1
- name: Setup Pages
id: pages
uses: actions/configure-pages@v1
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.1' # reads from a '.ruby-version' or '.tools-version' file if 'ruby-version' is omitted
bundler-cache: true
- name: Build site
run: bundle exec jekyll b -d "_site${{ steps.pages.outputs.base_path }}"
env:
JEKYLL_ENV: "production"
- name: Test site
run: |
bundle exec htmlproofer _site --disable-external --check-html --allow_hash_href
- name: Upload site artifact
uses: actions/upload-pages-artifact@v1
with:
path: "_site${{ steps.pages.outputs.base_path }}"
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
4-4. root 폴더에 ‘.github’ 폴더를 생성하고, 생성한 폴더 안에 ‘workflows’ 폴더를 생성하고, 생성한 폴더 안에 ‘pages-deploy.yml’ 파일을 만들고 아래 내용을 입력한다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
.trigger-container {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.trigger-button {
display: inline-block;
margin-bottom: 10px;
padding: 10px 20px;
background-color: #4c9aff;
color: white;
font-size: 16px;
border: none;
cursor: pointer;
border-radius: 4px;
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.1);
transition: background-color 0.3s;
}
.trigger-button:hover {
background-color: #2e86ff;
}
.message {
font-size: 16px;
color: #333;
}
</style>
</head>
<body>
<div class="trigger-container">
<button id="triggerButton" class="trigger-button">UPLOAD</button>
<div id="message" class="message"></div>
</div>
<script>
document.getElementById("triggerButton").addEventListener("click", function() {
var messageElement = document.getElementById("message");
messageElement.textContent = "요청 전송 중...";
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://api.github.com/repos/USERNAME/REPO_NAME/dispatches", true);
xhr.setRequestHeader("Accept", "application/vnd.github.v3+json");
xhr.setRequestHeader("Authorization", "Bearer GITHUB_ACCESS_TOKEN");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onload = function() {
if (xhr.status === 204) {
messageElement.textContent = "요청이 성공적으로 전송되었습니다." + xhr.status;
} else {
messageElement.textContent = "요청 전송에 실패했습니다.<br>상태 코드: " + xhr.status;
}
};
xhr.onerror = function() {
messageElement.textContent = "요청 전송 중 알 수 없는 오류가 발생했습니다.";
};
xhr.send(JSON.stringify({"event_type": "RUN_WORKFLOW_DISPATCH"}));
});
</script>
</body>
</html>
4-5. 배포버튼을 만들기 위해, 아래 링크 중 본인의 내용에 맞게 수정(아래 하이라이트 부분)한다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
.trigger-container {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.trigger-button {
display: inline-block;
margin-bottom: 10px;
padding: 10px 20px;
background-color: #4c9aff;
color: white;
font-size: 16px;
border: none;
cursor: pointer;
border-radius: 4px;
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.1);
transition: background-color 0.3s;
}
.trigger-button:hover {
background-color: #2e86ff;
}
.message {
font-size: 16px;
color: #333;
}
</style>
</head>
<body>
<div class="trigger-container">
<button id="triggerButton" class="trigger-button">UPLOAD</button>
<div id="message" class="message"></div>
</div>
<script>
document.getElementById("triggerButton").addEventListener("click", function() {
var messageElement = document.getElementById("message");
messageElement.textContent = "요청 전송 중...";
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://api.github.com/repos/USERNAME/REPO_NAME/dispatches", true);
xhr.setRequestHeader("Accept", "application/vnd.github.v3+json");
xhr.setRequestHeader("Authorization", "Bearer GITHUB_ACCESS_TOKEN");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onload = function() {
if (xhr.status === 204) {
messageElement.textContent = "요청이 성공적으로 전송되었습니다." + xhr.status;
} else {
messageElement.textContent = "요청 전송에 실패했습니다.<br>상태 코드: " + xhr.status;
}
};
xhr.onerror = function() {
messageElement.textContent = "요청 전송 중 알 수 없는 오류가 발생했습니다.";
};
xhr.send(JSON.stringify({"event_type": "RUN_WORKFLOW_DISPATCH"}));
});
</script>
</body>
</html>
4-6. 배포 버튼을 링크로 만들기 위해 아래HTML블록생성 링크로 접속한다.
https://www.notion-tools.com/embeds/html
4-7. 위 ‘4-5’에서 만든 코드를 넣고 링크를 생성한다.
4-8. 노션에서 /embed 를 검색해서 임베드 블록을 생성한다.
4-9. 위 ‘4-7’에서 생성한 링크를 임베드 해준다.
4-10. 생성된 배포 버튼(임베디드된 링크)
4-11. 업로드 버튼을 눌르면, 깃액션을 통해 봇으로 배포되는 것을 확인할 수 있다.
'Others > IT_ETC' 카테고리의 다른 글
[AI] LLM 모델 결과 비교하기 GPT VS Llama3 (1) | 2025.01.12 |
---|---|
[K8S] 쿠버네티스(K8S) 파드 확인 (0) | 2025.01.11 |
[NOTION] 노션 데이터베이스 API 연동 (0) | 2025.01.11 |
[ETC] 2023년 IT 트랜드 (1) | 2025.01.11 |
[KoGPT/AI/인공지능] KoGPT API 사용법, KoGPT API 사용, KoGPT API 사용하기, KoGPT API 사용, KoGPT API 사용, KoGPT API 사용하기, 카카오 AI, 카카오 AI 사용하기, 카카오 AI 사용, 카카오 GPT, 카카오 챗봇, 카카오 인공지능 (0) | 2025.01.11 |