1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-07-13 01:30:24 +02:00

PythonBuild: Implementation of pythonBuild step (#3483)

* Implementation of pythonBuild step

* minor update and refactoring

* minor update

* add integration test and test project to testdata dir

* remove generated build data dir

* Rewrite some logic. Minor fix in integration tests for python

* Add new input parameters to pythonBuild.yaml

* rewrite logic
remove some checks

* rollback

* resolve merge conflict in piper.go
Update logic in python build. Create bom now works fine

* remove duplicate line

* refactoring fix

* resolve comment. Remove install build and change build command. Change twine upload command

* add groovy wrapper for pythonBuild step

* Rewrite tests. Remove some cheks from pythonBuild.go

* add some test to pythonBuild_test.go

* Add some parameters and credentials to the pythonBuild.groovy

* fix issue in unit tests

* add pythonBuild to fieldRelatedWhitelist

* update integration test for pythonBuild

* add imports

* update integration tests and add a new one

* minor fix

* fix some issues in integration tests

* update integration tests. Make it works again

Co-authored-by: Anil Keshav <anil.keshav@sap.com>
Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
TheShifter
2022-03-29 20:01:44 +03:00
committed by GitHub
parent 9ab7894c1a
commit 188e743f7b
22 changed files with 749 additions and 0 deletions

View File

@ -88,6 +88,7 @@ func GetAllStepMetadata() map[string]config.StepData {
"npmExecuteScripts": npmExecuteScriptsMetadata(),
"pipelineCreateScanSummary": pipelineCreateScanSummaryMetadata(),
"protecodeExecuteScan": protecodeExecuteScanMetadata(),
"pythonBuild": pythonBuildMetadata(),
"shellExecute": shellExecuteMetadata(),
"sonarExecuteScan": sonarExecuteScanMetadata(),
"terraformExecute": terraformExecuteMetadata(),

View File

@ -183,6 +183,7 @@ func Execute() {
rootCmd.AddCommand(ApiProxyUploadCommand())
rootCmd.AddCommand(GradleExecuteBuildCommand())
rootCmd.AddCommand(ApiKeyValueMapUploadCommand())
rootCmd.AddCommand(PythonBuildCommand())
addRootFlags(rootCmd)

107
cmd/pythonBuild.go Normal file
View File

@ -0,0 +1,107 @@
package cmd
import (
"fmt"
"github.com/SAP/jenkins-library/pkg/command"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/telemetry"
)
const (
PyBomFilename = "bom.xml"
)
type pythonBuildUtils interface {
command.ExecRunner
FileExists(filename string) (bool, error)
piperutils.FileUtils
}
type pythonBuildUtilsBundle struct {
*command.Command
*piperutils.Files
}
func newPythonBuildUtils() pythonBuildUtils {
utils := pythonBuildUtilsBundle{
Command: &command.Command{},
Files: &piperutils.Files{},
}
// Reroute command output to logging framework
utils.Stdout(log.Writer())
utils.Stderr(log.Writer())
return &utils
}
func pythonBuild(config pythonBuildOptions, telemetryData *telemetry.CustomData) {
utils := newPythonBuildUtils()
err := runPythonBuild(&config, telemetryData, utils)
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runPythonBuild(config *pythonBuildOptions, telemetryData *telemetry.CustomData, utils pythonBuildUtils) error {
installFlags := []string{"-m", "pip", "install", "--upgrade"}
err := buildExecute(config, utils, installFlags)
if err != nil {
return fmt.Errorf("Python build failed with error: %w", err)
}
if config.CreateBOM {
if err := runBOMCreationForPy(utils, installFlags); err != nil {
return fmt.Errorf("BOM creation failed: %w", err)
}
}
if config.Publish {
if err := publishWithTwine(config, utils, installFlags); err != nil {
return fmt.Errorf("failed to publish: %w", err)
}
}
return nil
}
func buildExecute(config *pythonBuildOptions, utils pythonBuildUtils, installFlags []string) error {
var flags []string
flags = append(flags, config.BuildFlags...)
flags = append(flags, "setup.py", "sdist", "bdist_wheel")
log.Entry().Info("starting building python project:")
err := utils.RunExecutable("python3", flags...)
if err != nil {
return err
}
return nil
}
func runBOMCreationForPy(utils pythonBuildUtils, installFlags []string) error {
installFlags = append(installFlags, "cyclonedx-bom")
if err := utils.RunExecutable("python3", installFlags...); err != nil {
return err
}
if err := utils.RunExecutable("cyclonedx-bom", "--e", "--output", PyBomFilename); err != nil {
return err
}
return nil
}
func publishWithTwine(config *pythonBuildOptions, utils pythonBuildUtils, installFlags []string) error {
installFlags = append(installFlags, "twine")
if err := utils.RunExecutable("python3", installFlags...); err != nil {
return err
}
if err := utils.RunExecutable("twine", "upload", "--username", config.TargetRepositoryUser,
"--password", config.TargetRepositoryPassword, "--repository-url", config.TargetRepositoryURL,
"dist/*"); err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,215 @@
// Code generated by piper's step-generator. DO NOT EDIT.
package cmd
import (
"fmt"
"os"
"time"
"github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/splunk"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/SAP/jenkins-library/pkg/validation"
"github.com/spf13/cobra"
)
type pythonBuildOptions struct {
BuildFlags []string `json:"buildFlags,omitempty"`
CreateBOM bool `json:"createBOM,omitempty"`
Publish bool `json:"publish,omitempty"`
TargetRepositoryPassword string `json:"targetRepositoryPassword,omitempty"`
TargetRepositoryUser string `json:"targetRepositoryUser,omitempty"`
TargetRepositoryURL string `json:"targetRepositoryURL,omitempty"`
}
// PythonBuildCommand Step build a python project
func PythonBuildCommand() *cobra.Command {
const STEP_NAME = "pythonBuild"
metadata := pythonBuildMetadata()
var stepConfig pythonBuildOptions
var startTime time.Time
var logCollector *log.CollectorHook
var splunkClient *splunk.Splunk
telemetryClient := &telemetry.Telemetry{}
var createPythonBuildCmd = &cobra.Command{
Use: STEP_NAME,
Short: "Step build a python project",
Long: `Step build python project with using test Vault credentials`,
PreRunE: func(cmd *cobra.Command, _ []string) error {
startTime = time.Now()
log.SetStepName(STEP_NAME)
log.SetVerbose(GeneralConfig.Verbose)
GeneralConfig.GitHubAccessTokens = ResolveAccessTokens(GeneralConfig.GitHubTokens)
path, _ := os.Getwd()
fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path}
log.RegisterHook(fatalHook)
err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile)
if err != nil {
log.SetErrorCategory(log.ErrorConfiguration)
return err
}
log.RegisterSecret(stepConfig.TargetRepositoryPassword)
log.RegisterSecret(stepConfig.TargetRepositoryUser)
if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 {
sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID)
log.RegisterHook(&sentryHook)
}
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
splunkClient = &splunk.Splunk{}
logCollector = &log.CollectorHook{CorrelationID: GeneralConfig.CorrelationID}
log.RegisterHook(logCollector)
}
validation, err := validation.New(validation.WithJSONNamesForStructFields(), validation.WithPredefinedErrorMessages())
if err != nil {
return err
}
if err = validation.ValidateStruct(stepConfig); err != nil {
log.SetErrorCategory(log.ErrorConfiguration)
return err
}
return nil
},
Run: func(_ *cobra.Command, _ []string) {
stepTelemetryData := telemetry.CustomData{}
stepTelemetryData.ErrorCode = "1"
handler := func() {
config.RemoveVaultSecretFiles()
stepTelemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
stepTelemetryData.ErrorCategory = log.GetErrorCategory().String()
stepTelemetryData.PiperCommitHash = GitCommit
telemetryClient.SetData(&stepTelemetryData)
telemetryClient.Send()
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
splunkClient.Send(telemetryClient.GetData(), logCollector)
}
}
log.DeferExitHandler(handler)
defer handler()
telemetryClient.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
splunkClient.Initialize(GeneralConfig.CorrelationID,
GeneralConfig.HookConfig.SplunkConfig.Dsn,
GeneralConfig.HookConfig.SplunkConfig.Token,
GeneralConfig.HookConfig.SplunkConfig.Index,
GeneralConfig.HookConfig.SplunkConfig.SendLogs)
}
pythonBuild(stepConfig, &stepTelemetryData)
stepTelemetryData.ErrorCode = "0"
log.Entry().Info("SUCCESS")
},
}
addPythonBuildFlags(createPythonBuildCmd, &stepConfig)
return createPythonBuildCmd
}
func addPythonBuildFlags(cmd *cobra.Command, stepConfig *pythonBuildOptions) {
cmd.Flags().StringSliceVar(&stepConfig.BuildFlags, "buildFlags", []string{}, "Defines list of build flags to be used.")
cmd.Flags().BoolVar(&stepConfig.CreateBOM, "createBOM", false, "Creates the bill of materials (BOM) using CycloneDX plugin.")
cmd.Flags().BoolVar(&stepConfig.Publish, "publish", false, "Configures the build to publish artifacts to a repository.")
cmd.Flags().StringVar(&stepConfig.TargetRepositoryPassword, "targetRepositoryPassword", os.Getenv("PIPER_targetRepositoryPassword"), "Password for the target repository where the compiled binaries shall be uploaded - typically provided by the CI/CD environment.")
cmd.Flags().StringVar(&stepConfig.TargetRepositoryUser, "targetRepositoryUser", os.Getenv("PIPER_targetRepositoryUser"), "Username for the target repository where the compiled binaries shall be uploaded - typically provided by the CI/CD environment.")
cmd.Flags().StringVar(&stepConfig.TargetRepositoryURL, "targetRepositoryURL", os.Getenv("PIPER_targetRepositoryURL"), "URL of the target repository where the compiled binaries shall be uploaded - typically provided by the CI/CD environment.")
}
// retrieve step metadata
func pythonBuildMetadata() config.StepData {
var theMetaData = config.StepData{
Metadata: config.StepMetadata{
Name: "pythonBuild",
Aliases: []config.Alias{},
Description: "Step build a python project",
},
Spec: config.StepSpec{
Inputs: config.StepInputs{
Parameters: []config.StepParameters{
{
Name: "buildFlags",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string",
Mandatory: false,
Aliases: []config.Alias{},
Default: []string{},
},
{
Name: "createBOM",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "STEPS", "STAGES", "PARAMETERS"},
Type: "bool",
Mandatory: false,
Aliases: []config.Alias{},
Default: false,
},
{
Name: "publish",
ResourceRef: []config.ResourceReference{},
Scope: []string{"STEPS", "STAGES", "PARAMETERS"},
Type: "bool",
Mandatory: false,
Aliases: []config.Alias{},
Default: false,
},
{
Name: "targetRepositoryPassword",
ResourceRef: []config.ResourceReference{
{
Name: "commonPipelineEnvironment",
Param: "custom/repositoryPassword",
},
},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_targetRepositoryPassword"),
},
{
Name: "targetRepositoryUser",
ResourceRef: []config.ResourceReference{
{
Name: "commonPipelineEnvironment",
Param: "custom/repositoryUsername",
},
},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_targetRepositoryUser"),
},
{
Name: "targetRepositoryURL",
ResourceRef: []config.ResourceReference{
{
Name: "commonPipelineEnvironment",
Param: "custom/repositoryUrl",
},
},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_targetRepositoryURL"),
},
},
},
Containers: []config.Container{
{Name: "python", Image: "python:3.9", WorkingDir: "/home/node"},
},
},
}
return theMetaData
}

