23년 7월 GitHub은 저장소에 적용할 수 있는 저장소 규칙(Repository Rules) 기능을 정식으로 공개했다.
협업하다 보면 다양한 일이 있기 때문에 저장소를 보호하는 정책이 필요한 경우가 생긴다. 이런 목적으로 보통 Branch protection rule를 사용한다.
Branch protection rule을 사용하면 특정 브랜치에 커밋이 푸시되기 전에 force push를 막는다거나 Pull Reqeust에서 코드 리뷰를 일정 수 이상해야 한다거나 특정 CI 검사가 통과해야 하는 등 팀에서 협업하는 데 합의한 조건을 실수로 위반하지 않게 조건을 걸 수 있다.
이 Branch protection rule을 사용하면 브랜치를 원하는 대로 관리할 수 있다. 오픈소스 저장소나 작은 팀에서는 큰 문제가 없지만 회사의 규모가 커지면 Branch protection rule만으로는 부족함을 느낄 수밖에 없다. 각 브랜치에서 설정해야 하므로 조직 차원에서 일관된 정책을 사용할 수 없게 된다. 예를 들어 프로덕션에 나가기 전에는 라이센스와 보안 검사를 하고 테스트를 돌려봐야 한다는 정책을 정한다고 하더라도 각 팀에 Branch protection rule을 설정해 달라고 안내할 수는 있지만 이를 강제할 방법은 없었다.(물론 API로 모든 저장소에 설정을 검사한다거나 하면 불가능하진 않겠지만...)
저장소 규칙(Repository Rules)
Repository Rules는 이러한 문제를 해결하고 조직 내 모든 저장소에 대한 규칙을 한 곳에서 통합해서 관리할 수 있도록 나온 기능으로 회사 내 모든 저장소에 대한 거버넌스를 쉽게 할 수 있다.
org의 Settings 메뉴에서 Repository 하위에서 Rulesets라는 메뉴를 볼 수 있다. 참고로 위 메시지에 나온 대로 Ruleset을 저장소에 강제 규칙으로 만들려면 계정을 GitHub Enterprise로 업그레이드해야 한다. 아무래도 이러한 규칙을 조직 단위로 쓰려는 요구사항 자체가 회사에서 보통 있기 마련이라서 GitHub Enterprise에서만 된다는 건 큰 문제는 아닐 것으로 보인다.
Rulset은 브랜치, 태그, 푸시에 대해서 만들 수 있는데 여기서는 브랜치에 대해서 만들어 보자. 각 성격에 따라 강제할 수 있는 규칙이 다를 뿐 크게 다르지 않다.
브랜치 규칙 세트(Branch Ruleset)
당연히 Ruleset의 이름을 정하고 Enforcement status에서는 규칙을 활성화하면 저장소 브랜치에 규칙이 바로 적용된다. 보통은 적용할 때 테스트가 필요하므로 Enterprise 플랜을 사용한다면 Evaluate를 선택해서 규칙을 강제하지 않고 Rule insights에서 적용 상태를 보는 것만도 가능하다.
그 아래는 Bypass list를 설정할 수 있다. 어떤 규칙이든 반드시 예외 사항은 필요하기 때문에 해당 규칙을 무시할 수 있는 목록을 설정할 수 있다.
여기서 어드민 역할이나 저장소의 할당된 역할을 Bypass 목록에 추가할 수도 있고 해당 조직에서 사용하는 팀이나 앱을 지정하는 것도 가능하다. 이렇게 추가한 Bypass 목록은 항상 허용할지 Pull Request에서만 허용할지도 지정할 수 있다.
이제 해당 Ruleset을 적용할 대상을 지정할 차례이다. 대상은 저장소나 브랜치를 대상으로 지정할 수 있다.
대상은 모든 저장소, 이름 기반의 동적 리스트, 프로퍼티 기반 동적 리스트, 선택한 저장소로 지정할 수 있다. 여기서 사실 나는 프로퍼티 기반 동적 리스트(Dynamic list by property)만 유용할 것으로 생각한다.
모든 저장소에 하는 것은 규칙이 너무 강해서 쉽지 않고 특정 저장소만 고르는 것은 작은 조직에서는 가능하지만, 시간이 지나면서 저장소가 계속 늘어날 텐데 관리하기가 쉽지 않아 보인다. 그리고 이름 기반의 동적 리스트는 저장소 이름을 패턴으로 지정할 수 있는데 회사에서 저장소 이름의 규칙을 지정해서 만들도록 하는 것은 전혀 가능해 보이지 않는다. 이름을 규칙에 따라 만들게 할 수 있다면 이런 Ruleset도 필요 없이 그냥 각 저장소에 설정할 규칙도 만들 수 있지 않나 싶다.
그래서 프로퍼티 기반 동적 리스트(Dynamic list by property)만 남게 되는데 여기서 프로퍼티라는 것은 전에 GitHub 저장소의 메타데이터를 관리할 수 있는 Custom Properties 설명했던 저장소의 메타데이터를 지정하는 기능이다. 각 저장소의 담당 팀이나 티어, 서비스 종류나 성격 등을 메타데이터로 지정할 수 있는 기능인데 이 메타데이터에 기반해서 타겟을 지정할 수 있기 때문에 가장 유연하고 관리하기가 좋아 보인다.
타겟 종류를 선택하면 포함 규칙과 제외 규칙을 지정할 수 있다.
타켓을 추가할 때는 미리 만들어 놓은 Custom Property를 기반으로 대상을 설정할 수 있다. 실제로 사용한다면 다양한 고민이 필요하겠지만 프로퍼티를 잘 설정해 두었다면 다양한 조합으로 대상을 지정할 수 있다.
저장소의 브랜치에 대해서도 기본 브랜치에만 적용할지 모든 브랜치에 적용할지를 선택할 수 있고 패턴으로 지정하면 releases/**/*
같은 패턴으로도 지정할 수 있다. 회사에 어느 정도 브랜치 관례가 있다면 개발용 브랜치와 릴리스용 브랜치에 대해 다른 규칙을 적용하는 것도 가능하다.(여기선 크게 상관없지만 나는 릴리스 브랜치가 따로 있는 걸 좋아하진 않는다.)
이제 대상이 된 저장소 브랜치에 규칙을 지정할 수 있다. 일렬로 된 히스토리만 허용하거나 서명한 커밋만 받거나 Pull Request에서 반드시 통과해야 할 상태 검사를 하는 등의 규칙이 가능하다.
마지막으로 제약사항을 추가할 수 있다. 패턴 매칭으로 특정 커밋 메시지를 강제하거나 커밋의 회사 이메일 주소만 허용하거나 브랜치 이름 규칙을 강제하는 등의 조건을 지정할 수 있다.
규칙을 적용하면 커밋이나 브랜치를 푸시할 때 Git 차원에서 오류가 나면서 푸시 자체가 막히게 되어 있어서 조직 내 정책을 훨씬 쉽게 관리하고 적용할 수 있다. Tag Ruleset과 Push Ruleset도 적용할 규칙만 달라질 뿐 기능은 동일하게 사용할 수 있다.
GitHub에서 저장소 관리에 대한 고민도 꽤 많았는데 상당히 반가운 기능이다.
Comments