github

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 30, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package github 은 GitHub REST API 로 리포지토리를 프로비저닝한다.

GitLab 어댑터와 두 가지가 근본적으로 다르다.

하나, 네임스페이스를 만들 수 없다. GitHub Organization 은 API 로 생성되지 않으므로 EnsureGroup 은 "확인"만 한다 — 없으면 사람이 먼저 만들어야 한다.

둘, 토큰을 발급할 수 없다. GitLab 은 프로젝트 범위 토큰 API 가 있지만 GitHub 에는 리포 단위 토큰이 없다. 대신 워크플로가 내장 GITHUB_TOKEN 을 쓰고, 클러스터 쪽(Argo CD·kubelet)은 스택에 등록된 PAT 를 재사용한다.

Index

Constants

View Source
const (
	// DefaultAPIBaseURL 는 github.com 의 API 주소다.
	// GitHub Enterprise Server 는 https://{host}/api/v3 형태를 쓴다.
	DefaultAPIBaseURL = "https://api.github.com"

	// GHCRHost 는 GitHub Container Registry 의 호스트다.
	GHCRHost = "ghcr.io"
)
View Source
const SecretProvider = "openbao"

SecretProvider 는 토큰을 보관하는 시크릿 백엔드다.

Variables

View Source
var ErrAccessTokenUnsupported = errors.New(
	"github 은 리포 범위 액세스 토큰 발급을 지원하지 않습니다")

ErrAccessTokenUnsupported 는 GitHub 에 리포 범위 토큰 발급 API 가 없음을 알린다.

GitLab 의 Project Access Token 에 대응하는 것이 GitHub 에는 없다. 워크플로는 내장 GITHUB_TOKEN 을 쓰고, 클러스터 쪽 인증은 스택에 등록된 PAT 를 재사용한다. 호출자가 이 오류를 보고 그 경로로 갈라져야 한다.

Functions

func TokenSecretPath

func TokenSecretPath(env, orgID string) string

TokenSecretPath 는 PAT 의 시크릿 경로다.

값을 기록하는 쪽은 stack 모듈(설치 마지막의 토큰 소스 등록)이다. 경로를 양쪽에 따로 적으면 한쪽만 바뀌어도 컴파일은 통과하고 런타임에 "등록된 토큰이 없다" 로만 드러나므로 공유 규약을 그대로 쓴다.

func WebBaseURLFor added in v0.6.0

func WebBaseURLFor(apiBaseURL string) string

WebBaseURLFor 는 API 주소에 대응하는 웹 주소다.

github.com 은 API 호스트가 따로 있고, GitHub Enterprise Server 는 같은 호스트의 /api/v3 아래에 API 가 있다.

Types

type BuildReader added in v0.6.0

type BuildReader struct {
	// contains filtered or unexported fields
}

BuildReader 는 GitHub Actions 워크플로 실행 이력을 읽는다.

스택의 파이프라인은 organization 아래 앱 이름의 리포에서 돈다. port.CIBuildReader 는 job 이름으로 묻기 때문에 소유자를 쥐고 리포를 찾는다.

func NewBuildReader added in v0.6.0

func NewBuildReader(client *Client, owner string) *BuildReader

NewBuildReader 는 owner 아래 리포의 실행 이력을 읽는 BuildReader 를 만든다.

func (*BuildReader) ArtifactWebURL added in v0.6.0

func (r *BuildReader) ArtifactWebURL(ref port.CIArtifactRef) string

ArtifactWebURL 은 실행 페이지 주소다. GitHub 은 산출물 파일 주소를 주지 않고, 실행 페이지가 산출물 목록을 보여 준다.

func (*BuildReader) ListBuilds added in v0.6.0

func (r *BuildReader) ListBuilds(ctx context.Context, jobName, branch string, limit int) ([]port.CIBuild, error)

ListBuilds 는 최근 워크플로 실행과 그 잡을 읽어 정규화한다.

리포가 없으면 빈 목록이다 — 실행 기록이 없는 것이지 오류가 아니다.

func (*BuildReader) ReadArtifact added in v0.6.0

func (r *BuildReader) ReadArtifact(ctx context.Context, ref port.CIArtifactRef) ([]byte, bool, error)

ReadArtifact 는 실행이 upload-artifact 로 남긴 묶음에서 파일 하나를 꺼낸다.