View File

@ -0,0 +1,17 @@
package cmd
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestPythonBuildCommand(t *testing.T) {
t.Parallel()
testCmd := PythonBuildCommand()
// only high level testing performed - details are tested in step generation procedure
assert.Equal(t, "pythonBuild", testCmd.Use, "command name incorrect")
}

127
cmd/pythonBuild_test.go Normal file
View File

@ -0,0 +1,127 @@
package cmd
import (
"fmt"
"testing"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/stretchr/testify/assert"
"github.com/SAP/jenkins-library/pkg/mock"
)
type pythonBuildMockUtils struct {
t *testing.T
config *pythonBuildOptions
*mock.ExecMockRunner
*mock.FilesMock
}
type puthonBuildMockUtils struct {
*mock.ExecMockRunner
*mock.FilesMock
clientOptions []piperhttp.ClientOptions // set by mock
fileUploads map[string]string // set by mock
}
func newPythonBuildTestsUtils() pythonBuildMockUtils {
utils := pythonBuildMockUtils{
ExecMockRunner: &mock.ExecMockRunner{},
FilesMock: &mock.FilesMock{},
}
return utils
}
func (f *pythonBuildMockUtils) GetConfig() *pythonBuildOptions {
return f.config
}
func TestRunPythonBuild(t *testing.T) {
t.Run("success - build", func(t *testing.T) {
config := pythonBuildOptions{}
utils := newPythonBuildTestsUtils()
telemetryData := telemetry.CustomData{}
err := runPythonBuild(&config, &telemetryData, utils)
assert.NoError(t, err)
assert.Equal(t, "python3", utils.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"setup.py", "sdist", "bdist_wheel"}, utils.ExecMockRunner.Calls[0].Params)
})
t.Run("failure - build failure", func(t *testing.T) {
config := pythonBuildOptions{}
utils := newPythonBuildTestsUtils()
utils.ShouldFailOnCommand = map[string]error{"python3 setup.py sdist bdist_wheel": fmt.Errorf("build failure")}
telemetryData := telemetry.CustomData{}
err := runPythonBuild(&config, &telemetryData, utils)
assert.EqualError(t, err, "Python build failed with error: build failure")
})
t.Run("success - publishes binaries", func(t *testing.T) {
config := pythonBuildOptions{
Publish: true,
TargetRepositoryURL: "https://my.target.repository.local",
TargetRepositoryUser: "user",
TargetRepositoryPassword: "password",
}
utils := newPythonBuildTestsUtils()
telemetryData := telemetry.CustomData{}
err := runPythonBuild(&config, &telemetryData, utils)
assert.NoError(t, err)
assert.Equal(t, "python3", utils.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"setup.py", "sdist", "bdist_wheel"}, utils.ExecMockRunner.Calls[0].Params)
assert.Equal(t, "python3", utils.ExecMockRunner.Calls[1].Exec)
assert.Equal(t, []string{"-m", "pip", "install", "--upgrade", "twine"}, utils.ExecMockRunner.Calls[1].Params)
assert.Equal(t, "twine", utils.ExecMockRunner.Calls[2].Exec)
assert.Equal(t, []string{"upload", "--username", config.TargetRepositoryUser,
"--password", config.TargetRepositoryPassword, "--repository-url", config.TargetRepositoryURL,
"dist/*"}, utils.ExecMockRunner.Calls[2].Params)
})
t.Run("success - create BOM", func(t *testing.T) {
config := pythonBuildOptions{
CreateBOM: true,
}
utils := newPythonBuildTestsUtils()
telemetryData := telemetry.CustomData{}
err := runPythonBuild(&config, &telemetryData, utils)
assert.NoError(t, err)
assert.Equal(t, "python3", utils.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"setup.py", "sdist", "bdist_wheel"}, utils.ExecMockRunner.Calls[0].Params)
assert.Equal(t, "python3", utils.ExecMockRunner.Calls[1].Exec)
assert.Equal(t, []string{"-m", "pip", "install", "--upgrade", "cyclonedx-bom"}, utils.ExecMockRunner.Calls[1].Params)
assert.Equal(t, "cyclonedx-bom", utils.ExecMockRunner.Calls[2].Exec)
assert.Equal(t, []string{"--e", "--output", "bom.xml"}, utils.ExecMockRunner.Calls[2].Params)
})
t.Run("failure - install pre-requisites for BOM creation", func(t *testing.T) {
config := pythonBuildOptions{
CreateBOM: true,
}
utils := newPythonBuildTestsUtils()
utils.ShouldFailOnCommand = map[string]error{"python3 -m pip install --upgrade cyclonedx-bom": fmt.Errorf("install failure")}
telemetryData := telemetry.CustomData{}
err := runPythonBuild(&config, &telemetryData, utils)
assert.EqualError(t, err, "BOM creation failed: install failure")
})
t.Run("failure - install pre-requisites for Twine upload", func(t *testing.T) {
config := pythonBuildOptions{
Publish: true,
}
utils := newPythonBuildTestsUtils()
utils.ShouldFailOnCommand = map[string]error{"python3 -m pip install --upgrade twine": fmt.Errorf("install failure")}
telemetryData := telemetry.CustomData{}
err := runPythonBuild(&config, &telemetryData, utils)
assert.EqualError(t, err, "failed to publish: install failure")
})
}

