mirror of
https://github.com/docker/compose.git
synced 2026-02-09 01:59:22 +08:00
feat(experiments): add experimental feature state (#11633)
Use environment variable for global opt-out and Docker Desktop (if available) to determine specific experiment states. In the future, we'll allow per-feature opt-in/opt-out via env vars as well, but currently there is a single `COMPOSE_EXPERIMENTAL` env var that can be used to opt-out of all experimental features independently of Docker Desktop configuration.
This commit is contained in:
@@ -30,7 +30,8 @@ import (
|
||||
|
||||
// Client for integration with Docker Desktop features.
|
||||
type Client struct {
|
||||
client *http.Client
|
||||
apiEndpoint string
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
// NewClient creates a Desktop integration client for the provided in-memory
|
||||
@@ -45,11 +46,16 @@ func NewClient(apiEndpoint string) *Client {
|
||||
transport = otelhttp.NewTransport(transport)
|
||||
|
||||
c := &Client{
|
||||
client: &http.Client{Transport: transport},
|
||||
apiEndpoint: apiEndpoint,
|
||||
client: &http.Client{Transport: transport},
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) Endpoint() string {
|
||||
return c.apiEndpoint
|
||||
}
|
||||
|
||||
// Close releases any open connections.
|
||||
func (c *Client) Close() error {
|
||||
c.client.CloseIdleConnections()
|
||||
@@ -84,6 +90,35 @@ func (c *Client) Ping(ctx context.Context) (*PingResponse, error) {
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
type FeatureFlagResponse map[string]FeatureFlagValue
|
||||
|
||||
type FeatureFlagValue struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
func (c *Client) FeatureFlags(ctx context.Context) (FeatureFlagResponse, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, backendURL("/features"), http.NoBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var ret FeatureFlagResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// backendURL generates a URL for the given API path.
|
||||
//
|
||||
// NOTE: Custom transport handles communication. The host is to create a valid
|
||||
|
||||
62
internal/desktop/discovery.go
Normal file
62
internal/desktop/discovery.go
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright 2024 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package desktop
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
)
|
||||
|
||||
// engineLabelDesktopAddress is used to detect that Compose is running with a
|
||||
// Docker Desktop context. When this label is present, the value is an endpoint
|
||||
// address for an in-memory socket (AF_UNIX or named pipe).
|
||||
const engineLabelDesktopAddress = "com.docker.desktop.address"
|
||||
|
||||
// NewFromDockerClient creates a Desktop Client using the Docker CLI client to
|
||||
// auto-discover the Desktop CLI socket endpoint (if available).
|
||||
//
|
||||
// An error is returned if there is a failure communicating with Docker Desktop,
|
||||
// but even on success, a nil Client can be returned if the active Docker Engine
|
||||
// is not a Desktop instance.
|
||||
func NewFromDockerClient(ctx context.Context, dockerCli command.Cli) (*Client, error) {
|
||||
// safeguard to make sure this doesn't get stuck indefinitely
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second)
|
||||
defer cancel()
|
||||
|
||||
info, err := dockerCli.Client().Info(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying server info: %w", err)
|
||||
}
|
||||
for _, l := range info.Labels {
|
||||
k, v, ok := strings.Cut(l, "=")
|
||||
if !ok || k != engineLabelDesktopAddress {
|
||||
continue
|
||||
}
|
||||
|
||||
desktopCli := NewClient(v)
|
||||
_, err := desktopCli.Ping(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pinging Desktop API: %w", err)
|
||||
}
|
||||
return desktopCli, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package desktop
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type IntegrationService interface {
|
||||
MaybeEnableDesktopIntegration(ctx context.Context) error
|
||||
}
|
||||
Reference in New Issue
Block a user