GitHub 은 산출물을 실행 안의 이름 붙은 zip 으로 보관한다. 보존 기간이 지나면 expired 가 되고, 그것은 없는 것과 같다.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client 는 port.SCMProvisioner 와 port.PipelineConfigurator 의 GitHub 구현체다.

func NewClient

func NewClient(baseURL, token string) *Client

NewClient 는 GitHub REST 클라이언트를 만든다.

baseURL 이 비면 github.com 을 쓴다. token 은 repo·workflow 스코프를 가진 PAT 다.

func (*Client) BaseURL

func (c *Client) BaseURL() string

BaseURL 은 이 클라이언트가 바라보는 API 주소다.

func (*Client) CommitFiles

func (c *Client) CommitFiles(ctx context.Context, projectID string, spec port.CommitSpec) error

CommitFiles 는 여러 파일을 한 커밋으로 올린다(upsert).

Contents API 를 파일마다 부르면 커밋이 파일 수만큼 생기고, Argo CD 가 그 중간 상태를 하나씩 동기화해 배포가 여러 번 일어난다. Git Data API 로 트리 하나를 만들어 커밋 하나로 밀어야 한다.

func (*Client) CreateProjectAccessToken

func (c *Client) CreateProjectAccessToken(
	_ context.Context,
	_ string,
	_ port.AccessTokenSpec,
) (string, error)

CreateProjectAccessToken 은 GitHub 에서 지원되지 않는다.

조용히 빈 문자열을 돌려주면 호출자가 자격증명 없이 Argo CD 를 구성해 동기화가 "authentication required" 로 실패한다. 명시적으로 알린다.

func (*Client) DeleteImageRepository

func (c *Client) DeleteImageRepository(ctx context.Context, target *port.ImageTarget) error

DeleteImageRepository 는 GHCR 패키지를 지운다.

리포지토리와 패키지는 GitHub 에서 별개 리소스다 — 리포를 지워도 패키지는 남는다. 경로도 다르다: 개인 계정은 /user/packages, 조직은 /orgs/{org}/packages.

PAT 에 delete:packages 스코프가 필요하다.

func (*Client) DeleteProject

func (c *Client) DeleteProject(ctx context.Context, projectID string) error

DeleteProject 는 리포지토리를 지운다.

이미 없으면 성공으로 본다 — 삭제의 목표는 "없는 상태" 이고, 404 를 오류로 올리면 앞선 시도가 절반쯤 성공한 뒤 재시도할 때 영영 끝나지 않는다.

PAT 에 delete_repo 스코프가 없으면 403 이 온다. 이 경우 GitHub 은 권한 부족을 알려주므로 오류를 그대로 올려 사용자가 스코프를 고칠 수 있게 한다.

func (*Client) EnsureGroup

func (c *Client) EnsureGroup(ctx context.Context, spec port.GroupSpec) (*port.SCMGroup, error)

EnsureGroup 은 소유자(Organization 또는 사용자 계정)가 존재하는지 확인한다.

만들지 않는다 — GitHub Organization 은 API 로 생성할 수 없다. 없는 소유자를 조용히 넘기면 리포 생성이 엉뚱한 네임스페이스로 흘러가므로 여기서 끊는다.

func (*Client) EnsureProject

func (c *Client) EnsureProject(ctx context.Context, spec port.ProjectSpec) (*port.SCMProject, error)

EnsureProject 는 리포지토리를 조회하고 없으면 만든다.

func (*Client) Ping

func (c *Client) Ping(ctx context.Context) error

Ping 은 현재 토큰이 실제로 인증되는지 확인한다.

보관된 PAT 는 사용자가 폐기하거나 만료될 수 있다. 쓰기 전에 확인하지 않으면 이후 모든 호출이 401 로 죽고 원인이 프로비저닝 실패처럼 보인다.

func (*Client) SetPipelineVariable added in v0.6.0

func (c *Client) SetPipelineVariable(ctx context.Context, projectID, key, value string) error

SetPipelineVariable 은 리포 Actions 변수(vars)를 만들거나 갱신한다.

시크릿이 아니라 변수다. 워크플로가 ${{ vars.X }} 로 읽으므로 시크릿에 넣으면 빈 값이 되고, 정책 같은 비밀 아닌 값이 로그에서 *** 로 가려진다. 변수 API 에는 upsert 가 없다. POST 로 만들고 이미 있으면(409) PATCH 한다.

