go mod private library
เมื่อเราเขียน go หลายๆ services ก็เริ่มมีของหลายอย่างที่แสดงตัวว่าสามารถแยกออกมาเป็น library ได้ แต่เนื่องจากบางครั้งเราทำงานใน enterprise ที่เป็นระบบปิด ซึ่งอาจจะพบปัญหาในการแยก library โดยเฉพาะกับ go เนื่องจากคำสั่ง go get นั้น ใช้ git จัดการอยู่เบื้องหลัง
วันนี้จึงมาเล่าประสบการณ์การทำ private library ร่วมกับการใช้ go mod ว่าจะมีวิธีทำอย่างไร ซึ่งผมขอแยกเล่าระหว่าง version v0.0.0 และ v2.0.0 โดยข้าม v1.0.0 ไป เพราะผมงง 555 และทำด้วย gitlab ที่ตั้งภายในบริษัทนะครับ
library version v0.0.0
version นี้ง่ายมาก ให้แยก repo ออกมาได้เลย โดยไม่ต้องมี go.mod อยู่ใน repo นั่นแปลว่า repo นี้ไม่ได้ใช้ go module และไม่ต้องติด tag ด้วย ขอยกตัวอย่างชื่อ repo ว่า odds.com/go/log
ทีนี้เวลาเราจะ import เจ้าตัวนี้เข้าไปใช้ มันจะยุ่งๆนิดนึง ซึ่งอาจจะต้องดูว่า git server ของเรามันตั้ง security ไว้มากเกินไปหรือเปล่าด้วย และใช้ protocol อะไร
สมมุติว่าแก้ปัญหาเหล่านั้นได้แล้ว เวลาจะเขียนโค้ดให้ import แบบนี้ครับ
import "odds.co/go/log.git"
มันจะต้องมี .git
ด้วยนะ ซึ่งเมื่อเราใช้ go mod จะเห็นว่ามัน require ของหน้าตาประมาณนี้
require (
odds.com/go/log.git v0.0.0-20190221033752-642ee591bac3
)
มันจะเห็นเป็น version v0.0.0 เอง แล้วแปะท้ายมาด้วยวันที่และเลข commit
library vesion v2.0.0
ไอ้ตัวนี้เริ่มต้องทำ go module ละครับ ซึ่งผมจะเริ่มด้วยการไป git tag ไอ้ตัวเดิมไว้ก่อน ซึ่งผมสั่งมันว่า
git tag v1.0.0
นั่นแหล่ะครับ ไอ้เจ้า v0.0.0 ของผมมันเลยได้ v1.0.0 ไปตอนนี้ และผมเลยข้ามมันไป เอาละ เราต้องมาทำ go module ให้มันละ ซึ่งผมเจาะจงชื่อมันแบบนี้เลยครับ
go mod odds.com/go/log/v2
หลังจากนั้นเราจะได้ไฟล์ go.mod ที่มีหน้าตาแบบนี้ครับ
module odds.com/go/log/v2
จากนั้นผมก็ติด tag ให้มันแบบนี้
git tag v2.0.0
ซึ่งปกติการที่ version จะวิ่งด้วยเลขหน้า จะหมายถึงมันเปลี่ยนไปจนคนที่เคยใช้ version ก่อนหน้านี้จะไม่สามารถใช้ได้อีก เราถึงจะเปลี่ยนเลข version ตัว major ครับ
แต่เราสมมุติเหตุการณ์ว่ามันเปลี่ยนจริงๆ ที่นี้เราก็ push มันขึ้นไปรอไว้ครับ
git push origin master
git push --tags
เอา tag ขึ้นไปด้วยนะครับ
ทีนี้คนที่เคยเรียก v0.0.0 จะมาเรียก v2.0.0 วิธีง่ายสุด ผมก็ไปแก้ตอนที่ import เป็นแบบนี้ครับ
import "odds.co/go/log.git/v2"
แต่เรายังเรียกใช้ของแบบเดิมนะครับ เช่นเคยเรียก log.Println ก็ยังคงเดิม แค่นี้ก็สามารถใช้งานได้แล้ว
สำหรับคนที่มีปัญหาเรื่อง net ในบริษัท ว่าถ้าจะออก internet ต้องสลับ wifi อะไรทำนองนี้ อาจจะติดปัญหาว่าถ้าจะ get lib ข้างในก็จะติดว่า get lib ข้างนอกไม่ได้ ก็ให้ใช้ go get
แก้ปัญหาก่อน ซึ่งเมื่อเราใช้ go module คำสั่ง go get จะทำงานสอดคล้องกับ go module เองครับ
go get odds.co/go/log.git/v2
สั่งแบบนี้ตอนที่ต่อ net ภายในก่อนครับ แล้วค่อยสลับไป net นอก แล้วลอง go run
ดู น่าจะไม่ติดปัญหาอะไรแล้ว
ส่วนคนที่ติดปัญหาเรื่อง git protocol แบบที่ผมเจอ ก็ลองบังคับ git ให้ไปใช้ ssh แทนด้วยคำสั่งแบบนี้ครับ
git config --global url."git@odds.com:".insteadOf "https://odds.com"
คิดว่าน่าจะเป็นประโยชน์นะครับ