Skip to content

แยก repository ไฟล์ content ออกจาก framework

Published
 at 05:00 AM

By : Parinya T. | 3 min read

สวัสดีผู้อ่านทุกท่านครับ สำหรับเนื้อหานี้เกิดจากความอยากรู้อยากลองของผมล้วนๆเลย อยากจะแยกส่วนของเนื้อหาของเว็บออกไปเก็บไว้เป็น private repository แต่ก็อยากให้ทุกครั้งที่อัพเดทเนื้อหาใหม่ขึ้นไป ก็อยากให้ trigger ไปยัง action บน repository เพื่อทำการ build & deploy ด้วย

ฟังดูวุ่นวายจัง จะเริ่มยังไงดี ?

หลังจากนอนคิดสัก 3 ชั่วโมงก็พบว่า… หลับครับ แต่ก่อนหลับก็ได้คำตอบว่าสิ่งที่ควรจะทำมีประมาณนี้

Blog Image

จากภาพ เมื่อมี commit ใหม่บน content repository จะมีการ Trigger ไปยัง action บน main repository ให้ทำการ sync & pull ทั้งจาก content และ media เกิดเป็น commit ใหม่บน repository ซึ่งจะทำให้ build & deploy action ทำงาน

Table of contents

Show all topics

แยก repository ส่วนของเนื้อหา ออกจาก framework

ผมทำการสร้าง repository ขึ้นมาใหม่เป็น private โดยแยกทั้งสองออกจากกัน repository แรกเอาไว้เก็บเนื้อหาบล็อกทั้งหมด และอีกอันเอาไว้เก็บไฟล์รูป โดยที่ทั้งสอง repo นั้นยังคง files structure ไว้เช่นเดียวกับตอนก่อนแยกไฟล์

จากนั้นลบโฟลเดอร์และไฟล์ทั้งหมดออกจาก repository หลักและทำการ commit ขึ้นไปก่อน เนื่องจากเราจะใช้ git submodule เพิ่มเข้ามาใหม่ (ตอนแรกผมไม่ได้ทำก่อนแล้วมัน conflict กันตอนเปิด pull request)

จากนั้น เปิด terminal บน directory ที่ต้องการ clone repository จากนั้นก็ทำการ clone ผ่านคำสั่ง

git submodule add -f [url] [folderName]

หมายเหตุ [url] กับ [folderName] ให้เปลี่ยนโดยไม่ต้องใส่ [] นะครับ และระวังการใช้ -f (force) ด้วยนะครับ อาจจะส่งผลในกรณีที่ใน directory มีไฟล์อื่นๆอยู่แล้ว

หากใครต้องการให้ submodule อัพเดททุกครั้งที่มีการ git pull อย่าลืมใส่คำสั่ง (ใส่แค่ครั้งแรกที่ทำ submodul ก็พอ)

git submodule update --init --recursive

ในส่วนของไฟล์รูปผมก็ทำเหมือนกัน ต่างกันเพียง directory เท่านั้น

จะเห็นว่าที่ repo หลักจะมีไฟล์ .gitmodule เพิ่มขึ้นมาพร้อมกับโค้ดประมาณนี้

[submodule "src/content/blog"]
	path = src/content/blog
	url = https://github.com/pickyzz/blog-posts
[submodule "public/assets/images"]
	path = public/assets/images
	url = https://github.com/pickyzz/blog-images

สังเกตว่า url จะเป็นคนละชื่อกับ path และ submodule เนื่องจากการใส่พารามิเตอร์ในส่วน [folderName] นั่นเอง

หมายเหตุ จะมีจุดให้ปวดหัวนิดหน่อยตอน push ผ่าน submodule ซึ่งผมเองก็เจอปัญหาตรงนี้นิดหน่อย ซึ่งการแก้ก็จะต่างกันออกไป ตรงนี้ไม่สามารถรับประกันได้ว่าจะราบรื่นไปตลอดนะครับ

เพิ่มขั้นตอนบนไฟล์ github action

เมื่อเรามี submodule แล้วเราจำเป็นต้องเพิ่มขั้นตอนระหว่างการ build ด้วย เพราะ action จะไม่โหลดโมดูลให้อัตโนมัติ