func (*Client) SetProjectVariable

func (c *Client) SetProjectVariable(ctx context.Context, projectID string, v port.ProjectVariable) error

SetProjectVariable 은 Actions 시크릿을 등록하거나 이미 있으면 갱신한다.

GitHub 은 평문 시크릿을 받지 않는다. 리포의 공개키를 받아 libsodium sealed box 로 암호화한 값만 올릴 수 있다 — 평문으로 PUT 하면 400 이 난다. PUT 자체가 upsert 라 GitLab 처럼 POST→PUT 폴백이 필요 없다.

func (*Client) WithHTTPClient

func (c *Client) WithHTTPClient(h *http.Client) *Client

WithHTTPClient 는 타임아웃·전송 계층을 교체한다.

type SecretStore

type SecretStore interface {
	GetTokenForStack(ctx context.Context, provider, stackID, path string) (string, error)
}

SecretStore 는 토큰 조회에 필요한 최소 동작만 노출한다.

다른 모듈의 동일 타입을 재사용하지 않는다 — 모듈 간 직접 import 를 피하기 위해 CI/CD 컨텍스트가 자기 계약을 소유한다.

type TokenIssuer

type TokenIssuer struct {
	// contains filtered or unexported fields
}

TokenIssuer 는 보관된 GitHub PAT 를 돌려준다.

이름은 GitLab 쪽과 맞췄지만 실제로 발급하지는 않는다 — GitHub 은 SaaS 라 우리가 토큰을 만들 수 없다. 사용자가 등록한 PAT 를 읽는 것이 전부이며, 그래서 Force 재발급도 의미가 없다(만료·폐기되면 사람이 다시 등록해야 한다).

func NewTokenIssuer

func NewTokenIssuer(secrets SecretStore) *TokenIssuer

NewTokenIssuer 는 TokenIssuer 를 만든다.

func (*TokenIssuer) EnsureToken

func (t *TokenIssuer) EnsureToken(ctx context.Context, spec port.SCMTokenSpec) (string, error)

EnsureToken 은 보관된 PAT 를 돌려준다.

없으면 새로 만들지 않고 실패한다 — 조용히 빈 토큰으로 진행하면 리포 생성이 401 로 죽고, 오류가 프로비저닝 버그처럼 보여 원인을 찾기 어렵다.

type WorkflowTrigger added in v0.6.0

type WorkflowTrigger struct {
	// contains filtered or unexported fields
}

WorkflowTrigger 는 port.CIBuildTrigger 의 GitHub Actions 구현체다.

스택에 묶인 파이프라인의 "실행" 은 플랫폼이 빌드하지 않고 CI 에 넘긴다. GitHub Actions 는 push 가 있을 때만 돌므로, 커밋 없이 지금 실행하려면 workflow_dispatch 로 시작시켜야 한다 — 스캐폴딩이 워크플로에 그 트리거를 둔다.

func NewWorkflowTrigger added in v0.6.0

func NewWorkflowTrigger(client *Client, owner, workflowFile string) *WorkflowTrigger

NewWorkflowTrigger 는 owner 아래 리포의 workflowFile(.github/workflows/ 안의 파일 이름)을 시작시키는 트리거를 만든다.

func (*WorkflowTrigger) TriggerBuild added in v0.6.0

func (t *WorkflowTrigger) TriggerBuild(ctx context.Context, jobName, branch string) (string, error)

TriggerBuild 는 jobName(리포)의 branch 에서 워크플로를 시작시키고 실행 주소를 돌려준다.

그 브랜치의 최신 실행이 아직 돌고 있으면 새로 시작하지 않고 그 실행에 붙는다. 화면은 파이프라인을 만든 직후 "실행" 을 한 번 더 부르는데, 스캐폴딩 커밋의 실행과 겹치면 같은 커밋의 배포 잡 둘이 되커밋을 밀어 둘째가 실패한다(워크플로의 concurrency 는 취소하지 않고 직렬화하므로 둘 다 끝까지 돈다).

func (*WorkflowTrigger) WithWebBaseURL added in v0.6.0

func (t *WorkflowTrigger) WithWebBaseURL(base string) *WorkflowTrigger

WithWebBaseURL 은 실행 링크에 쓸 웹 주소를 정한다.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL