TIE_golang_syntax error && "gitlab_ci.yaml error"

kyoungyeon·2025년 7월 11일
0

TIL

목록 보기
125/129

syntax error

  • pipeline 이 에러가났는데 2개 파일이 다 확인 필요했음

main.go 파일의 문제인지

1> gotodot vs Getenv

debuging section 중요성

  • .env 파일이 로컬에 있다보니 dev 환경에선 그대로 파일을 읽느냐
  • gitlab PR시 gitignore로 인해 test, deploy 환경이니 ci/cd variables에 api-key연동을 해서 어떻게 읽느냐 에 따라 쓰는 메소드가 다름
go env                    # 모든 Go 환경 변수 출력
go env GOPATH            # 특정 환경 변수 확인
go env GOOS GOARCH       # 여러 변수 동시 확인

# 주요 Go 환경 변수들
GOROOT=/usr/local/go     # Go 설치 경로
GOPATH=/home/user/go     # 워크스페이스 경로
GOOS=linux               # 운영체제
GOARCH=amd64             # 아키텍처

아무튼 ..

Usage

  • godotenv (외부 패키지) <- 처음엔 바이브 코딩으로 추천되는 라이브러리 써봄
  • 위 경우 로컬환경에서 .env 파일을 읽어서 환경 변수로 로드하는 패키지임
import (
    "fmt"
    "log"
    "os"
    
    "github.com/joho/godotenv"
)


func main() {
    // .env 파일 로드
    err := godotenv.Load()
    if err != nil {
        log.Fatal("Error loading .env file")
    }
    
    // 환경 변수 읽기
    apiKey := os.Getenv("API_KEY")
    fmt.Println("API Key:", apiKey)
}
  • 환경체크를 하는게 중요했음
func loadConfig() {
    // .env 파일 로드 시도 (실패해도 괜찮음)
    if err := godotenv.Load(); err != nil {
        log.Println("Note: .env file not found, using system environment variables")
    }
}


    // 필수 환경 변수 확인
    config := &Config{
        APIKey:      os.Getenv("API_KEY"),
        DatabaseURL: os.Getenv("DATABASE_URL"),
        Port:        getEnvOrDefault("PORT", "8080"),
        Environment: env,
    }
    
    // 유효성 검사
    if config.APIKey == "" {
        return nil, log.Fatal("API_KEY environment variable is required")
    }
    
    if config.DatabaseURL == "" {
        return nil, log.Fatal("DATABASE_URL environment variable is required")
    }
    
    return config, nil
}

func getEnvOrDefault(key, defaultValue string) string {
    if value := os.Getenv(key); value != "" {
        return value
    }
    return defaultValue
}

Wrong syntax

// ❌ 잘못된 방법 - os.Getenv는 에러를 반환하지 않음
err := os.Getenv("API_KEY")  // 컴파일 에러!
// 아래와 같이 쓴다고함
apiKey := os.Getenv("API_KEY")
if apiKey == "" {
    log.Fatal("API_KEY is required") } //종료
    

둘 다 쓴 이유

coverage 차이

  • godotenv.Load(): .env 파일을 읽어서 환경 변수로 로드 (로컬 개발용)
  • os.Getenv(): 환경 Variables 값 읽기 (로컬/배포 공통) , go 내장 함수임.

에러 처리 방식이 다름

  • godotenv.Load()는 에러 반환
  • os.Getenv()는 빈 문자열 반환 (이것도 디버깅때 오히려 주의)
    • 즉 에러를 반환하지 않아서 컴파일 에러남.

제한사항

  • GitLab Variables로 환경 변수 설정, .env 파일 없음
fmt 말고 log 쓰기!

확인차 log 메소드를 쓰는데 (stdout+timestamp)가 로그로 나오기에 좀 더 디버깅을 gitlab CI 툴에서 보기 편하다

output

2> fmt, log 작동 비교

    A[Go 애플리케이션] --> B{출력 방식}
    B --> C[fmt.Println]
    B --> D[log.Println]
    
    C --> E[stdout만 출력]
    D --> F[stdout + 타임스탬프]
    
    E --> G[GitLab CI 로그]
    F --> H[GitLab CI 로그<br/>+ 시간 정보]
    
편리성

// log.Printf - 타임스탬프와 함께 출력
if err != nil {
    log.Printf("오류 발생: %v", err)
    // 프로그램은 계속 실행됨
}

// log.Fatalf - 로그 출력 후 프로그램 종료
if err != nil {
    log.Fatalf("치명적 오류: %v", err)
    // 프로그램이 즉시 종료됨 (os.Exit(1)과 동일)
}
가용성
  • custom log
// 기존 방식
if err != nil {
    log.Fatal("환경변수 로드 실패:", err)  // 형식이 불일치
}

// 개선된 방식  
if err != nil {
    log.Fatalf("❌ 환경변수 로드 실패: %v", err)  // Printf 형식으로 통일
}

그외 질문

  • 코드 짤때 개발/배포 환경마다 좀 미묘하게 코드가 달라져서 고민됬는데
    = 코드는 하나로 통일하고 환경만 다르게 설정하는 게 맞습니다. 라고 답변받음..

gitlab_ci.yml 파일의 문제인지

yaml 문법 오류

gitlab이 yaml lint가 빡세다

  • 스페이스를 조심하라
    • tab도 최대한 지양하자..

Err

