สวัสดีผู้อ่านทุกท่านครับ สำหรับเนื้อหานี้เกิดจากความอยากรู้อยากลองของผมล้วนๆเลย อยากจะแยกส่วนของเนื้อหาของเว็บออกไปเก็บไว้เป็น private repository แต่ก็อยากให้ทุกครั้งที่อัพเดทเนื้อหาใหม่ขึ้นไป ก็อยากให้ trigger ไปยัง action บน repository เพื่อทำการ build & deploy ด้วย
ฟังดูวุ่นวายจัง จะเริ่มยังไงดี ?
หลังจากนอนคิดสัก 3 ชั่วโมงก็พบว่า… หลับครับ แต่ก่อนหลับก็ได้คำตอบว่าสิ่งที่ควรจะทำมีประมาณนี้
จากภาพ เมื่อมี 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 ด้วย
สร้าง 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 ครั้งตามที่ได้เขียนไว้
ขอบคุณทุกท่านที่เข้ามาอ่าน แล้วพบกันใหม่ในครั้งต่อไปครับ