Provisioning: Implement connection repositories endpoint for GitHub

This change implements the `/repositories` subresource endpoint for Connection
resources, enabling listing of repositories accessible through a GitHub App
connection.

Changes:
- Add ListRepositories method to Connection interface
- Add ListInstallationRepositories to GitHub Client interface
- Implement GitHub client method to list installation repositories
  - Creates installation access token from JWT
  - Handles pagination up to 1000 repos
- Implement ListRepositories in GitHub Connection
- Update connectionRepositoriesConnector to use Connection.ListRepositories
- Add ConnectionGetter interface and GetConnection method to APIBuilder
- Add comprehensive tests for the new functionality
This commit is contained in:
Roberto Jimenez Sanchez
2026-01-13 09:56:40 +01:00
parent 91ab753368
commit a6a9358d5b
10 changed files with 478 additions and 19 deletions
@@ -432,3 +432,120 @@ func TestConnection_Validate(t *testing.T) {
})
}
}
func TestConnection_ListRepositories(t *testing.T) {
t.Run("should list repositories successfully", func(t *testing.T) {
c := &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GithubConnectionType,
GitHub: &provisioning.GitHubConnectionConfig{
AppID: "123",
InstallationID: "456",
},
},
Secure: provisioning.ConnectionSecure{
Token: common.InlineSecureValue{
Create: common.NewSecretValue("test-token"),
},
},
}
mockFactory := NewMockGithubFactory(t)
mockClient := NewMockClient(t)
mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("test-token")).Return(mockClient)
mockClient.EXPECT().ListInstallationRepositories(mock.Anything, "456").Return([]Repository{
{Name: "repo1", Owner: "owner1", URL: "https://github.com/owner1/repo1"},
{Name: "repo2", Owner: "owner2", URL: "https://github.com/owner2/repo2"},
}, nil)
conn := NewConnection(c, mockFactory)
repos, err := conn.ListRepositories(context.Background())
require.NoError(t, err)
require.Len(t, repos, 2)
assert.Equal(t, "repo1", repos[0].Name)
assert.Equal(t, "owner1", repos[0].Owner)
assert.Equal(t, "https://github.com/owner1/repo1", repos[0].URL)
assert.Equal(t, "repo2", repos[1].Name)
assert.Equal(t, "owner2", repos[1].Owner)
assert.Equal(t, "https://github.com/owner2/repo2", repos[1].URL)
})
t.Run("should return error when GitHub config is nil", func(t *testing.T) {
c := &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GitlabConnectionType,
},
}
mockFactory := NewMockGithubFactory(t)
conn := NewConnection(c, mockFactory)
_, err := conn.ListRepositories(context.Background())
require.Error(t, err)
assert.Contains(t, err.Error(), "github configuration is required")
})
t.Run("should return error when listing repositories fails", func(t *testing.T) {
c := &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GithubConnectionType,
GitHub: &provisioning.GitHubConnectionConfig{
AppID: "123",
InstallationID: "456",
},
},
Secure: provisioning.ConnectionSecure{
Token: common.InlineSecureValue{
Create: common.NewSecretValue("test-token"),
},
},
}
mockFactory := NewMockGithubFactory(t)
mockClient := NewMockClient(t)
mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("test-token")).Return(mockClient)
mockClient.EXPECT().ListInstallationRepositories(mock.Anything, "456").Return(nil, assert.AnError)
conn := NewConnection(c, mockFactory)
_, err := conn.ListRepositories(context.Background())
require.Error(t, err)
assert.Contains(t, err.Error(), "list installation repositories")
})
t.Run("should return empty list when no repositories", func(t *testing.T) {
c := &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GithubConnectionType,
GitHub: &provisioning.GitHubConnectionConfig{
AppID: "123",
InstallationID: "456",
},
},
Secure: provisioning.ConnectionSecure{
Token: common.InlineSecureValue{
Create: common.NewSecretValue("test-token"),
},
},
}
mockFactory := NewMockGithubFactory(t)
mockClient := NewMockClient(t)
mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("test-token")).Return(mockClient)
mockClient.EXPECT().ListInstallationRepositories(mock.Anything, "456").Return([]Repository{}, nil)
conn := NewConnection(c, mockFactory)
repos, err := conn.ListRepositories(context.Background())
require.NoError(t, err)
require.Len(t, repos, 0)
})
}