View File

@ -0,0 +1,89 @@
//go:build integration
// +build integration
// can be execute with go test -tags=integration ./integration/...
package main
import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/testcontainers/testcontainers-go"
)
func TestBuildPythonProject(t *testing.T) {
t.Parallel()
ctx := context.Background()
pwd, err := os.Getwd()
assert.NoError(t, err, "Getting current working directory failed.")
pwd = filepath.Dir(pwd)
tempDir, err := createTmpDir("")
defer os.RemoveAll(tempDir) // clean up
assert.NoError(t, err, "Error when creating temp dir")
err = copyDir(filepath.Join(pwd, "integration", "testdata", "TestPythonIntegration", "python-project"), tempDir)
if err != nil {
t.Fatal("Failed to copy test project.")
}
//workaround to use test script util it is possible to set workdir for Exec call
testScript := fmt.Sprintf(`#!/bin/sh
cd /test
/piperbin/piper pythonBuild >test-log.txt 2>&1`)
ioutil.WriteFile(filepath.Join(tempDir, "runPiper.sh"), []byte(testScript), 0700)
reqNode := testcontainers.ContainerRequest{
Image: "python:3.9",
Cmd: []string{"tail", "-f"},
BindMounts: map[string]string{
pwd: "/piperbin",
tempDir: "/test",
},
}
nodeContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: reqNode,
Started: true,
})
code, err := nodeContainer.Exec(ctx, []string{"sh", "/test/runPiper.sh"})
assert.NoError(t, err)
assert.Equal(t, 0, code)
content, err := ioutil.ReadFile(filepath.Join(tempDir, "/test-log.txt"))
if err != nil {
t.Fatal("Could not read test-log.txt.", err)
}
output := string(content)
assert.Contains(t, output, "info pythonBuild - running command: python3 setup.py sdist bdist_wheel")
assert.Contains(t, output, "info pythonBuild - running command: python3 -m pip install --upgrade cyclonedx-bom")
assert.Contains(t, output, "info pythonBuild - running command: cyclonedx-bom --e --output bom.xml")
assert.Contains(t, output, "info pythonBuild - SUCCESS")
//workaround to use test script util it is possible to set workdir for Exec call
testScript = fmt.Sprintf(`#!/bin/sh
cd /test
ls -l . dist build >files-list.txt 2>&1`)
ioutil.WriteFile(filepath.Join(tempDir, "runPiper.sh"), []byte(testScript), 0700)
code, err = nodeContainer.Exec(ctx, []string{"sh", "/test/runPiper.sh"})
assert.NoError(t, err)
assert.Equal(t, 0, code)
content, err = ioutil.ReadFile(filepath.Join(tempDir, "/files-list.txt"))
if err != nil {
t.Fatal("Could not read files-list.txt.", err)
}
output = string(content)
assert.Contains(t, output, "bom.xml")
assert.Contains(t, output, "example-pkg-0.0.1.tar.gz")
assert.Contains(t, output, "example_pkg-0.0.1-py3-none-any.whl")
}

