mirror of https://github.com/harness/drone.git
933 lines
31 KiB
Go
933 lines
31 KiB
Go
// Copyright 2023 Harness, Inc.
|
||
//
|
||
// 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 metadata
|
||
|
||
import (
|
||
"context"
|
||
"net/http"
|
||
"net/url"
|
||
"strings"
|
||
|
||
apiauth "github.com/harness/gitness/app/api/auth"
|
||
"github.com/harness/gitness/app/api/request"
|
||
"github.com/harness/gitness/app/paths"
|
||
"github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||
"github.com/harness/gitness/registry/app/common"
|
||
"github.com/harness/gitness/types/enum"
|
||
)
|
||
|
||
func (c *APIController) GetClientSetupDetails(
|
||
ctx context.Context,
|
||
r artifact.GetClientSetupDetailsRequestObject,
|
||
) (artifact.GetClientSetupDetailsResponseObject, error) {
|
||
regRefParam := r.RegistryRef
|
||
imageParam := r.Params.Artifact
|
||
tagParam := r.Params.Version
|
||
|
||
regInfo, _ := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(regRefParam))
|
||
|
||
space, err := c.SpaceFinder.FindByRef(ctx, regInfo.ParentRef)
|
||
if err != nil {
|
||
return artifact.GetClientSetupDetails400JSONResponse{
|
||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||
*GetErrorResponse(http.StatusBadRequest, err.Error()),
|
||
),
|
||
}, nil
|
||
}
|
||
|
||
session, _ := request.AuthSessionFrom(ctx)
|
||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||
enum.PermissionRegistryView)
|
||
if err = apiauth.CheckRegistry(
|
||
ctx,
|
||
c.Authorizer,
|
||
session,
|
||
permissionChecks...,
|
||
); err != nil {
|
||
return artifact.GetClientSetupDetails403JSONResponse{
|
||
UnauthorizedJSONResponse: artifact.UnauthorizedJSONResponse(
|
||
*GetErrorResponse(http.StatusForbidden, err.Error()),
|
||
),
|
||
}, nil
|
||
}
|
||
|
||
reg, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier)
|
||
if err != nil {
|
||
return artifact.GetClientSetupDetails404JSONResponse{
|
||
NotFoundJSONResponse: artifact.NotFoundJSONResponse(
|
||
*GetErrorResponse(http.StatusNotFound, "registry doesn't exist with this ref"),
|
||
),
|
||
}, err
|
||
}
|
||
|
||
packageType := string(reg.PackageType)
|
||
|
||
return artifact.GetClientSetupDetails200JSONResponse{
|
||
ClientSetupDetailsResponseJSONResponse: *c.GenerateClientSetupDetails(
|
||
ctx, packageType, imageParam, tagParam, regInfo.RegistryRef,
|
||
),
|
||
}, nil
|
||
}
|
||
|
||
func (c *APIController) GenerateClientSetupDetails(
|
||
ctx context.Context,
|
||
packageType string,
|
||
image *artifact.ArtifactParam,
|
||
tag *artifact.VersionParam,
|
||
registryRef string,
|
||
) *artifact.ClientSetupDetailsResponseJSONResponse {
|
||
session, _ := request.AuthSessionFrom(ctx)
|
||
username := session.Principal.Email
|
||
loginUsernameLabel := "Username: <USERNAME>"
|
||
loginUsernameValue := "<USERNAME>"
|
||
loginPasswordLabel := "Password: *see step 2*"
|
||
blankString := ""
|
||
switch packageType {
|
||
case string(artifact.PackageTypeMAVEN):
|
||
return c.generateMavenClientSetupDetail(ctx, image, tag, registryRef, username)
|
||
case string(artifact.PackageTypeHELM):
|
||
return c.generateHelmClientSetupDetail(ctx, blankString, loginUsernameLabel, loginUsernameValue,
|
||
loginPasswordLabel, username, registryRef, image, tag)
|
||
case string(artifact.PackageTypeGENERIC):
|
||
return c.generateGenericClientSetupDetail(ctx, blankString, registryRef, image, tag)
|
||
case string(artifact.PackageTypePYTHON):
|
||
return c.generatePythonClientSetupDetail(ctx, registryRef, username, image, tag)
|
||
}
|
||
header1 := "Login to Docker"
|
||
section1step1Header := "Run this Docker command in your terminal to authenticate the client."
|
||
dockerLoginValue := "docker login <LOGIN_HOSTNAME>"
|
||
section1step1Commands := []artifact.ClientSetupStepCommand{
|
||
{Label: &blankString, Value: &dockerLoginValue},
|
||
{Label: &loginUsernameLabel, Value: &loginUsernameValue},
|
||
{Label: &loginPasswordLabel, Value: &blankString},
|
||
}
|
||
section1step1Type := artifact.ClientSetupStepTypeStatic
|
||
section1step2Header := "For the Password field above, generate an identity token"
|
||
section1step2Type := artifact.ClientSetupStepTypeGenerateToken
|
||
section1Steps := []artifact.ClientSetupStep{
|
||
{
|
||
Header: §ion1step1Header,
|
||
Commands: §ion1step1Commands,
|
||
Type: §ion1step1Type,
|
||
},
|
||
{
|
||
Header: §ion1step2Header,
|
||
Type: §ion1step2Type,
|
||
},
|
||
}
|
||
section1 := artifact.ClientSetupSection{
|
||
Header: &header1,
|
||
}
|
||
_ = section1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: §ion1Steps,
|
||
})
|
||
header2 := "Pull an image"
|
||
section2step1Header := "Run this Docker command in your terminal to pull image."
|
||
dockerPullValue := "docker pull <HOSTNAME>/<REGISTRY_NAME>/<IMAGE_NAME>:<TAG>"
|
||
section2step1Commands := []artifact.ClientSetupStepCommand{
|
||
{Label: &blankString, Value: &dockerPullValue},
|
||
}
|
||
section2step1Type := artifact.ClientSetupStepTypeStatic
|
||
section2Steps := []artifact.ClientSetupStep{
|
||
{
|
||
Header: §ion2step1Header,
|
||
Commands: §ion2step1Commands,
|
||
Type: §ion2step1Type,
|
||
},
|
||
}
|
||
section2 := artifact.ClientSetupSection{
|
||
Header: &header2,
|
||
}
|
||
_ = section2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: §ion2Steps,
|
||
})
|
||
header3 := "Retag and Push the image"
|
||
section3step1Header := "Run this Docker command in your terminal to tag the image."
|
||
dockerTagValue := "docker tag <IMAGE_NAME>:<TAG> <HOSTNAME>/<REGISTRY_NAME>/<IMAGE_NAME>:<TAG>"
|
||
section3step1Commands := []artifact.ClientSetupStepCommand{
|
||
{Label: &blankString, Value: &dockerTagValue},
|
||
}
|
||
section3step1Type := artifact.ClientSetupStepTypeStatic
|
||
section3step2Header := "Run this Docker command in your terminal to push the image."
|
||
dockerPushValue := "docker push <HOSTNAME>/<REGISTRY_NAME>/<IMAGE_NAME>:<TAG>"
|
||
section3step2Commands := []artifact.ClientSetupStepCommand{
|
||
{Label: &blankString, Value: &dockerPushValue},
|
||
}
|
||
section3step2Type := artifact.ClientSetupStepTypeStatic
|
||
section3Steps := []artifact.ClientSetupStep{
|
||
{
|
||
Header: §ion3step1Header,
|
||
Commands: §ion3step1Commands,
|
||
Type: §ion3step1Type,
|
||
},
|
||
{
|
||
Header: §ion3step2Header,
|
||
Commands: §ion3step2Commands,
|
||
Type: §ion3step2Type,
|
||
},
|
||
}
|
||
section3 := artifact.ClientSetupSection{
|
||
Header: &header3,
|
||
}
|
||
_ = section3.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: §ion3Steps,
|
||
})
|
||
clientSetupDetails := artifact.ClientSetupDetails{
|
||
MainHeader: "Docker Client Setup",
|
||
SecHeader: "Follow these instructions to install/use Docker artifacts or compatible packages.",
|
||
Sections: []artifact.ClientSetupSection{
|
||
section1,
|
||
section2,
|
||
section3,
|
||
},
|
||
}
|
||
|
||
c.replacePlaceholders(ctx, &clientSetupDetails.Sections, username, registryRef, image, tag, "", "", "")
|
||
|
||
return &artifact.ClientSetupDetailsResponseJSONResponse{
|
||
Data: clientSetupDetails,
|
||
Status: artifact.StatusSUCCESS,
|
||
}
|
||
}
|
||
|
||
//nolint:lll
|
||
func (c *APIController) generateGenericClientSetupDetail(
|
||
ctx context.Context, blankString string,
|
||
registryRef string, image *artifact.ArtifactParam, tag *artifact.VersionParam,
|
||
) *artifact.ClientSetupDetailsResponseJSONResponse {
|
||
header1 := "Generate identity token"
|
||
section1Header := "An identity token will serve as the password for uploading and downloading artifact."
|
||
section1Type := artifact.ClientSetupStepTypeGenerateToken
|
||
section1steps := []artifact.ClientSetupStep{
|
||
{
|
||
Header: §ion1Header,
|
||
Type: §ion1Type,
|
||
},
|
||
}
|
||
section1 := artifact.ClientSetupSection{
|
||
Header: &header1,
|
||
}
|
||
_ = section1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: §ion1steps,
|
||
})
|
||
|
||
header2 := "Upload Artifact"
|
||
section2step1Header := "Run this curl command in your terminal to push the artifact."
|
||
//nolint:lll
|
||
pushValue := "curl --location --request PUT '<HOSTNAME>/<REGISTRY_NAME>/<ARTIFACT_NAME>/<VERSION>' \\\n--form 'filename=\"<FILENAME>\"' \\\n--form 'file=@\"<FILE_PATH>\"' \\\n--form 'description=\"<DESC>\"' \\\n--header 'x-api-key: <API_KEY>'"
|
||
section2step1Commands := []artifact.ClientSetupStepCommand{
|
||
{Label: &blankString, Value: &pushValue},
|
||
}
|
||
section2step1Type := artifact.ClientSetupStepTypeStatic
|
||
section2steps := []artifact.ClientSetupStep{
|
||
{
|
||
Header: §ion2step1Header,
|
||
Commands: §ion2step1Commands,
|
||
Type: §ion2step1Type,
|
||
},
|
||
}
|
||
section2 := artifact.ClientSetupSection{
|
||
Header: &header2,
|
||
}
|
||
_ = section2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: §ion2steps,
|
||
})
|
||
header3 := "Download Artifact"
|
||
section3step1Header := "Run this command in your terminal to download the artifact."
|
||
//nolint:lll
|
||
pullValue := "curl --location '<HOSTNAME>/<REGISTRY_NAME>/<ARTIFACT_NAME>:<VERSION>:<FILENAME>' --header 'x-api-key: <API_KEY>' " +
|
||
"-J -O"
|
||
section3step1Commands := []artifact.ClientSetupStepCommand{
|
||
{Label: &blankString, Value: &pullValue},
|
||
}
|
||
section3step1Type := artifact.ClientSetupStepTypeStatic
|
||
section3steps := []artifact.ClientSetupStep{
|
||
{
|
||
Header: §ion3step1Header,
|
||
Commands: §ion3step1Commands,
|
||
Type: §ion3step1Type,
|
||
},
|
||
}
|
||
section3 := artifact.ClientSetupSection{
|
||
Header: &header3,
|
||
}
|
||
_ = section3.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: §ion3steps,
|
||
})
|
||
|
||
clientSetupDetails := artifact.ClientSetupDetails{
|
||
MainHeader: "Generic Client Setup",
|
||
SecHeader: "Follow these instructions to install/use Generic artifacts or compatible packages.",
|
||
Sections: []artifact.ClientSetupSection{
|
||
section1,
|
||
section2,
|
||
section3,
|
||
},
|
||
}
|
||
//nolint:lll
|
||
c.replacePlaceholders(ctx, &clientSetupDetails.Sections, "", registryRef, image, tag, "", "",
|
||
string(artifact.PackageTypeGENERIC))
|
||
return &artifact.ClientSetupDetailsResponseJSONResponse{
|
||
Data: clientSetupDetails,
|
||
Status: artifact.StatusSUCCESS,
|
||
}
|
||
}
|
||
|
||
//nolint:lll
|
||
func (c *APIController) generateHelmClientSetupDetail(
|
||
ctx context.Context,
|
||
blankString string,
|
||
loginUsernameLabel string,
|
||
loginUsernameValue string,
|
||
loginPasswordLabel string,
|
||
username string,
|
||
registryRef string,
|
||
image *artifact.ArtifactParam,
|
||
tag *artifact.VersionParam,
|
||
) *artifact.ClientSetupDetailsResponseJSONResponse {
|
||
header1 := "Login to Helm"
|
||
section1step1Header := "Run this Helm command in your terminal to authenticate the client."
|
||
helmLoginValue := "helm registry login <LOGIN_HOSTNAME>"
|
||
section1step1Commands := []artifact.ClientSetupStepCommand{
|
||
{Label: &blankString, Value: &helmLoginValue},
|
||
{Label: &loginUsernameLabel, Value: &loginUsernameValue},
|
||
{Label: &loginPasswordLabel, Value: &blankString},
|
||
}
|
||
section1step1Type := artifact.ClientSetupStepTypeStatic
|
||
section1step2Header := "For the Password field above, generate an identity token"
|
||
section1step2Type := artifact.ClientSetupStepTypeGenerateToken
|
||
section1Steps := []artifact.ClientSetupStep{
|
||
{
|
||
Header: §ion1step1Header,
|
||
Commands: §ion1step1Commands,
|
||
Type: §ion1step1Type,
|
||
},
|
||
{
|
||
Header: §ion1step2Header,
|
||
Type: §ion1step2Type,
|
||
},
|
||
}
|
||
section1 := artifact.ClientSetupSection{
|
||
Header: &header1,
|
||
}
|
||
_ = section1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: §ion1Steps,
|
||
})
|
||
|
||
header2 := "Push a version"
|
||
section2step1Header := "Run this Helm push command in your terminal to push a chart in OCI form." +
|
||
" Note: Make sure you add oci:// prefix to the repository URL."
|
||
helmPushValue := "helm push <CHART_TGZ_FILE> oci://<HOSTNAME>/<REGISTRY_NAME>"
|
||
section2step1Commands := []artifact.ClientSetupStepCommand{
|
||
{Label: &blankString, Value: &helmPushValue},
|
||
}
|
||
section2step1Type := artifact.ClientSetupStepTypeStatic
|
||
section2Steps := []artifact.ClientSetupStep{
|
||
{
|
||
Header: §ion2step1Header,
|
||
Commands: §ion2step1Commands,
|
||
Type: §ion2step1Type,
|
||
},
|
||
}
|
||
section2 := artifact.ClientSetupSection{
|
||
Header: &header2,
|
||
}
|
||
_ = section2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: §ion2Steps,
|
||
})
|
||
|
||
header3 := "Pull a version"
|
||
section3step1Header := "Run this Helm command in your terminal to pull a specific chart version."
|
||
helmPullValue := "helm pull oci://<HOSTNAME>/<REGISTRY_NAME>/<IMAGE_NAME> --version <TAG>"
|
||
section3step1Commands := []artifact.ClientSetupStepCommand{
|
||
{Label: &blankString, Value: &helmPullValue},
|
||
}
|
||
section3step1Type := artifact.ClientSetupStepTypeStatic
|
||
section3Steps := []artifact.ClientSetupStep{
|
||
{
|
||
Header: §ion3step1Header,
|
||
Commands: §ion3step1Commands,
|
||
Type: §ion3step1Type,
|
||
},
|
||
}
|
||
section3 := artifact.ClientSetupSection{
|
||
Header: &header3,
|
||
}
|
||
_ = section3.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: §ion3Steps,
|
||
})
|
||
clientSetupDetails := artifact.ClientSetupDetails{
|
||
MainHeader: "Helm Client Setup",
|
||
SecHeader: "Follow these instructions to install/use Helm artifacts or compatible packages.",
|
||
Sections: []artifact.ClientSetupSection{
|
||
section1,
|
||
section2,
|
||
section3,
|
||
},
|
||
}
|
||
|
||
c.replacePlaceholders(ctx, &clientSetupDetails.Sections, username, registryRef, image, tag, "", "", "")
|
||
|
||
return &artifact.ClientSetupDetailsResponseJSONResponse{
|
||
Data: clientSetupDetails,
|
||
Status: artifact.StatusSUCCESS,
|
||
}
|
||
}
|
||
|
||
func (c *APIController) generateMavenClientSetupDetail(
|
||
ctx context.Context,
|
||
artifactName *artifact.ArtifactParam,
|
||
version *artifact.VersionParam,
|
||
registryRef string,
|
||
username string,
|
||
) *artifact.ClientSetupDetailsResponseJSONResponse {
|
||
staticStepType := artifact.ClientSetupStepTypeStatic
|
||
generateTokenStepType := artifact.ClientSetupStepTypeGenerateToken
|
||
|
||
section1 := artifact.ClientSetupSection{
|
||
Header: stringPtr("1. Generate Identity Token"),
|
||
SecHeader: stringPtr("An identity token will serve as the password for uploading and downloading artifacts."),
|
||
}
|
||
_ = section1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: &[]artifact.ClientSetupStep{
|
||
{
|
||
Header: stringPtr("Generate an identity token"),
|
||
Type: &generateTokenStepType,
|
||
},
|
||
},
|
||
})
|
||
|
||
mavenSection1 := artifact.ClientSetupSection{
|
||
Header: stringPtr("2. Pull a Maven Package"),
|
||
SecHeader: stringPtr("Set default repository in your pom.xml file."),
|
||
}
|
||
_ = mavenSection1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: &[]artifact.ClientSetupStep{
|
||
{
|
||
Header: stringPtr("To set default registry in your pom.xml file by adding the following:"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
//nolint:lll
|
||
Value: stringPtr("<repositories>\n <repository>\n <id>maven-dev</id>\n <url><REGISTRY_URL>/<REGISTRY_NAME></url>\n <releases>\n <enabled>true</enabled>\n <updatePolicy>always</updatePolicy>\n </releases>\n <snapshots>\n <enabled>true</enabled>\n <updatePolicy>always</updatePolicy>\n </snapshots>\n </repository>\n</repositories>"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
//nolint:lll
|
||
Header: stringPtr("Copy the following your ~/ .m2/settings.xml file for MacOs, or $USERPROFILE$\\ .m2\\settings.xml for Windows to authenticate with token to pull from your Maven registry."),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
//nolint:lll
|
||
Value: stringPtr("<settings>\n <servers>\n <server>\n <id>maven-dev</id>\n <username><USERNAME></username>\n <password>identity-token</password>\n </server>\n </servers>\n</settings>"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
//nolint:lll
|
||
Header: stringPtr("Add a dependency to the project's pom.xml (replace <GROUP_ID>, <ARTIFACT_ID> & <VERSION> with your own):"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
//nolint:lll
|
||
Value: stringPtr("<dependency>\n <groupId><GROUP_ID></groupId>\n <artifactId><ARTIFACT_ID></artifactId>\n <version><VERSION></version>\n</dependency>"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
Header: stringPtr("Install dependencies in pom.xml file"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("mvn install"),
|
||
},
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
mavenSection2 := artifact.ClientSetupSection{
|
||
Header: stringPtr("3. Push a Maven Package"),
|
||
SecHeader: stringPtr("Set default repository in your pom.xml file."),
|
||
}
|
||
|
||
_ = mavenSection2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: &[]artifact.ClientSetupStep{
|
||
{
|
||
Header: stringPtr("To set default registry in your pom.xml file by adding the following:"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
//nolint:lll
|
||
Value: stringPtr("<distributionManagement>\n <snapshotRepository>\n <id>maven-dev</id>\n <url><REGISTRY_URL>/<REGISTRY_NAME></url>\n </snapshotRepository>\n <repository>\n <id>maven-dev</id>\n <url><REGISTRY_URL>/<REGISTRY_NAME></url>\n </repository>\n</distributionManagement>"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
//nolint:lll
|
||
Header: stringPtr("Copy the following your ~/ .m2/setting.xml file for MacOs, or $USERPROFILE$\\ .m2\\settings.xml for Windows to authenticate with token to push to your Maven registry."),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
//nolint:lll
|
||
Value: stringPtr("<settings>\n <servers>\n <server>\n <id>maven-dev</id>\n <username><USERNAME></username>\n <password>identity-token</password>\n </server>\n </servers>\n</settings>"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
Header: stringPtr("Publish package to your Maven registry."),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("mvn deploy"),
|
||
},
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
gradleSection1 := artifact.ClientSetupSection{
|
||
Header: stringPtr("2. Pull a Gradle Package"),
|
||
SecHeader: stringPtr("Set default repository in your build.gradle file."),
|
||
}
|
||
_ = gradleSection1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: &[]artifact.ClientSetupStep{
|
||
{
|
||
Header: stringPtr("Set the default registry in your project’s build.gradle by adding the following:"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
//nolint:lll
|
||
Value: stringPtr("repositories{\n maven{\n url \"<REGISTRY_URL>/<REGISTRY_NAME>\"\n\n credentials {\n username \"<USERNAME>\"\n password \"identity-token\"\n }\n }\n}"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
//nolint:lll
|
||
Header: stringPtr("As this is a private registry, you’ll need to authenticate. Create or add to the ~/.gradle/gradle.properties file with the following:"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("repositoryUser=<USERNAME>\nrepositoryPassword={{identity-token}}"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
Header: stringPtr("Add a dependency to the project’s build.gradle"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("dependencies {\n implementation '<GROUP_ID>:<ARTIFACT_ID>:<VERSION>'\n}"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
Header: stringPtr("Install dependencies in build.gradle file"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("gradlew build // Linux or OSX\n gradlew.bat build // Windows"),
|
||
},
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
gradleSection2 := artifact.ClientSetupSection{
|
||
Header: stringPtr("3. Push a Gradle Package"),
|
||
SecHeader: stringPtr("Set default repository in your build.gradle file."),
|
||
}
|
||
|
||
_ = gradleSection2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: &[]artifact.ClientSetupStep{
|
||
{
|
||
Header: stringPtr("Add a maven publish plugin configuration to the project's build.gradle."),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
//nolint:lll
|
||
Value: stringPtr("publishing {\n publications {\n maven(MavenPublication) {\n groupId = 'GROUP_ID'\n artifactId = 'ARTIFACT_ID'\n version = 'VERSION'\n\n from components.java\n }\n }\n}"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
Header: stringPtr("Publish package to your Maven registry."),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("gradlew publish"),
|
||
},
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
sbtSection1 := artifact.ClientSetupSection{
|
||
Header: stringPtr("2. Pull a Sbt/Scala Package"),
|
||
SecHeader: stringPtr("Set default repository in your build.sbt file."),
|
||
}
|
||
_ = sbtSection1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: &[]artifact.ClientSetupStep{
|
||
{
|
||
Header: stringPtr("Set the default registry in your project’s build.sbt by adding the following:"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
//nolint:lll
|
||
Value: stringPtr("resolver += \"Harness Registry\" at \"<REGISTRY_URL>/<REGISTRY_NAME>\"\ncredentials += Credentials(Path.userHome / \".sbt\" / \".Credentials\")"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
//nolint:lll
|
||
Header: stringPtr("As this is a private registry, you’ll need to authenticate. Create or add to the ~/.sbt/.credentials file with the following:"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
//nolint:lll
|
||
Value: stringPtr("realm=Harness Registry\nhost=<LOGIN_HOSTNAME>\nuser=<USERNAME>\npassword={{identity-token}}"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
Header: stringPtr("Add a dependency to the project’s build.sbt"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("libraryDependencies += \"<GROUP_ID>\" % \"<ARTIFACT_ID>\" % \"<VERSION>\""),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
Header: stringPtr("Install dependencies in build.sbt file"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("sbt update"),
|
||
},
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
sbtSection2 := artifact.ClientSetupSection{
|
||
Header: stringPtr("3. Push a Sbt/Scala Package"),
|
||
SecHeader: stringPtr("Set default repository in your build.sbt file."),
|
||
}
|
||
|
||
_ = sbtSection2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: &[]artifact.ClientSetupStep{
|
||
{
|
||
Header: stringPtr("Add publish configuration to the project’s build.sbt."),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("publishTo := Some(\"Harness Registry\" at \"<REGISTRY_URL>/<REGISTRY_NAME>\")"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
Header: stringPtr("Publish package to your Maven registry."),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("sbt publish"),
|
||
},
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
section2 := artifact.ClientSetupSection{}
|
||
_ = section2.FromTabSetupStepConfig(artifact.TabSetupStepConfig{
|
||
Tabs: &[]artifact.TabSetupStep{
|
||
{
|
||
Header: stringPtr("Maven"),
|
||
Sections: &[]artifact.ClientSetupSection{
|
||
mavenSection1,
|
||
mavenSection2,
|
||
},
|
||
},
|
||
{
|
||
Header: stringPtr("Gradle"),
|
||
Sections: &[]artifact.ClientSetupSection{
|
||
gradleSection1,
|
||
gradleSection2,
|
||
},
|
||
},
|
||
{
|
||
Header: stringPtr("Sbt/Scala"),
|
||
Sections: &[]artifact.ClientSetupSection{
|
||
sbtSection1,
|
||
sbtSection2,
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
clientSetupDetails := artifact.ClientSetupDetails{
|
||
MainHeader: "Maven Client Setup",
|
||
SecHeader: "Follow these instructions to install/use Maven artifacts or compatible packages.",
|
||
Sections: []artifact.ClientSetupSection{
|
||
section1,
|
||
section2,
|
||
},
|
||
}
|
||
groupID := ""
|
||
if artifactName != nil {
|
||
parts := strings.Split(string(*artifactName), ":")
|
||
if len(parts) == 2 {
|
||
groupID = parts[0]
|
||
*artifactName = artifact.ArtifactParam(parts[1])
|
||
}
|
||
}
|
||
|
||
rootSpace, _, _ := paths.DisectRoot(registryRef)
|
||
registryURL := c.URLProvider.RegistryURL(ctx, "maven", rootSpace)
|
||
|
||
//nolint:lll
|
||
c.replacePlaceholders(ctx, &clientSetupDetails.Sections, username, registryRef, artifactName, version, registryURL,
|
||
groupID, "")
|
||
|
||
return &artifact.ClientSetupDetailsResponseJSONResponse{
|
||
Data: clientSetupDetails,
|
||
Status: artifact.StatusSUCCESS,
|
||
}
|
||
}
|
||
|
||
func (c *APIController) generatePythonClientSetupDetail(
|
||
ctx context.Context,
|
||
registryRef string,
|
||
username string,
|
||
image *artifact.ArtifactParam,
|
||
tag *artifact.VersionParam,
|
||
) *artifact.ClientSetupDetailsResponseJSONResponse {
|
||
staticStepType := artifact.ClientSetupStepTypeStatic
|
||
generateTokenType := artifact.ClientSetupStepTypeGenerateToken
|
||
|
||
// Authentication section
|
||
section1 := artifact.ClientSetupSection{
|
||
Header: stringPtr("Configure Authentication"),
|
||
}
|
||
_ = section1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: &[]artifact.ClientSetupStep{
|
||
{
|
||
Header: stringPtr("Create or update your ~/.pypirc file with the following content:"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("[distutils]\n" +
|
||
"index-servers = harness\n\n" +
|
||
"[harness]\n" +
|
||
"repository = <REGISTRY_URL>\n" +
|
||
"username = <USERNAME>\n" +
|
||
"password = *see step 2*"),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
Header: stringPtr("Generate an identity token for authentication"),
|
||
Type: &generateTokenType,
|
||
},
|
||
},
|
||
})
|
||
|
||
// Publish section
|
||
section2 := artifact.ClientSetupSection{
|
||
Header: stringPtr("Publish Package"),
|
||
}
|
||
_ = section2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: &[]artifact.ClientSetupStep{
|
||
{
|
||
Header: stringPtr("Build and publish your package:"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("python -m build"),
|
||
},
|
||
{
|
||
Value: stringPtr("python -m twine upload --repository harness /path/to/files/*"),
|
||
},
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
// Install section
|
||
section3 := artifact.ClientSetupSection{
|
||
Header: stringPtr("Install Package"),
|
||
}
|
||
_ = section3.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
|
||
Steps: &[]artifact.ClientSetupStep{
|
||
{
|
||
Header: stringPtr("Install a package using pip:"),
|
||
Type: &staticStepType,
|
||
Commands: &[]artifact.ClientSetupStepCommand{
|
||
{
|
||
Value: stringPtr("pip install --index-url <UPLOAD_URL>/simple --no-deps <ARTIFACT_NAME>==<VERSION>"),
|
||
},
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
clientSetupDetails := artifact.ClientSetupDetails{
|
||
MainHeader: "Python Client Setup",
|
||
SecHeader: "Follow these instructions to install/use Python packages from this registry.",
|
||
Sections: []artifact.ClientSetupSection{
|
||
section1,
|
||
section2,
|
||
section3,
|
||
},
|
||
}
|
||
|
||
registryURL := c.URLProvider.PackageURL(ctx, registryRef, "python")
|
||
|
||
c.replacePlaceholders(ctx, &clientSetupDetails.Sections, username, registryRef, image, tag, registryURL, "",
|
||
string(artifact.PackageTypePYTHON))
|
||
|
||
return &artifact.ClientSetupDetailsResponseJSONResponse{
|
||
Data: clientSetupDetails,
|
||
Status: artifact.StatusSUCCESS,
|
||
}
|
||
}
|
||
|
||
func (c *APIController) replacePlaceholders(
|
||
ctx context.Context,
|
||
clientSetupSections *[]artifact.ClientSetupSection,
|
||
username string,
|
||
regRef string,
|
||
image *artifact.ArtifactParam,
|
||
tag *artifact.VersionParam,
|
||
registryURL string,
|
||
groupID string,
|
||
pkgType string,
|
||
) {
|
||
uploadURL := ""
|
||
if pkgType == string(artifact.PackageTypePYTHON) {
|
||
regURL, _ := url.Parse(registryURL)
|
||
// append username:password to the host
|
||
regURL.User = url.UserPassword(username, "identity-token")
|
||
uploadURL = regURL.String()
|
||
}
|
||
|
||
for i := range *clientSetupSections {
|
||
tab, err := (*clientSetupSections)[i].AsTabSetupStepConfig()
|
||
if err != nil || tab.Tabs == nil {
|
||
//nolint:lll
|
||
c.replacePlaceholdersInSection(ctx, &(*clientSetupSections)[i], username, regRef, image, tag, pkgType,
|
||
registryURL, groupID, uploadURL)
|
||
} else {
|
||
for j := range *tab.Tabs {
|
||
c.replacePlaceholders(ctx, (*tab.Tabs)[j].Sections, username, regRef, image, tag, registryURL, groupID,
|
||
pkgType)
|
||
}
|
||
_ = (*clientSetupSections)[i].FromTabSetupStepConfig(tab)
|
||
}
|
||
}
|
||
}
|
||
|
||
func (c *APIController) replacePlaceholdersInSection(
|
||
ctx context.Context,
|
||
clientSetupSection *artifact.ClientSetupSection,
|
||
username string,
|
||
regRef string,
|
||
image *artifact.ArtifactParam,
|
||
tag *artifact.VersionParam,
|
||
pkgType string,
|
||
registryURL string,
|
||
groupID string,
|
||
uploadURL string,
|
||
) {
|
||
rootSpace, _, _ := paths.DisectRoot(regRef)
|
||
_, registryName, _ := paths.DisectLeaf(regRef)
|
||
var hostname string
|
||
if pkgType == string(artifact.PackageTypeGENERIC) {
|
||
hostname = c.URLProvider.RegistryURL(ctx, rootSpace, "generic")
|
||
} else {
|
||
hostname = common.TrimURLScheme(c.URLProvider.RegistryURL(ctx, rootSpace))
|
||
}
|
||
|
||
sec, err := clientSetupSection.AsClientSetupStepConfig()
|
||
if err != nil || sec.Steps == nil {
|
||
return
|
||
}
|
||
for _, st := range *sec.Steps {
|
||
if st.Commands == nil {
|
||
continue
|
||
}
|
||
for j := range *st.Commands {
|
||
replaceText(username, st, j, hostname, registryName, image, tag, registryURL, groupID, uploadURL)
|
||
}
|
||
}
|
||
_ = clientSetupSection.FromClientSetupStepConfig(sec)
|
||
}
|
||
|
||
func replaceText(
|
||
username string,
|
||
st artifact.ClientSetupStep,
|
||
i int,
|
||
hostname string,
|
||
repoName string,
|
||
image *artifact.ArtifactParam,
|
||
tag *artifact.VersionParam,
|
||
registryURL string,
|
||
groupID string,
|
||
uploadURL string,
|
||
) {
|
||
if username != "" {
|
||
(*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "<USERNAME>", username))
|
||
if (*st.Commands)[i].Label != nil {
|
||
(*st.Commands)[i].Label = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Label, "<USERNAME>", username))
|
||
}
|
||
}
|
||
if groupID != "" {
|
||
(*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "<GROUP_ID>", groupID))
|
||
}
|
||
if registryURL != "" {
|
||
(*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "<REGISTRY_URL>", registryURL))
|
||
}
|
||
if uploadURL != "" {
|
||
(*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "<UPLOAD_URL>", uploadURL))
|
||
}
|
||
if hostname != "" {
|
||
(*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "<HOSTNAME>", hostname))
|
||
}
|
||
if hostname != "" {
|
||
(*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value,
|
||
"<LOGIN_HOSTNAME>", common.GetHost(hostname)))
|
||
}
|
||
if repoName != "" {
|
||
(*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "<REGISTRY_NAME>", repoName))
|
||
}
|
||
if image != nil {
|
||
(*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "<IMAGE_NAME>",
|
||
string(*image)))
|
||
(*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "<ARTIFACT_ID>",
|
||
string(*image)))
|
||
(*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "<ARTIFACT_NAME>",
|
||
string(*image)))
|
||
}
|
||
if tag != nil {
|
||
(*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "<TAG>", string(*tag)))
|
||
(*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "<VERSION>", string(*tag)))
|
||
}
|
||
}
|
||
|
||
func stringPtr(s string) *string {
|
||
return &s
|
||
}
|