2022-10-19 02:31:22 +00:00
|
|
|
// Copyright 2021 Gravitational, 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 main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"path"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Describes a Drone trigger as it pertains to container image building.
|
|
|
|
type TriggerInfo struct {
|
2022-10-31 18:00:55 +00:00
|
|
|
Trigger trigger
|
|
|
|
Name string
|
|
|
|
Flags *TriggerFlags
|
|
|
|
SupportedVersions []*ReleaseVersion
|
|
|
|
SetupSteps []step
|
|
|
|
ParentePipelineNames []string
|
2022-10-19 02:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This type is mainly used to make passing these vars around cleaner
|
|
|
|
type TriggerFlags struct {
|
|
|
|
ShouldAffectProductionImages bool
|
|
|
|
ShouldBuildNewImages bool
|
|
|
|
UseUniqueStagingTag bool
|
|
|
|
ShouldOnlyPublishFullSemver bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewTagTrigger(branchMajorVersion string) *TriggerInfo {
|
|
|
|
tagTrigger := triggerTag
|
|
|
|
|
|
|
|
return &TriggerInfo{
|
|
|
|
Trigger: tagTrigger,
|
|
|
|
Name: "tag",
|
|
|
|
Flags: &TriggerFlags{
|
|
|
|
ShouldAffectProductionImages: false,
|
|
|
|
ShouldBuildNewImages: true,
|
|
|
|
UseUniqueStagingTag: false,
|
|
|
|
ShouldOnlyPublishFullSemver: true,
|
|
|
|
},
|
|
|
|
SupportedVersions: []*ReleaseVersion{
|
|
|
|
{
|
2022-12-06 20:03:51 +00:00
|
|
|
MajorVersion: branchMajorVersion,
|
|
|
|
ShellVersion: "$DRONE_TAG",
|
|
|
|
// Omitted because it doesn't matter here - only the full semver will only be published (see Flags)
|
|
|
|
// ShellIsPrerelease: // ,
|
2022-10-19 02:31:22 +00:00
|
|
|
RelativeVersionName: "branch",
|
|
|
|
},
|
|
|
|
},
|
2022-10-31 18:00:55 +00:00
|
|
|
ParentePipelineNames: []string{
|
|
|
|
tagCleanupPipelineName,
|
|
|
|
},
|
2022-10-19 02:31:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewPromoteTrigger(branchMajorVersion string) *TriggerInfo {
|
2022-12-06 20:03:51 +00:00
|
|
|
prereleaseFilePath := "/go/vars/release-is-prerelease"
|
|
|
|
shellVersion := "$DRONE_TAG"
|
|
|
|
|
2022-10-19 02:31:22 +00:00
|
|
|
promoteTrigger := triggerPromote
|
|
|
|
promoteTrigger.Target.Include = append(promoteTrigger.Target.Include, "promote-docker")
|
|
|
|
|
|
|
|
return &TriggerInfo{
|
|
|
|
Trigger: promoteTrigger,
|
|
|
|
Name: "promote",
|
|
|
|
Flags: &TriggerFlags{
|
|
|
|
ShouldAffectProductionImages: true,
|
|
|
|
ShouldBuildNewImages: false,
|
|
|
|
UseUniqueStagingTag: false,
|
|
|
|
ShouldOnlyPublishFullSemver: false,
|
|
|
|
},
|
|
|
|
SupportedVersions: []*ReleaseVersion{
|
|
|
|
{
|
2022-12-06 20:03:51 +00:00
|
|
|
MajorVersion: branchMajorVersion,
|
|
|
|
ShellVersion: shellVersion,
|
|
|
|
// Truthy if the file exists, which indicates a prerelease. See `recordPrereleaseStatus`` for details.
|
|
|
|
ShellIsPrerelease: fmt.Sprintf("[ -f %s ]", prereleaseFilePath),
|
2022-10-19 02:31:22 +00:00
|
|
|
RelativeVersionName: "branch",
|
|
|
|
},
|
|
|
|
},
|
2022-12-06 20:03:51 +00:00
|
|
|
SetupSteps: []step{verifyTaggedStep(), recordPrereleaseStatus(shellVersion, prereleaseFilePath)},
|
2022-10-19 02:31:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewCronTrigger(latestMajorVersions []string) *TriggerInfo {
|
|
|
|
if len(latestMajorVersions) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-10-31 18:00:55 +00:00
|
|
|
majorVersionVarBasePath := "/go/vars/full-version"
|
2022-10-19 02:31:22 +00:00
|
|
|
|
|
|
|
supportedVersions := make([]*ReleaseVersion, 0, len(latestMajorVersions))
|
|
|
|
if len(latestMajorVersions) > 0 {
|
|
|
|
latestMajorVersion := latestMajorVersions[0]
|
|
|
|
supportedVersions = append(supportedVersions, &ReleaseVersion{
|
|
|
|
MajorVersion: latestMajorVersion,
|
2022-10-31 18:00:55 +00:00
|
|
|
ShellVersion: readCronShellVersionCommand(majorVersionVarBasePath, latestMajorVersion),
|
2022-10-19 02:31:22 +00:00
|
|
|
RelativeVersionName: "current-version",
|
2022-10-31 18:00:55 +00:00
|
|
|
SetupSteps: []step{getLatestSemverStep(latestMajorVersion, majorVersionVarBasePath)},
|
2022-10-19 02:31:22 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
if len(latestMajorVersions) > 1 {
|
|
|
|
for i, majorVersion := range latestMajorVersions[1:] {
|
|
|
|
supportedVersions = append(supportedVersions, &ReleaseVersion{
|
2022-12-06 20:03:51 +00:00
|
|
|
MajorVersion: majorVersion,
|
|
|
|
ShellVersion: readCronShellVersionCommand(majorVersionVarBasePath, majorVersion),
|
|
|
|
// Omitted because it doesn't matter here - latest tags should always be built
|
|
|
|
// ShellIsPrerelease: // ,
|
2022-10-19 02:31:22 +00:00
|
|
|
RelativeVersionName: fmt.Sprintf("previous-version-%d", i+1),
|
2022-10-31 18:00:55 +00:00
|
|
|
SetupSteps: []step{getLatestSemverStep(majorVersion, majorVersionVarBasePath)},
|
2022-10-19 02:31:22 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &TriggerInfo{
|
|
|
|
Trigger: cronTrigger([]string{"teleport-container-images-cron"}),
|
|
|
|
Name: "cron",
|
|
|
|
Flags: &TriggerFlags{
|
|
|
|
ShouldAffectProductionImages: true,
|
|
|
|
ShouldBuildNewImages: true,
|
|
|
|
UseUniqueStagingTag: true,
|
|
|
|
ShouldOnlyPublishFullSemver: false,
|
|
|
|
},
|
|
|
|
SupportedVersions: supportedVersions,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-31 18:00:55 +00:00
|
|
|
func getLatestSemverStep(majorVersion string, majorVersionVarBasePath string) step {
|
2022-10-19 02:31:22 +00:00
|
|
|
// We don't use "/go/src/github.com/gravitational/teleport" here as a later stage
|
|
|
|
// may need to clone a different version, and "/go" persists between steps
|
|
|
|
cloneDirectory := "/tmp/teleport"
|
2022-10-31 18:00:55 +00:00
|
|
|
majorVersionVarPath := fmt.Sprintf("%s-%s", majorVersionVarBasePath, majorVersion)
|
2022-10-19 02:31:22 +00:00
|
|
|
return step{
|
|
|
|
Name: fmt.Sprintf("Find the latest available semver for %s", majorVersion),
|
|
|
|
Image: fmt.Sprintf("golang:%s", GoVersion),
|
|
|
|
Commands: append(
|
|
|
|
cloneRepoCommands(cloneDirectory, fmt.Sprintf("branch/%s", majorVersion)),
|
2022-10-31 18:00:55 +00:00
|
|
|
fmt.Sprintf("mkdir -pv $(dirname %q)", majorVersionVarPath),
|
2022-10-19 02:31:22 +00:00
|
|
|
fmt.Sprintf("cd %q", path.Join(cloneDirectory, "build.assets", "tooling", "cmd", "query-latest")),
|
2022-10-31 18:00:55 +00:00
|
|
|
fmt.Sprintf("go run . %q | sed 's/v//' > %q", majorVersion, majorVersionVarPath),
|
2022-10-19 02:31:22 +00:00
|
|
|
fmt.Sprintf("echo Found full semver \"$(cat %q)\" for major version %q", majorVersionVarPath, majorVersion),
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func readCronShellVersionCommand(majorVersionDirectory, majorVersion string) string {
|
2022-10-31 18:00:55 +00:00
|
|
|
return fmt.Sprintf("v$(cat '%s-%s')", majorVersionDirectory, majorVersion)
|
2022-10-19 02:31:22 +00:00
|
|
|
}
|
|
|
|
|
2022-12-06 20:03:51 +00:00
|
|
|
func recordPrereleaseStatus(shellVersion, recordFilePath string) step {
|
|
|
|
clonePath := "/tmp/repo"
|
|
|
|
commands := []string{
|
|
|
|
"apk add git",
|
|
|
|
}
|
|
|
|
commands = append(commands, cloneRepoCommands(clonePath, "${DRONE_TAG}")...)
|
|
|
|
commands = append(commands,
|
|
|
|
fmt.Sprintf("mkdir -pv $(dirname %q)", recordFilePath),
|
|
|
|
fmt.Sprintf("cd %q", path.Join(clonePath, "build.assets", "tooling")),
|
|
|
|
// If the tag is a prerelease, create a file who's existence shows that it is one
|
|
|
|
fmt.Sprintf("go run ./cmd/check -tag %s -check prerelease &> /dev/null || echo 'Version is a prerelease' > %q", shellVersion, recordFilePath),
|
|
|
|
fmt.Sprintf("printf 'Version is '; [ ! -f \"%s\" ] && printf 'not '; echo 'a prerelease'", recordFilePath),
|
|
|
|
)
|
|
|
|
|
|
|
|
return step{
|
|
|
|
// Note that Drone will evaluate certain variables (such as '${DRONE_TAG}') to their actual value in the step name
|
|
|
|
Name: fmt.Sprintf("Record if tag (%s) is prerelease", shellVersion),
|
|
|
|
Image: fmt.Sprintf("golang:%s-alpine", GoVersion),
|
|
|
|
Commands: commands,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-19 02:31:22 +00:00
|
|
|
// Drone triggers must all evaluate to "true" for a pipeline to be executed.
|
|
|
|
// As a result these pipelines are duplicated for each trigger.
|
|
|
|
// See https://docs.drone.io/pipeline/triggers/ for details.
|
|
|
|
func (ti *TriggerInfo) buildPipelines() []pipeline {
|
|
|
|
pipelines := make([]pipeline, 0, len(ti.SupportedVersions))
|
|
|
|
for _, teleportVersion := range ti.SupportedVersions {
|
|
|
|
pipeline := teleportVersion.buildVersionPipeline(ti.SetupSteps, ti.Flags)
|
|
|
|
pipeline.Name += "-" + ti.Name
|
|
|
|
pipeline.Trigger = ti.Trigger
|
2022-10-31 18:00:55 +00:00
|
|
|
pipeline.DependsOn = append(pipeline.DependsOn, ti.ParentePipelineNames...)
|
2022-10-19 02:31:22 +00:00
|
|
|
|
|
|
|
pipelines = append(pipelines, pipeline)
|
|
|
|
}
|
|
|
|
|
|
|
|
return pipelines
|
|
|
|
}
|