View File

@ -0,0 +1,6 @@
general:
steps:
pythonBuild:
createBOM: true
publish: false

View File

@ -0,0 +1,19 @@
Copyright (c) 2018 The Python Packaging Authority
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,5 @@
# Example Package
This is a simple example package. You can use
[Github-flavored Markdown](https://guides.github.com/features/mastering-markdown/)
to write your content.

View File

@ -0,0 +1,6 @@
[build-system]
requires = [
"setuptools>=42",
"wheel"
]
build-backend = "setuptools.build_meta"

View File

@ -0,0 +1,24 @@
[metadata]
name = example-package-TEST
version = 0.0.1
author = Example Author
author_email = author@example.com
description = A small example package
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/pypa/sampleproject
project_urls =
Bug Tracker = https://github.com/pypa/sampleproject/issues
classifiers =
Programming Language :: Python :: 3
License :: OSI Approved :: MIT License
Operating System :: OS Independent
[options]
package_dir =
= src
packages = find:
python_requires = >=3.6
[options.packages.find]
where = src

View File

@ -0,0 +1,19 @@
import setuptools
setuptools.setup(
name="example-pkg",
version="0.0.1",
author="Example Author",
author_email="author@example.com",
description="A small example package",
long_description="Long description for small example package",
long_description_content_type="text/markdown",
url="https://github.com/example/pypi/github",
packages=setuptools.find_packages(),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires='>=3.6',
)

View File

@ -0,0 +1,2 @@
def add_one(number):
return number + 1

View File

@ -0,0 +1,16 @@
Metadata-Version: 2.1
Name: example-pkg
Version: 0.0.1
Summary: A small example package
Home-page: https://github.com/example/pypi/github
Author: Example Author
Author-email: author@example.com
License: UNKNOWN
Project-URL: Bug Tracker, https://github.com/pypa/sampleproject/issues
Description: Long description for small example package
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.6
Description-Content-Type: text/markdown

View File

@ -0,0 +1,10 @@
README.md
pyproject.toml
setup.cfg
setup.py
src/example_package/__init__.py
src/example_package/example.py
src/example_pkg.egg-info/PKG-INFO
src/example_pkg.egg-info/SOURCES.txt
src/example_pkg.egg-info/dependency_links.txt
src/example_pkg.egg-info/top_level.txt

View File

@ -0,0 +1 @@
example_package

View File

@ -0,0 +1,66 @@
metadata:
name: pythonBuild
description: Step build a python project
longDescription: Step build python project with using test Vault credentials
spec:
inputs:
params:
- name: buildFlags
type: "[]string"
description: Defines list of build flags to be used.
scope:
- PARAMETERS
- STAGES
- STEPS
- name: createBOM
type: bool
description: Creates the bill of materials (BOM) using CycloneDX plugin.
scope:
- GENERAL
- STEPS
- STAGES
- PARAMETERS
default: false
- name: publish
type: bool
description: Configures the build to publish artifacts to a repository.
scope:
- STEPS
- STAGES
- PARAMETERS
- name: targetRepositoryPassword
description: "Password for the target repository where the compiled binaries shall be uploaded - typically provided by the CI/CD environment."
type: string
scope:
- PARAMETERS
- STAGES
- STEPS
secret: true
resourceRef:
- name: commonPipelineEnvironment
param: custom/repositoryPassword
- name: targetRepositoryUser
description: "Username for the target repository where the compiled binaries shall be uploaded - typically provided by the CI/CD environment."
type: string
scope:
- PARAMETERS
- STAGES
- STEPS
secret: true
resourceRef:
- name: commonPipelineEnvironment
param: custom/repositoryUsername
- name: targetRepositoryURL
description: "URL of the target repository where the compiled binaries shall be uploaded - typically provided by the CI/CD environment."
type: string
scope:
- PARAMETERS
- STAGES
- STEPS
resourceRef:
- name: commonPipelineEnvironment
param: custom/repositoryUrl
containers:
- name: python
image: python:3.9
workingDir: /home/node

View File

@ -213,6 +213,7 @@ public class CommonStepsTest extends BasePiperTest{
'gradleExecuteBuild', //implementing new golang pattern without fields
'shellExecute', //implementing new golang pattern without fields
'apiKeyValueMapUpload', //implementing new golang pattern without fields
'pythonBuild', //implementing new golang pattern without fields
]
@Test

16
vars/pythonBuild.groovy Normal file
View File

@ -0,0 +1,16 @@
import com.sap.piper.BuildTool
import com.sap.piper.DownloadCacheUtils
import groovy.transform.Field
import static com.sap.piper.Prerequisites.checkScript
@Field String METADATA_FILE = 'metadata/pythonBuild.yaml'
@Field String STEP_NAME = getClass().getName()
void call(Map parameters = [:]) {
List credentials = [[type: 'token', id: 'altDeploymentRepositoryPasswordId', env: ['PIPER_altDeploymentRepositoryPassword']]]
final script = checkScript(this, parameters) ?: this
parameters = DownloadCacheUtils.injectDownloadCacheInParameters(script, parameters, BuildTool.PIP)
piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials)
}