Skip to content

Commit 742074a

Browse files
authored
Merge pull request #28 from Interhyp/org-specific-user-suffix
feat: allow for organization-specific memberSuffixes
2 parents 233e431 + 7e6c7d6 commit 742074a

8 files changed

Lines changed: 314 additions & 6 deletions

File tree

api/v1alpha1/applyconfiguration/api/v1alpha1/organizationspec.go

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1alpha1/organization_types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,14 @@ type OrganizationSpec struct {
365365
// +optional
366366
Location string `json:"location,omitempty"`
367367

368+
// MemberSuffix defines a suffix appended to each team member username before matching/adding them on GitHub.
369+
// Useful when GitHub usernames follow a naming convention (e.g. enterprise suffix).
370+
// Is ignored if environment variable GITHUB_MEMBER_SUFFIX is set.
371+
// +kubebuilder:validation:MaxLength=100
372+
// +optional
373+
// +kubebuilder:default=""
374+
MemberSuffix string `json:"memberSuffix,omitempty"`
375+
368376
// Website is the organization's website URL.
369377
// This appears on the organization's GitHub profile page as a clickable link.
370378
// +kubebuilder:validation:MaxLength=255

config/crd/bases/github.interhyp.de_organizations.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,14 @@ spec:
368368
maxLength: 39
369369
minLength: 1
370370
type: string
371+
memberSuffix:
372+
default: ""
373+
description: |-
374+
MemberSuffix defines a suffix appended to each team member username before matching/adding them on GitHub.
375+
Useful when GitHub usernames follow a naming convention (e.g. enterprise suffix).
376+
Is ignored if environment variable GITHUB_MEMBER_SUFFIX is set.
377+
maxLength: 100
378+
type: string
371379
name:
372380
description: |-
373381
Name is the organization's display name shown on the GitHub profile.

docs/configuration/organization.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ spec:
2727
credentialsSecretName: acme-corp-app-credentials # Secret in credentials namespace
2828
plan: enterprise # enterprise | team | free
2929

30+
# --- Team Members ---
31+
memberSuffix: "@acme-corp.com" # Appended to usernames in Team.spec.members; overridden by GITHUB_MEMBER_SUFFIX env var
32+
3033
# --- Custom Properties ---
3134
# Define metadata fields that repositories must/can set
3235
customProperties:
@@ -199,6 +202,19 @@ Some features require specific GitHub plans:
199202
| Internal repository visibility | `enterprise` |
200203
| Runner groups | `team` or `enterprise` |
201204

205+
## Team Member Suffix
206+
207+
When GitHub usernames in your enterprise follow a naming convention (e.g. `[email protected]`), set `spec.memberSuffix` so you can write plain usernames in `Team.spec.members` without repeating the suffix everywhere:
208+
209+
```yaml
210+
spec:
211+
memberSuffix: "@acme-corp.com"
212+
```
213+
214+
With this set, a team member listed as `john.doe` in `Team.spec.members` will be looked up and added on GitHub as `[email protected]`.
215+
216+
The global `GITHUB_MEMBER_SUFFIX` environment variable takes precedence over this field if set. For multi-organization setups where different orgs use different naming conventions, `spec.memberSuffix` is the preferred approach since the env var applies uniformly to all organizations.
217+
202218
## Related Resources
203219

204220
- [Repository Configuration](repository.md) - Configure repositories in this organization

docs/crds.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ _Appears in:_
621621
| `rulesetPresets` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core) array_ | RulesetPresetList references RulesetPreset CRDs that define repository rulesets for this organization.<br />Rulesets enforce policies like branch protection, required reviews, and status checks.<br />See: https://docs.github.com/en/rest/orgs/rules | | |
622622
| `description` _string_ | Description is a human-readable description of the organization.<br />This appears on the organization's GitHub profile page. | | |
623623
| `location` _string_ | Location is the organization's location (e.g., "Munich, Germany").<br />This appears on the organization's GitHub profile page. | | MaxLength: 100 <br />Optional: \{\} <br /> |
624+
| `memberSuffix` _string_ | MemberSuffix defines a suffix appended to each team member username before matching/adding them on GitHub.<br />Useful when GitHub usernames follow a naming convention (e.g. enterprise suffix).<br />Is ignored if environment variable GITHUB_MEMBER_SUFFIX is set. | | MaxLength: 100 <br />Optional: \{\} <br /> |
624625
| `website` _string_ | Website is the organization's website URL.<br />This appears on the organization's GitHub profile page as a clickable link. | | MaxLength: 255 <br />Optional: \{\} <br /> |
625626
| `plan` _string_ | Plan indicates the GitHub plan tier for this organization (enterprise, team, or free).<br />Determines whether Enterprise-only features (e.g., custom properties, runner groups) are reconciled or skipped. | enterprise | Enum: [enterprise team free] <br />Optional: \{\} <br /> |
626627

internal/reconciler/teamrec/rec_members.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
"os"
77

8+
githubv1alpha1 "github.com/Interhyp/git-hubby/api/v1alpha1"
9+
"sigs.k8s.io/controller-runtime/pkg/client"
810
logPkg "sigs.k8s.io/controller-runtime/pkg/log"
911
)
1012

@@ -14,6 +16,22 @@ func (t *GitHubTeamReconciler) reconcileTeamMembers(ctx context.Context) error {
1416
if t.Kubernetes.Resource.IsIDPTeam() {
1517
return nil // IDP teams manage members via the identity provider
1618
}
19+
20+
envMemberSuffix := os.Getenv("GITHUB_MEMBER_SUFFIX")
21+
k8sOrgs := make(map[string]githubv1alpha1.Organization)
22+
if envMemberSuffix == "" {
23+
// need to fetch orgs to check for org specific memberSuffixes later
24+
for _, orgRef := range t.Kubernetes.Resource.Spec.OrganizationRefs {
25+
var org githubv1alpha1.Organization
26+
if err := t.Kubernetes.Client.Get(ctx, client.ObjectKey{Name: orgRef.Name, Namespace: t.Kubernetes.Resource.Namespace}, &org); err != nil {
27+
log.Error(err, "unable to fetch Organization for Team", "organization", orgRef)
28+
return err
29+
}
30+
// index by GitHub login for easier mapping
31+
k8sOrgs[org.GetLogin()] = org
32+
}
33+
}
34+
1735
for _, githubOrg := range t.Team.Organizations.Current {
1836
log = log.WithValues("organization", githubOrg.Resource)
1937

@@ -32,8 +50,12 @@ func (t *GitHubTeamReconciler) reconcileTeamMembers(ctx context.Context) error {
3250
}
3351
}
3452

53+
memberSuffix := envMemberSuffix
54+
if org, ok := k8sOrgs[githubOrg.Resource]; ok {
55+
memberSuffix = org.Spec.MemberSuffix
56+
}
57+
3558
for _, memberRef := range t.Kubernetes.Resource.Spec.Members {
36-
memberSuffix := os.Getenv("GITHUB_MEMBER_SUFFIX")
3759
memberRef += memberSuffix
3860
log := log.WithValues("member", memberRef)
3961
log.V(1).Info("Processing member")

0 commit comments

Comments
 (0)