Sponsored By
















※ 본 포스팅은 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. 업로드 버튼을 눌르면, 깃액션을 통해 봇으로 배포되는 것을 확인할 수 있다.









Sponsored By















+ Recent posts