`.gitlab-ci.yml`: (): did not find expected alphabetic or numeric character while scanning an anchor at line 33 column 32`

error_code

- [ -z "$NOTION_API_KEY" ] && echo "❌ API KEY 비어 있음" && exit 1

anchor syntax

# 올바른 앵커 사용법
default: &default_config
  timeout: 30
  retries: 3

job1:
  <<: *default_config  # 앵커 참조

Err 무한

jobs:daily-notion-tasks:script config should be a string or a nested array of strings up to 10 levels deep 뭘까?

진짜 뭔가했는데

  • gitlab yaml은 list _literal을 안받아들이고 fail 처리함
//대안 1 따옴표 
  - '[ -z "$NOTION_API_KEY" ] && echo "❌ API KEY 비어 있음" && exit 1'
// 대안 2 쉘스크립트 치환
 - |
      if [ -z "$NOTION_API_KEY" ]; then
        echo "❌ API KEY 비어 있음"
        exit 1
      fi

[ -z "$NOTION_API_KEY" ] && … 처럼 대괄호로 시작하면 YAML 은 리스트 리터럴 ([ a, b, c ]) 로 착각해-버립니다.

알게된 점

  • |(스칼라 블록) 다음에 들여쓴 부분은 하나의 문자열(쉘 스크립트)로 취급됩니다.
  • | 블록 안은 순수 문자열이므로 YAML 입장에서 배열/맵이 포함되지 않습니다.

err

jobs:daily-notion-tasks:script config should be a string or a nested array of strings …
  • 스페이스를 빠트리면? 위 에러 또 난다.. 
 //틀림 
 if [-z "$NOTION_API_KEY" ] || [ -z "$NOTION_DATABASE_ID" ]; then
// 맞음
 if [ -z "$NOTION_API_KEY"] || [-z "$NOTION_DATABASE_ID"]; then

분석사유

  • multi-line 스칼라(|) 블록 안의 조건문에서
    if [ -z … ] 앞뒤 공백이 빠져 if [-z …] 로 써 있었습니다.
  • YAML 파서는 [‐z 를 시작 대괄호가 있는 리스트 리터럴로 오해해 “script 안에 배열이 또 들어 있음” → 위 오류로 이어졌습니다.

근데 또 같은 err

jobs:daily-notion-tasks:script config should be a string or a nested array of strings…
  • 멀티 라인 포기함
    • 앞서 멀티라인 블록(|)을 넣으면서 YAML 파서가 배열 안에 또 배열이 있다고 착각했습니다.
  • 대안
    • 멀티라인 블록을 한 줄짜리 쉘 명령으로 변경
    • 기존 rules: 항목 들여쓰기와 조건식을 따옴표로 감싸 YAML 파싱 위험 제거
 rules:
    - if: '$CI_PIPELINE_SOURCE == "trigger"'  # API 트리거
    - if: '$CI_PIPELINE_SOURCE == "web"'      # 수동 실행

그래도 fail..

  • GitLab CI가 script 배열을 제대로 파싱하지 못하는 문제
  • 가능한 원인들:
    GitLab 버전과 YAML 파서의 호환성 문제
    특정 문자나 패턴이 GitLab CI 파서를 혼동시킴

=> 단순화 시킴

  • rule을 only
  • 이모지 제거 - 일부 GitLab 버전에서 문제 발생 가능
  • before_script 사용 - 환경변수 검증을 별도 섹션으로 분리
  • 따옴표 제거 - 단순 명령어는 따옴표 없이 사용
  • job 이름 단순화 - 특수문자 없는 단순한 이름 사용
image: golang:1.21

stages:
  - build
  - deploy

build:
  stage: build
  script:
    - go mod download
    - go build -o scheduler main.go
  only:
    - main

deploy:
  stage: deploy
  before_script:
    - echo "Checking environment variables"
    - test -n "$NOTION_API_KEY" || (echo "Missing NOTION_API_KEY" && exit 1)
    - test -n "$NOTION_DATABASE_ID" || (echo "Missing NOTION_DATABASE_ID" && exit 1)
  script:
    - go mod download
    - go build -o scheduler main.go
    - ./scheduler --now
  only:
    - triggers
    - web
    - main
  artifacts:
    paths:
      - scheduler
  • main PR == notion 자동화 되도록 설정완료

그외

yaml expansion 문법
${변수명:시작위치:길이}

${NOTION_API_KEY:0:10}
# NOTION_API_KEY의 0번째부터 10글자만 출력
# 예: "secret_abc123xyz" → "secret_abc"
# 전체 노출 (위험)
echo "API Key: $NOTION_API_KEY"
# 출력: API Key: secret_abc123xyz789

# 일부만 노출 (안전)
echo "API Key: ${NOTION_API_KEY:0:10}..."
# 출력: API Key: secret_abc...

비교

yaml

  • 참고로 순수 yaml 에서는 syntax error 없음
script:
  - echo "test"
  - [ -z "$VAR" ] && echo "error"  # 문법적으로 유효

GitLab CI는 script 배열의 각 요소가 문자열이어야 함

  • [ 로 시작하면 리스트로 해석해서 "배열 안에 배열" 에러

  • GitLab CI는 순수 YAML보다 엄격함

  • 특수문자([, &, |)는 따옴표로 감싸기

  • 디버깅은 단계별로: CI → 애플리케이션 → API

  • 보안: 민감한 정보는 일부만 로그에 출력

profile
🏠TECH & GOSSIP

0개의 댓글