Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lazy-planes-reply.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'grafana-github-datasource': minor
---

Enable PDC for github datasource
34 changes: 24 additions & 10 deletions pkg/github/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
googlegithub "github.com/google/go-github/v72/github"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/influxdata/tdigest"
"github.com/shurcooL/githubv4"
"golang.org/x/oauth2"
Expand Down Expand Up @@ -53,28 +54,28 @@ var runnerPerMinuteRate = map[string]float64{
}

// New instantiates a new GitHub API client.
func New(ctx context.Context, settings models.Settings) (*Client, error) {
func New(ctx context.Context, settings models.Settings, opts httpclient.Options) (*Client, error) {
if settings.SelectedAuthType == models.AuthTypeGithubApp {
return createAppClient(settings)
return createAppClient(settings, opts)
}
if settings.SelectedAuthType == models.AuthTypePAT {
return createAccessTokenClient(ctx, settings)
return createAccessTokenClient(ctx, settings, opts)
}
return nil, backend.DownstreamError(errors.New("access token or app token are required"))
}

func createAppClient(settings models.Settings) (*Client, error) {
transport, err := httpclient.GetDefaultTransport()
func createAppClient(settings models.Settings, opts httpclient.Options) (*Client, error) {
httpClient, err := httpclient.New(opts)
if err != nil {
return nil, backend.DownstreamError(errors.New("error: http.DefaultTransport is not of type *http.Transport"))
return nil, backend.DownstreamErrorf("error creating http client: %w", err)
}
itr, err := ghinstallation.New(transport, settings.AppIdInt64, settings.InstallationIdInt64, []byte(settings.PrivateKey))

itr, err := ghinstallation.New(httpClient.Transport, settings.AppIdInt64, settings.InstallationIdInt64, []byte(settings.PrivateKey))
if err != nil {
return nil, backend.DownstreamError(errors.New("error creating token source"))
}

httpClient := &http.Client{Transport: itr}

httpClient.Transport = itr
if settings.GitHubURL == "" {
return &Client{
restClient: googlegithub.NewClient(httpClient),
Expand All @@ -87,13 +88,26 @@ func createAppClient(settings models.Settings) (*Client, error) {
return useGitHubEnterprise(httpClient, settings)
}

func createAccessTokenClient(ctx context.Context, settings models.Settings) (*Client, error) {
func createAccessTokenClient(ctx context.Context, settings models.Settings, opts httpclient.Options) (*Client, error) {
src := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: settings.AccessToken},
)

httpClient := oauth2.NewClient(ctx, src)

cli := proxy.New(opts.ProxyOptions)
if cli.SecureSocksProxyEnabled() {
// only override the Transport if Secure Proxy is enabled.
transport, err := httpclient.GetTransport(opts)
if err != nil {
return nil, backend.DownstreamErrorf("error getting the transport: %w", err)
}

httpClient.Transport = &oauth2.Transport{
Base: transport,
Source: oauth2.ReuseTokenSource(nil, src),
}
}
if settings.GitHubURL == "" {
return &Client{
restClient: googlegithub.NewClient(httpClient),
Expand Down
5 changes: 3 additions & 2 deletions pkg/github/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"

"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"

"github.com/grafana/github-datasource/pkg/dfutil"
githubclient "github.com/grafana/github-datasource/pkg/github/client"
Expand Down Expand Up @@ -244,8 +245,8 @@ func (d *Datasource) QueryData(ctx context.Context, req *backend.QueryDataReques
}

// NewDatasource creates a new datasource for handling queries
func NewDatasource(ctx context.Context, settings models.Settings) (*Datasource, error) {
client, err := githubclient.New(ctx, settings)
func NewDatasource(ctx context.Context, settings models.Settings, opts httpclient.Options) (*Datasource, error) {
client, err := githubclient.New(ctx, settings, opts)
if err != nil {
return nil, err
}
Expand Down
16 changes: 11 additions & 5 deletions pkg/plugin/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import (
"fmt"

"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"

"github.com/grafana/github-datasource/pkg/github"
"github.com/grafana/github-datasource/pkg/models"
)

// NewGitHubInstance creates a new GitHubInstance using the settings to determine if things like the Caching Wrapper should be enabled
func NewGitHubInstance(ctx context.Context, settings models.Settings) (instancemgmt.Instance, error) {
gh, err := github.NewDatasource(ctx, settings)
func NewGitHubInstance(ctx context.Context, settings models.Settings, opts httpclient.Options) (instancemgmt.Instance, error) {
gh, err := github.NewDatasource(ctx, settings, opts)
if err != nil {
return nil, err
}
Expand All @@ -28,15 +29,20 @@ func NewGitHubInstance(ctx context.Context, settings models.Settings) (instancem
}

// NewDataSourceInstance creates a new instance
func NewDataSourceInstance(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
datasourceSettings, err := models.LoadSettings(settings)
func NewDataSourceInstance(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
opts, err := settings.HTTPClientOptions(ctx)
if err != nil {
return nil, err
}

datasourceSettings, err := models.LoadSettings(settings)
if err != nil {
return nil, err
}

datasourceSettings.CachingEnabled = true

instance, err := NewGitHubInstance(context.Background(), datasourceSettings)
instance, err := NewGitHubInstance(context.Background(), datasourceSettings, opts)
if err != nil {
return instance, fmt.Errorf("instantiating github instance: %w", err)
}
Expand Down
1 change: 1 addition & 0 deletions src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type GitHubDataSourceOptions = {
selectedAuthType?: GitHubAuthType;
appId?: string;
installationId?: string;
enableSecureSocksProxy?: boolean
} & DataSourceJsonData;

export type GitHubSecureJsonDataKeys =
Expand Down
20 changes: 18 additions & 2 deletions src/views/ConfigEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
import React, { ChangeEvent, useCallback, useEffect, useState } from 'react';
import { css } from '@emotion/css';
import { Collapse, Field, Input, Label, RadioButtonGroup, SecretInput, SecretTextArea, useStyles2 } from '@grafana/ui';
import {
Collapse,
Field,
Input,
Label,
RadioButtonGroup,
SecretInput,
SecretTextArea,
SecureSocksProxySettings,
useStyles2,
} from '@grafana/ui';
import { ConfigSection, DataSourceDescription } from '@grafana/plugin-ui';
import { Divider } from 'components/Divider';
import { components as selectors } from '../components/selectors';
import {
FeatureToggles,
onUpdateDatasourceJsonDataOption,
onUpdateDatasourceSecureJsonDataOption,
type DataSourcePluginOptionsEditorProps,
type GrafanaTheme2,
type SelectableValue,
} from '@grafana/data';
import type { GitHubAuthType, GitHubLicenseType, GitHubDataSourceOptions, GitHubSecureJsonData } from 'types/config';
import { config } from '@grafana/runtime';
import { gte } from 'semver';

export type ConfigEditorProps = DataSourcePluginOptionsEditorProps<GitHubDataSourceOptions, GitHubSecureJsonData>;

const ConfigEditor = (props: ConfigEditorProps) => {
console.log('here');
const { options, onOptionsChange } = props;
const { jsonData, secureJsonData, secureJsonFields } = options;
const secureSettings = secureJsonData || {};
Expand Down Expand Up @@ -196,7 +210,9 @@ const ConfigEditor = (props: ConfigEditorProps) => {
</>
)}
</ConfigSection>

{config.featureToggles['secureSocksDSProxyEnabled' as keyof FeatureToggles] && gte(config.buildInfo.version, '10.0.0') && (
<SecureSocksProxySettings options={options} onOptionsChange={onOptionsChange} />
)}
<Divider />

<ConfigSection title="Connection" isCollapsible>
Expand Down
Loading