โดยทำการเพิ่ม parameter เข้าไปที่ขั้นตอน checkout ดังนี้

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read

    steps:
      - uses: actions/checkout@v3
        name: "Checkout Source Code"
        with:
          submodules: true
          token: ${{ secrets.GH_TOKEN }}

      - [other Step]...

อ้างอิงจาก actions/checkout

เพิ่มเติม ในการทดสอบครั้งแรกพบว่า action หา private repository ไม่เจอ จึงหาข้อมูลเพิ่มเติมพบว่าใน github issue แนะนำให้เพิ่ม contents: read ในส่วนของ permissions ตามโค้ดด้านบน และอย่าลืมตั้งค่า private repository เพื่อ allow access ด้วย

Blog Image Blog Image

สร้าง github action ให้อัพเดท submodule อัตโนมัติ

ผมจะยังคงให้ build action ทำงานทุกครั้งที่มีการ commit ใหม่ แต่ว่าผมจะคั่นกลางด้วยการอัพเดท submodule และ push commit ขึ้นไปใหม่โดยอัตโนมัติ จากเดิมที่เราต้องมาทำเองในโฟลเดอร์หลักของเว็บ เราก็ให้ action จัดการตรงนี้แทนเสียเลย

โดยผมจะแยก action ออกเป็นคนละไฟล์กับ build & deploy action และให้ทำงานจากการ trigger จาก action ใน content repository โดยจะเขียน action ยิงมาจาก content repo เพิ่มภายหลังเพื่อไม่ให้สับสนขั้นตอน

สาเหตุที่แยกออกมานั้น เพราะ build & deploy จะทำงานเมื่อมี commit ใหม่ ถ้าไปเช็คตรงนั้นมันจะเป็นการวนซ้ำ action เดิมสองรอบ ถึงจะไม่มี commit ใหม่แล้วแต่มันก็กินเวลา เขียนแยกไว้น่าจะดีกว่า

name: Submodule update check

on:
  workflow_dispatch:

jobs:
  update:
    runs-on: ubuntu-latest
    permissions:
      contents: read

    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
          token: ${{ secrets.GH_TOKEN }}

      - name: Pull & update submodules recursively
        run: |
          git submodule update --init --recursive
          git submodule update --recursive --remote

      - name: Commit
        run: |
          git config --global user.name 'Git bot'
          git config --global user.email '[email protected]'
          git add --all
          git remote set-url origin https://x-access-token:${{ secrets.GH_TOKEN }}@github.com/${{ github.repository }}
          git commit -am "Auto updated submodule references" && git push || echo "No changes to commit"

อ้างอิงจาก ที่พึ่ง dev ยามยาก

ทำ Trigger action ข้าม repository

จากนั้นก็จัดการเขียน workflow โดยให้ทำงานทุกครั้งที่มี commit ใหม่บน content repository ให้ทำการสะกิดข้าม repo ไปยัง build action ตามที่คิดไว้ (repo เก็บรูปไม่ต้องทำ เพราะปกติจะอัพรูปก็ต้องทำพร้อมกับการเขียนเนื้อหา หรือไม่ก็อัพเดท ui อยู่แล้ว)

name: trigger build action
on:
  push:

jobs:
  build:
    runs-on: self-hosted
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          path: main

      - uses: convictional/[email protected]
        with:
          owner: pickyzz
          repo: blog-rebuild
          github_token: ${{ secrets.GH_TOKEN }}
          workflow_file_name: submodule.yml

หมายเหตุ เนื่องจากส่วนนี้ผมได้ทำการ selfhost action runner ต่างหากเอง ทำให้ผมใช้ runs-on: self-hosted หากต้องการใช้ runner ของทาง github สามารถใช้ runs-on: ubuntu-latest ได้ตามปกติ แต่จะมีการจำกัดการใช้งานบน private repository

สรุป

workflow ทั้งหมดนั้นสามารถทำงานได้ปกติ จะมีติดขัดช่วงการ push commit ในครั้งแรกๆที่ทำ submodule เล็กน้อย ซึ่งการแก้ไขก็คือให้ทำการลบไฟล์บน directory นั้นแล้ว commit ขึ้น repository ไปก่อน 1 ครั้งตามที่ได้เขียนไว้

ขอบคุณทุกท่านที่เข้ามาอ่าน แล้วพบกันใหม่ในครั้งต่อไปครับ

references