diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index d7ecdb0bc7..0000000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,217 +0,0 @@ -# Guidance on How to Contribute - -**Table of Contents:** - -1. [Using the issue tracker](#using-the-issue-tracker) -1. [Changing the code-base](#changing-the-code-base) -1. [Jenkins credential handling](#jenkins-credential-handling) -1. [Code Style](#code-style) -1. [References](#references) - -There are two primary ways to help: - -* Using the issue tracker, and -* Changing the code-base. - -## Using the issue tracker - -Use the issue tracker to suggest feature requests, report bugs, and ask questions. This is also a great way to connect with the developers of the project as well as others who are interested in this solution. - -Use the issue tracker to find ways to contribute. Find a bug or a feature, mention in the issue that you will take on that effort, then follow the "Changing the code-base" guidance below. - -## Changing the code-base - -Generally speaking, you should fork this repository, make changes in your own fork, and then submit a pull-request. All new code should have been thoroughly tested end-to-end in order to validate implemented features and the presence or lack of defects. - -### Working with forks - -* [Configure this repository as a remote for your own fork](https://help.github.com/articles/configuring-a-remote-for-a-fork/), and -* [Sync your fork with this repository](https://help.github.com/articles/syncing-a-fork/) before beginning to work on a new pull-request. - -### Tests - -All pipeline library coding _must_ come with automated unit tests. - -Besides that, we have an integration test suite, which is not triggered during normal pull request builds. However, integration tests are mandatory before a change can be merged. It is the duty of a team member of the SAP/jenkins-library project to execute these tests. -To trigger the integration test suite, the `HEAD` commit of the branch associated with the pull request must be pushed under the branch pattern `it/.*` (recommended naming convention: `it/`). As a result, the status `integration-tests` is updated in the pull request. - -### Documentation - -The contract of functionality exposed by a library functionality needs to be documented, so it can be properly used. -Implementation of a functionality and its documentation shall happen within the same commit(s). - -### Coding pattern - -Pipeline steps must not make use of return values. The pattern for sharing parameters between pipeline steps or between a pipeline step and a pipeline script is sharing values via the [`commonPipelineEnvironment`](../vars/commonPipelineEnvironment.groovy). Since there is no return value from a pipeline step the return value of a pipeline step is already `void` rather than `def`. - -#### EditorConfig - -To ensure a common file format, there is a `.editorConfig` file [in place](../.editorconfig). To respect this file, [check](http://editorconfig.org/#download) if your editor does support it natively or you need to download a plugin. - -### Commit Message Style - -Write [meaningful commit messages](http://who-t.blogspot.de/2009/12/on-commit-messages.html) and [adhere to standard formatting](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). - -Good commit messages speed up the review process and help to keep this project maintainable in the long term. - -## Developer Certificate of Origin (DCO) - -Due to legal reasons, contributors will be asked to accept a DCO when they create their first pull request to this project. This happens in an automated fashion during the submission process. SAP uses [the standard DCO text of the Linux Foundation](https://developercertificate.org/). - -## Jenkins credential handling - -References to Jenkins credentials should have meaningful names. - -We are using the following approach for naming Jenkins credentials: - -For username/password credentials: -`CredentialsId` like e.g. `neoCredentialsId` - -For other cases we add further information to the name like: - -* `gitSshCredentialsId` for ssh credentials -* `githubTokenCredentialsId`for token/string credentials -* `gcpFileCredentialsId` for file credentials - -## Code Style - -Generally, the code should follow any stylistic and architectural guidelines prescribed by the project. In the absence of guidelines, mimic the styles and patterns in the existing code-base. - -The intention of this section is to describe the code style for this project. As reference document, the [Groovy's style guide](http://groovy-lang.org/style-guide.html) was taken. For further reading about Groovy's syntax and examples, please refer to this guide. - -This project is intended to run in Jenkins [[2]](https://jenkins.io/doc/book/getting-started/) as part of a Jenkins Pipeline [[3]](https://jenkins.io/doc/book/pipeline/). It is composed by Jenkins Pipeline's syntax, Groovy's syntax and Java's syntax. - -Some Groovy's syntax is not yet supported by Jenkins. It is also the intention of this section to remark which Groovy's syntax is not yet supported by Jenkins. - -As Groovy supports 99% of Java’s syntax [[1]](http://groovy-lang.org/style-guide.html), many Java developers tend to write Groovy code using Java's syntax. Such a developer should also consider the following code style for this project. - -### General remarks - -Variables, methods, types and so on shall have meaningful self describing names. Doing so makes understanding code easier and requires less commenting. It helps people who did not write the code to understand it better. - -Code shall contain comments to explain the intention of the code when it is unclear what the intention of the author was. In such cases, comments should describe the "why" and not the "what" (that is in the code already). - -### Omit semicolons - -### Use the return keyword - -In Groovy it is optional to use the _return_ keyword. Use explicitly the _return_ keyword for better readability. - -### Use def - -When using _def_ in Groovy, the type is Object. Using _def_ simplifies the code, for example imports are not needed, and therefore the development is faster. - -### Do not use a visibility modifier for public classes and methods - -By default, classes and methods are public, the use of the public modifier is not needed. - -### Do not omit parentheses for Groovy methods - -In Groovy is possible to omit parentheses for top-level expressions, but [Jenkins Pipeline's syntax](https://jenkins.io/doc/book/pipeline/syntax/) use a block, specifically `pipeline { }` as top-level expression [[4]](https://jenkins.io/doc/book/pipeline/syntax/). Do not omit parenthesis for Groovy methods because Jenkins will interpret the method as a Pipeline Step. Conversely, do omit parenthesis for Jenkins Pipeline's Steps. - -### Omit the .class suffix - -In Groovy, the .class suffix is not needed. Omit the .class suffix for simplicity and better readability. - -e.g. `new ExpectedException().expect(AbortException.class)` - ---> `new ExpectedException().expect(AbortException)` - -### Omit getters and setters - -When declaring a field without modifier inside a Groovy bean, the Groovy compiler generates a private field and a getter and setter. - -### Do not initialize beans with named parameters - -Do not initialize beans with named parameters, because it is not supported by Jenkins: - -e.g. `Version javaVersion = new Version( major: 1, minor: 8)` - -Initialize beans using Java syntax: - -e.g. `Version javaVersion = new Version(1, 8)` - -Use named parameters for Jenkins Pipeline Steps: - -e.g. `sh returnStdout: true, script: command` - -### Do not use _with()_ operator - -The _with_ operator is not yet supported by Jenkins, and it must not be used or encapsulated in a @NonCPS method. - -### Use _==_ operator - -Use Groovy’s `==` instead of Java `equals()` to avoid NullPointerExceptions. To compare the references of objects, instead of `==`, you should use `a.is(b)` [[1]](http://groovy-lang.org/style-guide.html). - -### Use GStrings - -In Groovy, single quotes create Java Strings, and double quotes can create Java Strings or GStrings, depending if there is or not interpolation of variables [[1]](http://groovy-lang.org/style-guide.html). Using GStrings variable and string concatenation is more simple. - -#### Do not use curly braces {} for variables or variable.property - -For variables, or variable.property, drop the curly braces: - -e.g. `echo "[INFO] ${name} version ${version.version} is installed."` - ---> `echo "[INFO] $name version $version.version is installed."` - -#### Use 'single quotes' for Strings and constants - -#### Use "double quotes" for GStrings - -#### Use '''triple single quotes''' for multiline Strings - -#### Use """triple double quotes""" for multiline GStrings - -#### Use /slash/ for regular expressions - -This notation avoids to double escape backslashes, making easier working with regex. - -### Use native syntax for data structures - -Use the native syntax for data structures provided by Groovy like lists, maps, regex, or ranges of values. - -### Use aditional Groovy methods - -Use the additional methods provided by Groovy to manipulate String, Files, Streams, Collections, and other classes. -For a complete description of all available methods, please read the GDK API [[5]](http://groovy-lang.org/groovy-dev-kit.html). - -### Use Groovy's switch - -Groovy’s switch accepts any kind of type, thereby is more powerful. In this case, the use of _def_ instead of a type is necessary. - -### Use alias for import - -In Groovy, it is possible to assign an alias to imported packages. Use alias for imported packages to avoid the use of fully-qualified names and increase readability. - -### Use Groovy syntax to check objects - -In Groovy a null, void, equal to zero, or empty object evaluates to false, and if not, evaluates to true. Instead of writing null and size checks e.g. `if (name != null && name.length > 0) {}`, use just the object `if (name) {}`. - -### Use _?._ operator - -Use the safe dereference operator _?._, to simplify the code for accessing objects and object members safely. Using this operator, the Groovy compiler checks null objects and null object members, and returns _null_ if the object or the object member is null and never throws a NullPointerException. - -### Use _?:_ operator - -Use Elvis operator _?:_ to simplify default value validations. - -### Use _any_ keyword - -If the type of the exception thrown inside a try block is not important, catch any exception using the _any_ keyword. - -### Use _assert_ - -To check parameters, return values, and more, use the assert statement. - -## References - -[1] Groovy's syntax: [http://groovy-lang.org/style-guide.html](http://groovy-lang.org/style-guide.html) - -[2] Jenkins: [https://jenkins.io/doc/book/getting-started/](https://jenkins.io/doc/book/getting-started/) - -[3] Jenkins Pipeline: [https://jenkins.io/doc/book/pipeline/](https://jenkins.io/doc/book/pipeline/) - -[4] Jenkins Pipeline's syntax: [https://jenkins.io/doc/book/pipeline/syntax/](https://jenkins.io/doc/book/pipeline/syntax/) - -[5] GDK: Groovy Development Kit: [http://groovy-lang.org/groovy-dev-kit.html](http://groovy-lang.org/groovy-dev-kit.html) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 180ace3631..10febb1bb3 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/setup-go@v5 with: - go-version: '1.21.x' + go-version: '1.22.4' - name: Install Groovy run: sudo apt-get update && sudo apt-get install groovy -y diff --git a/.github/workflows/release-go.yml b/.github/workflows/release-go.yml index 1f800f2c11..e4ab18b585 100644 --- a/.github/workflows/release-go.yml +++ b/.github/workflows/release-go.yml @@ -1,6 +1,7 @@ name: Create new Release on: + workflow_dispatch: repository_dispatch: types: perform-release schedule: @@ -8,17 +9,15 @@ on: jobs: build: + permissions: write-all name: Publish runs-on: ubuntu-latest steps: - uses: styfle/cancel-workflow-action@0.11.0 + - uses: actions/checkout@v4 - # Workaround for https://github.com/SAP/jenkins-library/issues/1723, build only works with jdk8 currently - - uses: actions/setup-java@v4 - with: - java-version: 8 - distribution: zulu - - name: Prepare Release + + - name: Prepare assets and increment version run: | curl --insecure --silent --location --write-out '%{http_code}' --output ./piper_master https://github.com/SAP/jenkins-library/releases/latest/download/piper_master curl --insecure --silent --location --write-out '%{http_code}' --output ./piper_master-darwin.x86_64 https://github.com/SAP/jenkins-library/releases/latest/download/piper_master-darwin.x86_64 @@ -28,12 +27,59 @@ jobs: cp ./piper_master-darwin.arm64 ./piper-darwin.arm64 npm install semver --quiet echo "PIPER_version=v$(node_modules/.bin/semver -i minor $(curl --silent "https://api.github.com/repos/$GITHUB_REPOSITORY/releases/latest" | jq -r .tag_name))" >> $GITHUB_ENV + - uses: SAP/project-piper-action@master - name: 'publish Linux master binary' + name: Publish prerelease with: piper-version: master command: githubPublishRelease - flags: --token ${{ secrets.GITHUB_TOKEN }} --assetPathList ./piper_master --assetPathList ./piper --assetPathList ./piper_master-darwin.x86_64 --assetPathList ./piper-darwin.x86_64 --assetPathList ./piper_master-darwin.arm64 --assetPathList ./piper-darwin.arm64 + flags: > + --preRelease true + --token ${{ secrets.GITHUB_TOKEN }} + --assetPathList ./piper --assetPathList ./piper_master + --assetPathList ./piper-darwin.x86_64 --assetPathList ./piper_master-darwin.x86_64 + --assetPathList ./piper-darwin.arm64 --assetPathList ./piper_master-darwin.arm64 + + - name: Download Piper binary from recently published prerelease + uses: robinraju/release-downloader@v1 + with: + tag: ${{ env.PIPER_version }} + fileName: 'piper' + + - name: Test binary (check output for 'commit:' substring) + run: | + chmod +x piper + if ./piper version | grep -Fq "commit:"; then + echo "piper binary test is successful" + else + echo "piper binary test failed" + ./piper version + exit 1 + fi + + - name: Get recently published prerelease id + id: release_id + run: > + curl -L -s -o resp.json + -H "Accept: application/vnd.github.raw+json" + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" + ${{ github.api_url }}/repos/${{ github.repository }}/releases + + echo "release_id=$(jq 'first(.[] | select(.tag_name == "${{ env.PIPER_version }}")).id' resp.json)" >> "$GITHUB_OUTPUT" + + - name: Convert prereleae to Release + run: > + curl --fail-with-body -L -X PATCH + -H "Accept: application/vnd.github+json" + -H "Authorization: Bearer ${{ github.token }}" + ${{ github.api_url }}/repos/${{ github.repository }}/releases/${{ steps.release_id.outputs.release_id }} + -d '{"prerelease": false, "make_latest": true}' + + # Workaround for https://github.com/SAP/jenkins-library/issues/1723, build only works with jdk8 currently + - uses: actions/setup-java@v4 + with: + java-version: 8 + distribution: zulu - name: Build and publish jar for consumption in unit tests run: mvn package - uses: SAP/project-piper-action@master @@ -42,3 +88,42 @@ jobs: piper-version: master command: githubPublishRelease flags: --token ${{ secrets.GITHUB_TOKEN }} --version latest --assetPath ./target/jenkins-library.jar + + post: + name: Post Action + runs-on: ubuntu-latest + needs: [build] + if: always() + steps: + # Check status of the worklfow + - uses: martialonline/workflow-status@v4 + id: check + + # This step expects base64 encoded JSON object as below: + # { + # "smtp_url": "smtp+starttls://user:password@server:port", + # "smtp_mail_from": "from@mail.example", + # "smtp_mail_rcpt": "to@mail.example", + # } + - name: Decode SMTP secrets and set them in GITHUB_ENV + id: smtp_secrets + if: steps.check.outputs.status == 'failure' || steps.check.outputs.status == 'cancelled' + run: > + echo "${{ secrets.SMTP_CONFIG }}" | + base64 --decode | + jq -r 'to_entries[] | "\(.key)=\(.value)"' | + while read line; do + echo "$line" >> $GITHUB_ENV; echo "::add-mask::${line#*=}"; + done + - name: Notify Piper team on failure or cancelled + if: steps.smtp_secrets.conclusion == 'success' + uses: dawidd6/action-send-mail@v3 + with: + connection_url: ${{ env.smtp_url }} + subject: Workflow failure in ${{ github.repository }} + priority: high + to: ${{ env.smtp_mail_rcpt }} + from: Piper on GitHub <${{ env.smtp_mail_from }}> + body: | + Workflow '${{ github.workflow }}' has a job with status '${{ steps.check.outputs.status }}'. + Workflow link: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/update-go-dependencies.yml b/.github/workflows/update-go-dependencies.yml index 8f62a4be87..fe7f350d3a 100644 --- a/.github/workflows/update-go-dependencies.yml +++ b/.github/workflows/update-go-dependencies.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: '1.21.x' + go-version: '1.22.4' - name: Perform update run: | git checkout -B gh-action-update-golang-dependencies diff --git a/.github/workflows/upload-go-master.yml b/.github/workflows/upload-go-master.yml index 247b180b96..9f88021517 100644 --- a/.github/workflows/upload-go-master.yml +++ b/.github/workflows/upload-go-master.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: '1.21.x' + go-version: '1.22.4' - env: CGO_ENABLED: 0 run: | diff --git a/.github/workflows/verify-go.yml b/.github/workflows/verify-go.yml index 8c63864fb1..8226c83165 100644 --- a/.github/workflows/verify-go.yml +++ b/.github/workflows/verify-go.yml @@ -15,7 +15,7 @@ jobs: - uses: styfle/cancel-workflow-action@0.11.0 - uses: actions/setup-go@v5 with: - go-version: '1.21.x' + go-version: '1.22.4' - name: Cache Golang Packages uses: actions/cache@v3 with: @@ -43,7 +43,7 @@ jobs: steps: - uses: actions/setup-go@v5 with: - go-version: '1.21.x' + go-version: '1.22.4' - name: Cache Golang Packages uses: actions/cache@v3 with: @@ -63,7 +63,7 @@ jobs: steps: - uses: actions/setup-go@v5 with: - go-version: '1.21.x' + go-version: '1.22.4' - name: checkout uses: actions/checkout@v4 with: @@ -78,7 +78,7 @@ jobs: steps: - uses: actions/setup-go@v5 with: - go-version: '1.21.x' + go-version: '1.22.4' - name: Cache Golang Packages uses: actions/cache@v3 with: @@ -98,7 +98,7 @@ jobs: steps: - uses: actions/setup-go@v5 with: - go-version: '1.21.x' + go-version: '1.22.4' - name: Cache Golang Packages uses: actions/cache@v3 with: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..af4a1830ed --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,38 @@ +# Contributing to an SAP Open Source Project + +## General Remarks + +You are welcome to contribute content (code, documentation etc.) to this open source project. + +There are some important things to know: + +1. You must **comply to the license of this project**, **accept the Developer Certificate of Origin** (see below) before being able to contribute. The acknowledgement to the DCO will usually be requested from you as part of your first pull request to this project. +2. Please **adhere to our [Code of Conduct](documentation/CODE_OF_CONDUCT.md)**. +3. If you plan to use **generative AI for your contribution**, please see our guideline below. +4. **Not all proposed contributions can be accepted**. Some features may fit another project better or doesn't fit the general direction of this project. Of course, this doesn't apply to most bug fixes, but a major feature implementation for instance needs to be discussed with one of the maintainers first. Possibly, one who touched the related code or module recently. The more effort you invest, the better you should clarify in advance whether the contribution will match the project's direction. The best way would be to just open an issue to discuss the feature you plan to implement (make it clear that you intend to contribute). We will then forward the proposal to the respective code owner. This avoids disappointment. + +## Developer Certificate of Origin (DCO) + +Contributors will be asked to accept a DCO before they submit the first pull request to this projects, this happens in an automated fashion during the submission process. SAP uses [the standard DCO text of the Linux Foundation](https://developercertificate.org/). + +## Contributing with AI-generated code + +As artificial intelligence evolves, AI-generated code is becoming valuable for many software projects, including open-source initiatives. While we recognize the potential benefits of incorporating AI-generated content into our open-source projects there a certain requirements that need to be reflected and adhered to when making contributions. + +Please see our [guideline for AI-generated code contributions to SAP Open Source Software Projects](documentation/CONTRIBUTING_USING_GENAI.md) for these requirements. + +## How to Contribute + +1. Make sure the change is welcome (see [General Remarks](#general-remarks)). +2. Create a branch by forking the repository and apply your change. +3. Commit and push your change on that branch. +4. Create a pull request in the repository using this branch. +5. Follow the link posted by the CLA assistant to your pull request and accept it, as described above. +6. Wait for our code review and approval, possibly enhancing your change on request. + - Note that the maintainers have many duties. So, depending on the required effort for reviewing, testing, and clarification, this may take a while. +7. Once the change has been approved and merged, we will inform you in a comment. +8. Celebrate! + +## Development Guidelines + +See our [Development Guidelines](documentation/DEVELOPMENT.md) diff --git a/Dockerfile b/Dockerfile index bf79b06b4e..7a44ad5c56 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21 AS build-env +FROM golang:1.22.4 AS build-env COPY . /build WORKDIR /build diff --git a/README.md b/README.md index 20963e5142..6e0e340b81 100644 --- a/README.md +++ b/README.md @@ -29,5 +29,5 @@ before opening a pull request. [piper-library-user-doc]: https://sap.github.io/jenkins-library/ [piper-library-issues]: https://github.com/SAP/jenkins-library/issues -[piper-library-contribution]: .github/CONTRIBUTING.md +[piper-library-contribution]: CONTRIBUTING.md [google-group]: https://groups.google.com/forum/#!forum/project-piper diff --git a/cmd/abapAddonAssemblyKitCheck.go b/cmd/abapAddonAssemblyKitCheck.go index c4ce5950d0..0ab0b12621 100644 --- a/cmd/abapAddonAssemblyKitCheck.go +++ b/cmd/abapAddonAssemblyKitCheck.go @@ -27,7 +27,7 @@ func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, util log.Entry().Info("╚═══════════════════════════╝") conn := new(abapbuild.Connector) - if err := conn.InitAAKaaS(config.AbapAddonAssemblyKitEndpoint, config.Username, config.Password, utils, "", config.AbapAddonAssemblyKitCertificateFile, config.AbapAddonAssemblyKitCertificatePass); err != nil { + if err := conn.InitAAKaaS(config.AbapAddonAssemblyKitEndpoint, config.Username, config.Password, utils, config.AbapAddonAssemblyKitOriginHash, config.AbapAddonAssemblyKitCertificateFile, config.AbapAddonAssemblyKitCertificatePass); err != nil { return err } diff --git a/cmd/abapAddonAssemblyKitCheck_generated.go b/cmd/abapAddonAssemblyKitCheck_generated.go index 71d2226046..3711fb3110 100644 --- a/cmd/abapAddonAssemblyKitCheck_generated.go +++ b/cmd/abapAddonAssemblyKitCheck_generated.go @@ -25,6 +25,7 @@ type abapAddonAssemblyKitCheckOptions struct { Password string `json:"password,omitempty"` AddonDescriptorFileName string `json:"addonDescriptorFileName,omitempty"` AddonDescriptor string `json:"addonDescriptor,omitempty"` + AbapAddonAssemblyKitOriginHash string `json:"abapAddonAssemblyKitOriginHash,omitempty"` } type abapAddonAssemblyKitCheckCommonPipelineEnvironment struct { @@ -97,6 +98,7 @@ For Terminology refer to the [Scenario Description](https://www.project-piper.io log.RegisterSecret(stepConfig.AbapAddonAssemblyKitCertificatePass) log.RegisterSecret(stepConfig.Username) log.RegisterSecret(stepConfig.Password) + log.RegisterSecret(stepConfig.AbapAddonAssemblyKitOriginHash) if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 { sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID) @@ -173,6 +175,7 @@ func addAbapAddonAssemblyKitCheckFlags(cmd *cobra.Command, stepConfig *abapAddon cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password for the Addon Assembly Kit as a Service (AAKaaS) system") cmd.Flags().StringVar(&stepConfig.AddonDescriptorFileName, "addonDescriptorFileName", `addon.yml`, "File name of the YAML file which describes the Product Version and corresponding Software Component Versions") cmd.Flags().StringVar(&stepConfig.AddonDescriptor, "addonDescriptor", os.Getenv("PIPER_addonDescriptor"), "Structure in the commonPipelineEnvironment containing information about the Product Version and corresponding Software Component Versions") + cmd.Flags().StringVar(&stepConfig.AbapAddonAssemblyKitOriginHash, "abapAddonAssemblyKitOriginHash", os.Getenv("PIPER_abapAddonAssemblyKitOriginHash"), "Origin Hash for restricted AAKaaS scenarios") cmd.MarkFlagRequired("abapAddonAssemblyKitEndpoint") cmd.MarkFlagRequired("addonDescriptorFileName") @@ -274,6 +277,15 @@ func abapAddonAssemblyKitCheckMetadata() config.StepData { Aliases: []config.Alias{}, Default: os.Getenv("PIPER_addonDescriptor"), }, + { + Name: "abapAddonAssemblyKitOriginHash", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_abapAddonAssemblyKitOriginHash"), + }, }, }, Outputs: config.StepOutputs{ diff --git a/cmd/abapEnvironmentCloneGitRepo_generated.go b/cmd/abapEnvironmentCloneGitRepo_generated.go index 8e160194f1..4a474950ed 100644 --- a/cmd/abapEnvironmentCloneGitRepo_generated.go +++ b/cmd/abapEnvironmentCloneGitRepo_generated.go @@ -20,7 +20,7 @@ type abapEnvironmentCloneGitRepoOptions struct { Password string `json:"password,omitempty"` ByogUsername string `json:"byogUsername,omitempty"` ByogPassword string `json:"byogPassword,omitempty"` - ByogAuthMethod string `json:"byogAuthMethod,omitempty"` + ByogAuthMethod string `json:"byogAuthMethod,omitempty" validate:"possible-values=TOKEN BASIC"` Repositories string `json:"repositories,omitempty"` RepositoryName string `json:"repositoryName,omitempty"` BranchName string `json:"branchName,omitempty"` @@ -145,7 +145,7 @@ func addAbapEnvironmentCloneGitRepoFlags(cmd *cobra.Command, stepConfig *abapEnv cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0948") cmd.Flags().StringVar(&stepConfig.ByogUsername, "byogUsername", os.Getenv("PIPER_byogUsername"), "Username for bring your own git (BYOG) authentication") cmd.Flags().StringVar(&stepConfig.ByogPassword, "byogPassword", os.Getenv("PIPER_byogPassword"), "Password for bring your own git (BYOG) authentication") - cmd.Flags().StringVar(&stepConfig.ByogAuthMethod, "byogAuthMethod", os.Getenv("PIPER_byogAuthMethod"), "Specifies which authentication method is used for bring your own git (BYOG) repositories") + cmd.Flags().StringVar(&stepConfig.ByogAuthMethod, "byogAuthMethod", `TOKEN`, "Specifies which authentication method is used for bring your own git (BYOG) repositories") cmd.Flags().StringVar(&stepConfig.Repositories, "repositories", os.Getenv("PIPER_repositories"), "Specifies a YAML file containing the repositories configuration") cmd.Flags().StringVar(&stepConfig.RepositoryName, "repositoryName", os.Getenv("PIPER_repositoryName"), "Specifies a repository (Software Components) on the SAP BTP ABAP Environment system") cmd.Flags().StringVar(&stepConfig.BranchName, "branchName", os.Getenv("PIPER_branchName"), "Specifies a branch of a repository (Software Components) on the SAP BTP ABAP Environment system") @@ -245,7 +245,7 @@ func abapEnvironmentCloneGitRepoMetadata() config.StepData { Type: "string", Mandatory: false, Aliases: []config.Alias{}, - Default: os.Getenv("PIPER_byogAuthMethod"), + Default: `TOKEN`, }, { Name: "repositories", diff --git a/cmd/ansSendEvent.go b/cmd/ansSendEvent.go index 9376675f0a..484906a9e5 100644 --- a/cmd/ansSendEvent.go +++ b/cmd/ansSendEvent.go @@ -2,10 +2,11 @@ package cmd import ( "encoding/json" + "time" + "github.com/SAP/jenkins-library/pkg/ans" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/telemetry" - "time" ) func ansSendEvent(config ansSendEventOptions, telemetryData *telemetry.CustomData) { diff --git a/cmd/artifactPrepareVersion.go b/cmd/artifactPrepareVersion.go index b8383c46d0..173a693dac 100644 --- a/cmd/artifactPrepareVersion.go +++ b/cmd/artifactPrepareVersion.go @@ -85,6 +85,7 @@ func newArtifactPrepareVersionUtilsBundle() artifactPrepareVersionUtils { Files: &piperutils.Files{}, Client: &piperhttp.Client{}, } + utils.Client.SetOptions(piperhttp.ClientOptions{MaxRetries: 3}) utils.Stdout(log.Writer()) utils.Stderr(log.Writer()) return &utils @@ -208,6 +209,10 @@ func runArtifactPrepareVersion(config *artifactPrepareVersionOptions, telemetryD if config.VersioningType == "cloud" { certs, err := certutils.CertificateDownload(config.CustomTLSCertificateLinks, utils) + if err != nil { + return err + } + // commit changes and push to repository (including new version tag) gitCommitID, err = pushChanges(config, newVersion, repository, worktree, now, certs) if err != nil { diff --git a/cmd/azureBlobUpload_generated.go b/cmd/azureBlobUpload_generated.go index a6b69faab8..85b2627283 100644 --- a/cmd/azureBlobUpload_generated.go +++ b/cmd/azureBlobUpload_generated.go @@ -145,6 +145,12 @@ func azureBlobUploadMetadata() config.StepData { { Name: "jsonCredentialsAzure", ResourceRef: []config.ResourceReference{ + { + Name: "azureDevOpsVaultSecretName", + Type: "vaultSecret", + Default: "azure-dev-ops", + }, + { Name: "azureCredentialsId", Type: "secret", diff --git a/cmd/cloudFoundryDeploy.go b/cmd/cloudFoundryDeploy.go index 4bf7cf40e2..79a4e19aa2 100644 --- a/cmd/cloudFoundryDeploy.go +++ b/cmd/cloudFoundryDeploy.go @@ -148,7 +148,7 @@ func validateAppName(appName string) error { } message = append(message, fmt.Sprintf("Please change the name to fit this requirement(s). For more details please visit %s.", docuLink)) if fail { - return fmt.Errorf(strings.Join(message, " ")) + return errors.New(strings.Join(message, " ")) } return nil } diff --git a/cmd/cnbBuild.go b/cmd/cnbBuild.go index 6ee7a5d3d1..1bc012df79 100644 --- a/cmd/cnbBuild.go +++ b/cmd/cnbBuild.go @@ -168,18 +168,17 @@ func cleanDir(dir string, utils cnbutils.BuildUtils) error { } func extractZip(source, target string) error { - if isZip(source) { - log.Entry().Infof("Extracting archive '%s' to '%s'", source, target) - _, err := piperutils.Unzip(source, target) - if err != nil { - log.SetErrorCategory(log.ErrorBuild) - return errors.Wrapf(err, "Extracting archive '%s' to '%s' failed", source, target) - } - } else { + if !isZip(source) { log.SetErrorCategory(log.ErrorBuild) return errors.New("application path must be a directory or zip") } + log.Entry().Infof("Extracting archive '%s' to '%s'", source, target) + _, err := piperutils.Unzip(source, target) + if err != nil { + log.SetErrorCategory(log.ErrorBuild) + return errors.Wrapf(err, "Extracting archive '%s' to '%s' failed", source, target) + } return nil } @@ -494,7 +493,7 @@ func runCnbBuild(config *cnbBuildOptions, telemetry *buildpacks.Telemetry, image } if pathType != buildpacks.PathEnumArchive { - err = cnbutils.CopyProject(source, target, include, exclude, utils) + err = cnbutils.CopyProject(source, target, include, exclude, utils, false) if err != nil { log.SetErrorCategory(log.ErrorBuild) return errors.Wrapf(err, "Copying '%s' into '%s' failed", source, target) @@ -537,12 +536,6 @@ func runCnbBuild(config *cnbBuildOptions, telemetry *buildpacks.Telemetry, image } } - cnbRegistryAuth, err := cnbutils.GenerateCnbAuth(config.DockerConfigJSON, utils) - if err != nil { - log.SetErrorCategory(log.ErrorConfiguration) - return errors.Wrap(err, "failed to generate CNB_REGISTRY_AUTH") - } - if len(config.CustomTLSCertificateLinks) > 0 { caCertificates := "/tmp/ca-certificates.crt" _, err := utils.Copy("/etc/ssl/certs/ca-certificates.crt", caCertificates) @@ -558,7 +551,17 @@ func runCnbBuild(config *cnbBuildOptions, telemetry *buildpacks.Telemetry, image log.Entry().Info("skipping certificates update") } - utils.AppendEnv([]string{fmt.Sprintf("CNB_REGISTRY_AUTH=%s", cnbRegistryAuth)}) + dockerKeychain, err := cnbutils.ParseDockerConfig(config.DockerConfigJSON, utils) + if err != nil { + log.SetErrorCategory(log.ErrorConfiguration) + return errors.Wrap(err, "failed to parse dockerConfigJSON") + } + cnbAuthString, err := dockerKeychain.ToCNBString() + if err != nil { + log.SetErrorCategory(log.ErrorConfiguration) + return errors.Wrap(err, "failed to generate CNB_REGISTRY_AUTH") + } + utils.AppendEnv([]string{fmt.Sprintf("CNB_REGISTRY_AUTH=%s", cnbAuthString)}) utils.AppendEnv([]string{fmt.Sprintf("CNB_PLATFORM_API=%s", platformAPIVersion)}) creatorArgs := []string{ @@ -574,6 +577,10 @@ func runCnbBuild(config *cnbBuildOptions, telemetry *buildpacks.Telemetry, image } if config.RunImage != "" { + if !dockerKeychain.AuthExistsForImage(config.RunImage) { + log.Entry().Warnf("provided dockerConfigJSON does not contain credentials for the run-image %q, anonymous auth will be used", config.RunImage) + } + creatorArgs = append(creatorArgs, "-run-image", config.RunImage) } @@ -582,6 +589,9 @@ func runCnbBuild(config *cnbBuildOptions, telemetry *buildpacks.Telemetry, image } containerImage := path.Join(targetImage.ContainerRegistry.Host, targetImage.ContainerImageName) + if !dockerKeychain.AuthExistsForImage(containerImage) { + log.Entry().Warnf("provided dockerConfigJSON does not contain credentials for the target image %q, anonymous auth will be used", containerImage) + } for _, tag := range config.AdditionalTags { target := fmt.Sprintf("%s:%s", containerImage, tag) if !piperutils.ContainsString(creatorArgs, target) { @@ -609,7 +619,7 @@ func runCnbBuild(config *cnbBuildOptions, telemetry *buildpacks.Telemetry, image if len(config.PreserveFiles) > 0 { if pathType != buildpacks.PathEnumArchive { - err = cnbutils.CopyProject(target, source, ignore.CompileIgnoreLines(config.PreserveFiles...), nil, utils) + err = cnbutils.CopyProject(target, source, ignore.CompileIgnoreLines(config.PreserveFiles...), nil, utils, true) if err != nil { log.SetErrorCategory(log.ErrorBuild) return errors.Wrapf(err, "failed to preserve files using glob '%s'", config.PreserveFiles) diff --git a/cmd/cnbBuild_test.go b/cmd/cnbBuild_test.go index 0fe38a8c7a..f17c022a84 100644 --- a/cmd/cnbBuild_test.go +++ b/cmd/cnbBuild_test.go @@ -504,7 +504,7 @@ func TestRunCnbBuild(t *testing.T) { addBuilderFiles(&utils) err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) - assert.EqualError(t, err, "failed to generate CNB_REGISTRY_AUTH: json: cannot unmarshal string into Go struct field ConfigFile.auths of type types.AuthConfig") + assert.EqualError(t, err, "failed to parse dockerConfigJSON: json: cannot unmarshal string into Go struct field ConfigFile.auths of type types.AuthConfig") }) t.Run("error case: DockerConfigJSON file not there (config.json)", func(t *testing.T) { diff --git a/cmd/codeqlExecuteScan.go b/cmd/codeqlExecuteScan.go index 88b833ab78..fe66e8dc31 100644 --- a/cmd/codeqlExecuteScan.go +++ b/cmd/codeqlExecuteScan.go @@ -482,7 +482,7 @@ func getMavenSettings(buildCmd string, config *codeqlExecuteScanOptions, utils c return params } for i := 1; i < len(mvnParams); i += 2 { - params = fmt.Sprintf("%s %s=%s", params, mvnParams[i-1], mvnParams[i]) + params = fmt.Sprintf("%s \"%s=%s\"", params, mvnParams[i-1], mvnParams[i]) } } return params diff --git a/cmd/codeqlExecuteScan_test.go b/cmd/codeqlExecuteScan_test.go index 4f8580eba4..959d3c9c7c 100644 --- a/cmd/codeqlExecuteScan_test.go +++ b/cmd/codeqlExecuteScan_test.go @@ -56,7 +56,7 @@ func TestGetMavenSettings(t *testing.T) { params := getMavenSettings(buildCmd, &config, newCodeqlExecuteScanTestsUtils()) dir, _ := os.Getwd() projectSettingsPath := filepath.Join(dir, "test.xml") - expectedCommand := fmt.Sprintf(" --settings=%s", projectSettingsPath) + expectedCommand := fmt.Sprintf(" \"--settings=%s\"", projectSettingsPath) assert.Equal(t, expectedCommand, params) }) @@ -73,7 +73,7 @@ func TestGetMavenSettings(t *testing.T) { params := getMavenSettings(buildCmd, &config, newCodeqlExecuteScanTestsUtils()) dir, _ := os.Getwd() globalSettingsPath := filepath.Join(dir, "global.xml") - expectedCommand := fmt.Sprintf(" --global-settings=%s", globalSettingsPath) + expectedCommand := fmt.Sprintf(" \"--global-settings=%s\"", globalSettingsPath) assert.Equal(t, expectedCommand, params) }) @@ -84,7 +84,7 @@ func TestGetMavenSettings(t *testing.T) { dir, _ := os.Getwd() globalSettingsPath := filepath.Join(dir, "global.xml") projectSettingsPath := filepath.Join(dir, "test.xml") - expectedCommand := fmt.Sprintf(" --global-settings=%s --settings=%s", globalSettingsPath, projectSettingsPath) + expectedCommand := fmt.Sprintf(" \"--global-settings=%s\" \"--settings=%s\"", globalSettingsPath, projectSettingsPath) assert.Equal(t, expectedCommand, params) }) @@ -94,7 +94,7 @@ func TestGetMavenSettings(t *testing.T) { params := getMavenSettings(buildCmd, &config, newCodeqlExecuteScanTestsUtils()) dir, _ := os.Getwd() projectSettingsPath := filepath.Join(dir, ".pipeline/mavenProjectSettings.xml") - expectedCommand := fmt.Sprintf(" --settings=%s", projectSettingsPath) + expectedCommand := fmt.Sprintf(" \"--settings=%s\"", projectSettingsPath) assert.Equal(t, expectedCommand, params) }) @@ -104,7 +104,7 @@ func TestGetMavenSettings(t *testing.T) { params := getMavenSettings(buildCmd, &config, newCodeqlExecuteScanTestsUtils()) dir, _ := os.Getwd() projectSettingsPath := filepath.Join(dir, ".pipeline/mavenProjectSettings.xml") - expectedCommand := fmt.Sprintf(" --settings=%s", projectSettingsPath) + expectedCommand := fmt.Sprintf(" \"--settings=%s\"", projectSettingsPath) assert.Equal(t, expectedCommand, params) }) @@ -114,7 +114,7 @@ func TestGetMavenSettings(t *testing.T) { params := getMavenSettings(buildCmd, &config, newCodeqlExecuteScanTestsUtils()) dir, _ := os.Getwd() globalSettingsPath := filepath.Join(dir, ".pipeline/mavenGlobalSettings.xml") - expectedCommand := fmt.Sprintf(" --global-settings=%s", globalSettingsPath) + expectedCommand := fmt.Sprintf(" \"--global-settings=%s\"", globalSettingsPath) assert.Equal(t, expectedCommand, params) }) @@ -124,7 +124,7 @@ func TestGetMavenSettings(t *testing.T) { params := getMavenSettings(buildCmd, &config, newCodeqlExecuteScanTestsUtils()) dir, _ := os.Getwd() globalSettingsPath := filepath.Join(dir, ".pipeline/mavenGlobalSettings.xml") - expectedCommand := fmt.Sprintf(" --global-settings=%s", globalSettingsPath) + expectedCommand := fmt.Sprintf(" \"--global-settings=%s\"", globalSettingsPath) assert.Equal(t, expectedCommand, params) }) @@ -135,7 +135,7 @@ func TestGetMavenSettings(t *testing.T) { dir, _ := os.Getwd() globalSettingsPath := filepath.Join(dir, ".pipeline/mavenGlobalSettings.xml") projectSettingsPath := filepath.Join(dir, ".pipeline/mavenProjectSettings.xml") - expectedCommand := fmt.Sprintf(" --global-settings=%s --settings=%s", globalSettingsPath, projectSettingsPath) + expectedCommand := fmt.Sprintf(" \"--global-settings=%s\" \"--settings=%s\"", globalSettingsPath, projectSettingsPath) assert.Equal(t, expectedCommand, params) }) @@ -146,7 +146,7 @@ func TestGetMavenSettings(t *testing.T) { dir, _ := os.Getwd() globalSettingsPath := filepath.Join(dir, ".pipeline/mavenGlobalSettings.xml") projectSettingsPath := filepath.Join(dir, ".pipeline/mavenProjectSettings.xml") - expectedCommand := fmt.Sprintf(" --global-settings=%s --settings=%s", globalSettingsPath, projectSettingsPath) + expectedCommand := fmt.Sprintf(" \"--global-settings=%s\" \"--settings=%s\"", globalSettingsPath, projectSettingsPath) assert.Equal(t, expectedCommand, params) }) @@ -157,7 +157,7 @@ func TestGetMavenSettings(t *testing.T) { dir, _ := os.Getwd() globalSettingsPath := filepath.Join(dir, ".pipeline/mavenGlobalSettings.xml") projectSettingsPath := filepath.Join(dir, "test.xml") - expectedCommand := fmt.Sprintf(" --global-settings=%s --settings=%s", globalSettingsPath, projectSettingsPath) + expectedCommand := fmt.Sprintf(" \"--global-settings=%s\" \"--settings=%s\"", globalSettingsPath, projectSettingsPath) assert.Equal(t, expectedCommand, params) }) @@ -168,7 +168,7 @@ func TestGetMavenSettings(t *testing.T) { dir, _ := os.Getwd() globalSettingsPath := filepath.Join(dir, ".pipeline/mavenGlobalSettings.xml") projectSettingsPath := filepath.Join(dir, "test.xml") - expectedCommand := fmt.Sprintf(" --global-settings=%s --settings=%s", globalSettingsPath, projectSettingsPath) + expectedCommand := fmt.Sprintf(" \"--global-settings=%s\" \"--settings=%s\"", globalSettingsPath, projectSettingsPath) assert.Equal(t, expectedCommand, params) }) @@ -179,7 +179,7 @@ func TestGetMavenSettings(t *testing.T) { dir, _ := os.Getwd() globalSettingsPath := filepath.Join(dir, "global.xml") projectSettingsPath := filepath.Join(dir, ".pipeline/mavenProjectSettings.xml") - expectedCommand := fmt.Sprintf(" --global-settings=%s --settings=%s", globalSettingsPath, projectSettingsPath) + expectedCommand := fmt.Sprintf(" \"--global-settings=%s\" \"--settings=%s\"", globalSettingsPath, projectSettingsPath) assert.Equal(t, expectedCommand, params) }) @@ -190,7 +190,7 @@ func TestGetMavenSettings(t *testing.T) { dir, _ := os.Getwd() globalSettingsPath := filepath.Join(dir, "global.xml") projectSettingsPath := filepath.Join(dir, ".pipeline/mavenProjectSettings.xml") - expectedCommand := fmt.Sprintf(" --global-settings=%s --settings=%s", globalSettingsPath, projectSettingsPath) + expectedCommand := fmt.Sprintf(" \"--global-settings=%s\" \"--settings=%s\"", globalSettingsPath, projectSettingsPath) assert.Equal(t, expectedCommand, params) }) } @@ -246,7 +246,7 @@ func TestUpdateCmdFlag(t *testing.T) { dir, _ := os.Getwd() globalSettingsPath := filepath.Join(dir, "global.xml") projectSettingsPath := filepath.Join(dir, "test.xml") - expectedCommand := fmt.Sprintf("mvn clean install --global-settings=%s --settings=%s", globalSettingsPath, projectSettingsPath) + expectedCommand := fmt.Sprintf("mvn clean install \"--global-settings=%s\" \"--settings=%s\"", globalSettingsPath, projectSettingsPath) assert.Equal(t, expectedCommand, customFlags["--command"]) assert.Equal(t, "", customFlags["-c"]) }) diff --git a/cmd/contrastExecuteScan.go b/cmd/contrastExecuteScan.go index d25c652a25..4ae0b39f6e 100644 --- a/cmd/contrastExecuteScan.go +++ b/cmd/contrastExecuteScan.go @@ -10,6 +10,7 @@ import ( "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperutils" "github.com/SAP/jenkins-library/pkg/telemetry" + "github.com/pkg/errors" ) type contrastExecuteScanUtils interface { @@ -107,7 +108,7 @@ func runContrastExecuteScan(config *contrastExecuteScanOptions, telemetryData *t if unaudited > config.VulnerabilityThresholdTotal { msg := fmt.Sprintf("Your application %v in organization %v is not compliant. Total unaudited issues are %v which is greater than the VulnerabilityThresholdTotal count %v", config.ApplicationID, config.OrganizationID, unaudited, config.VulnerabilityThresholdTotal) - return reports, fmt.Errorf(msg) + return reports, errors.New(msg) } } } diff --git a/cmd/detectExecuteScan.go b/cmd/detectExecuteScan.go index 3b7952ff2a..e0f6a68444 100644 --- a/cmd/detectExecuteScan.go +++ b/cmd/detectExecuteScan.go @@ -845,7 +845,7 @@ func postScanChecksAndReporting(ctx context.Context, config detectExecuteScanOpt } if len(errorsOccured) > 0 { - return fmt.Errorf(strings.Join(errorsOccured, ": ")) + return errors.New(strings.Join(errorsOccured, ": ")) } return nil diff --git a/cmd/detectExecuteScan_test.go b/cmd/detectExecuteScan_test.go index 500e9d081c..7f02817729 100644 --- a/cmd/detectExecuteScan_test.go +++ b/cmd/detectExecuteScan_test.go @@ -92,7 +92,7 @@ func newBlackduckMockSystem(config detectExecuteScanOptions) blackduckSystem { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, "https://my.blackduck.system/api/projects/5ca86e11/versions/a6c94786/components?limit=999&offset=0": componentsContent, "https://my.blackduck.system/api/projects/5ca86e11/versions/a6c94786/vunlerable-bom-components?limit=999&offset=0": vulnerabilitiesContent, @@ -749,7 +749,6 @@ func TestAddDetectArgs(t *testing.T) { "--detect.blackduck.signature.scanner.paths=path1,path2", "--detect.source.path='.'", "--detect.blackduck.scan.mode='RAPID'", - "--detect.blackduck.rapid.compare.mode='BOM_COMPARE_STRICT'", "--detect.cleanup=false", "--detect.output.path='report'", }, diff --git a/cmd/jsonApplyPatch.go b/cmd/jsonApplyPatch.go index 14196201df..a64bc3d665 100644 --- a/cmd/jsonApplyPatch.go +++ b/cmd/jsonApplyPatch.go @@ -3,10 +3,11 @@ package cmd import ( "bytes" "encoding/json" + "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperutils" "github.com/SAP/jenkins-library/pkg/telemetry" - "github.com/evanphx/json-patch" + jsonpatch "github.com/evanphx/json-patch" ) func jsonApplyPatch(config jsonApplyPatchOptions, telemetryData *telemetry.CustomData) { diff --git a/cmd/malwareExecuteScan.go b/cmd/malwareExecuteScan.go index 55c90a0e5d..ec76c921f2 100644 --- a/cmd/malwareExecuteScan.go +++ b/cmd/malwareExecuteScan.go @@ -3,6 +3,11 @@ package cmd import ( "encoding/json" "fmt" + "io" + "os" + "strings" + "time" + piperDocker "github.com/SAP/jenkins-library/pkg/docker" piperhttp "github.com/SAP/jenkins-library/pkg/http" "github.com/SAP/jenkins-library/pkg/log" @@ -11,10 +16,6 @@ import ( "github.com/SAP/jenkins-library/pkg/telemetry" "github.com/SAP/jenkins-library/pkg/toolrecord" "github.com/pkg/errors" - "io" - "os" - "strings" - "time" ) type malwareScanUtils interface { diff --git a/cmd/mavenBuild.go b/cmd/mavenBuild.go index c1e61c0a55..af6461a8af 100644 --- a/cmd/mavenBuild.go +++ b/cmd/mavenBuild.go @@ -1,18 +1,21 @@ package cmd import ( + "encoding/json" "os" "path" "path/filepath" "reflect" "strings" + "github.com/SAP/jenkins-library/pkg/build" "github.com/SAP/jenkins-library/pkg/buildsettings" "github.com/SAP/jenkins-library/pkg/command" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/maven" "github.com/SAP/jenkins-library/pkg/piperutils" "github.com/SAP/jenkins-library/pkg/telemetry" + "github.com/SAP/jenkins-library/pkg/versioning" "github.com/pkg/errors" piperhttp "github.com/SAP/jenkins-library/pkg/http" @@ -159,7 +162,45 @@ func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomDat mavenOptions.Goals = []string{"deploy"} mavenOptions.Defines = []string{} _, err := maven.Execute(&mavenOptions, utils) - return err + if err != nil { + return err + } + if config.CreateBuildArtifactsMetadata { + buildCoordinates := []versioning.Coordinates{} + options := versioning.Options{} + var utils versioning.Utils + + matches, _ := fileUtils.Glob("**/pom.xml") + for _, match := range matches { + + artifact, err := versioning.GetArtifact("maven", match, &options, utils) + if err != nil { + log.Entry().Warnf("unable to get artifact metdata : %v", err) + } else { + coordinate, err := artifact.GetCoordinates() + if err != nil { + log.Entry().Warnf("unable to get artifact coordinates : %v", err) + } else { + coordinate.BuildPath = filepath.Dir(match) + coordinate.URL = config.AltDeploymentRepositoryURL + buildCoordinates = append(buildCoordinates, coordinate) + } + } + } + + if len(buildCoordinates) == 0 { + log.Entry().Warnf("unable to identify artifact coordinates for the maven packages published") + return nil + } + + var buildArtifacts build.BuildArtifacts + + buildArtifacts.Coordinates = buildCoordinates + jsonResult, _ := json.Marshal(buildArtifacts) + commonPipelineEnvironment.custom.mavenBuildArtifacts = string(jsonResult) + } + + return nil } else { log.Entry().Infof("publish not detected, ignoring maven deploy") } diff --git a/cmd/mavenBuild_generated.go b/cmd/mavenBuild_generated.go index 278af421bd..57af28804e 100644 --- a/cmd/mavenBuild_generated.go +++ b/cmd/mavenBuild_generated.go @@ -40,11 +40,13 @@ type mavenBuildOptions struct { JavaCaCertFilePath string `json:"javaCaCertFilePath,omitempty"` BuildSettingsInfo string `json:"buildSettingsInfo,omitempty"` DeployFlags []string `json:"deployFlags,omitempty"` + CreateBuildArtifactsMetadata bool `json:"createBuildArtifactsMetadata,omitempty"` } type mavenBuildCommonPipelineEnvironment struct { custom struct { - buildSettingsInfo string + buildSettingsInfo string + mavenBuildArtifacts string } } @@ -55,6 +57,7 @@ func (p *mavenBuildCommonPipelineEnvironment) persist(path, resourceName string) value interface{} }{ {category: "custom", name: "buildSettingsInfo", value: p.custom.buildSettingsInfo}, + {category: "custom", name: "mavenBuildArtifacts", value: p.custom.mavenBuildArtifacts}, } errCount := 0 @@ -269,6 +272,7 @@ func addMavenBuildFlags(cmd *cobra.Command, stepConfig *mavenBuildOptions) { cmd.Flags().StringVar(&stepConfig.JavaCaCertFilePath, "javaCaCertFilePath", os.Getenv("PIPER_javaCaCertFilePath"), "path to the cacerts file used by Java. When maven publish is set to True and customTlsCertificateLinks (to deploy the artifact to a repository with a self signed cert) are provided to trust the self signed certs, Piper will extend the existing Java cacerts to include the new self signed certs. if not provided Piper will search for the cacerts in $JAVA_HOME/jre/lib/security/cacerts") cmd.Flags().StringVar(&stepConfig.BuildSettingsInfo, "buildSettingsInfo", os.Getenv("PIPER_buildSettingsInfo"), "build settings info is typically filled by the step automatically to create information about the build settings that were used during the maven build . This information is typically used for compliance related processes.") cmd.Flags().StringSliceVar(&stepConfig.DeployFlags, "deployFlags", []string{`-Dmaven.main.skip=true`, `-Dmaven.test.skip=true`, `-Dmaven.install.skip=true`}, "maven deploy flags that will be used when publish is detected.") + cmd.Flags().BoolVar(&stepConfig.CreateBuildArtifactsMetadata, "createBuildArtifactsMetadata", false, "metadata about the artifacts that are build and published , this metadata is generally used by steps downstream in the pipeline") } @@ -507,6 +511,15 @@ func mavenBuildMetadata() config.StepData { Aliases: []config.Alias{}, Default: []string{`-Dmaven.main.skip=true`, `-Dmaven.test.skip=true`, `-Dmaven.install.skip=true`}, }, + { + Name: "createBuildArtifactsMetadata", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"STEPS", "STAGES", "PARAMETERS"}, + Type: "bool", + Mandatory: false, + Aliases: []config.Alias{}, + Default: false, + }, }, }, Containers: []config.Container{ @@ -519,6 +532,7 @@ func mavenBuildMetadata() config.StepData { Type: "piperEnvironment", Parameters: []map[string]interface{}{ {"name": "custom/buildSettingsInfo"}, + {"name": "custom/mavenBuildArtifacts"}, }, }, { diff --git a/cmd/mavenBuild_test.go b/cmd/mavenBuild_test.go index bb0cd11674..c7f6bb3d59 100644 --- a/cmd/mavenBuild_test.go +++ b/cmd/mavenBuild_test.go @@ -135,4 +135,25 @@ func TestMavenBuild(t *testing.T) { assert.Contains(t, mockedUtils.Calls[0].Params, "profile1,profile2") }) + t.Run("mavenBuild should not create build artifacts metadata when CreateBuildArtifactsMetadata is false and Publish is true", func(t *testing.T) { + mockedUtils := newMavenMockUtils() + mockedUtils.AddFile("pom.xml", []byte{}) + config := mavenBuildOptions{CreateBuildArtifactsMetadata: false, Publish: true} + err := runMavenBuild(&config, nil, &mockedUtils, &cpe) + assert.Nil(t, err) + assert.Equal(t, mockedUtils.Calls[0].Exec, "mvn") + assert.Contains(t, mockedUtils.Calls[0].Params, "install") + assert.Empty(t, cpe.custom.mavenBuildArtifacts) + }) + + t.Run("mavenBuild should not create build artifacts metadata when CreateBuildArtifactsMetadata is true and Publish is false", func(t *testing.T) { + mockedUtils := newMavenMockUtils() + mockedUtils.AddFile("pom.xml", []byte{}) + config := mavenBuildOptions{CreateBuildArtifactsMetadata: true, Publish: false} + err := runMavenBuild(&config, nil, &mockedUtils, &cpe) + assert.Nil(t, err) + assert.Equal(t, mockedUtils.Calls[0].Exec, "mvn") + assert.Empty(t, cpe.custom.mavenBuildArtifacts) + }) + } diff --git a/cmd/mavenExecute.go b/cmd/mavenExecute.go index 87d5fb1098..5c2f8cedd8 100644 --- a/cmd/mavenExecute.go +++ b/cmd/mavenExecute.go @@ -1,12 +1,13 @@ package cmd import ( + "os" + "github.com/SAP/jenkins-library/pkg/command" piperhttp "github.com/SAP/jenkins-library/pkg/http" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/maven" "github.com/SAP/jenkins-library/pkg/piperutils" - "os" "github.com/SAP/jenkins-library/pkg/telemetry" ) diff --git a/cmd/mavenExecuteIntegration.go b/cmd/mavenExecuteIntegration.go index 08d385b597..b39785b6d1 100644 --- a/cmd/mavenExecuteIntegration.go +++ b/cmd/mavenExecuteIntegration.go @@ -2,13 +2,14 @@ package cmd import ( "fmt" - "github.com/SAP/jenkins-library/pkg/log" - "github.com/SAP/jenkins-library/pkg/maven" - "github.com/SAP/jenkins-library/pkg/telemetry" "path/filepath" "strconv" "strings" "unicode" + + "github.com/SAP/jenkins-library/pkg/log" + "github.com/SAP/jenkins-library/pkg/maven" + "github.com/SAP/jenkins-library/pkg/telemetry" ) func mavenExecuteIntegration(config mavenExecuteIntegrationOptions, _ *telemetry.CustomData) { diff --git a/cmd/mavenExecuteStaticCodeChecks.go b/cmd/mavenExecuteStaticCodeChecks.go index 6847312865..250293cb04 100644 --- a/cmd/mavenExecuteStaticCodeChecks.go +++ b/cmd/mavenExecuteStaticCodeChecks.go @@ -1,10 +1,11 @@ package cmd import ( + "strconv" + "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/maven" "github.com/SAP/jenkins-library/pkg/telemetry" - "strconv" ) func mavenExecuteStaticCodeChecks(config mavenExecuteStaticCodeChecksOptions, telemetryData *telemetry.CustomData) { diff --git a/cmd/mtaBuild.go b/cmd/mtaBuild.go index 0982c0cb96..4f1ef4c64c 100644 --- a/cmd/mtaBuild.go +++ b/cmd/mtaBuild.go @@ -180,8 +180,10 @@ func runMtaBuild(config mtaBuildOptions, log.Entry().Infof("\"%s\" file found in project sources", mtaYamlFile) } - if err = setTimeStamp(mtaYamlFile, utils); err != nil { - return err + if config.EnableSetTimestamp { + if err = setTimeStamp(mtaYamlFile, utils); err != nil { + return err + } } mtarName, isMtarNativelySuffixed, err := getMtarName(config, mtaYamlFile, utils) diff --git a/cmd/mtaBuild_generated.go b/cmd/mtaBuild_generated.go index fc69335b0d..7912027e97 100644 --- a/cmd/mtaBuild_generated.go +++ b/cmd/mtaBuild_generated.go @@ -43,6 +43,7 @@ type mtaBuildOptions struct { Profiles []string `json:"profiles,omitempty"` BuildSettingsInfo string `json:"buildSettingsInfo,omitempty"` CreateBOM bool `json:"createBOM,omitempty"` + EnableSetTimestamp bool `json:"enableSetTimestamp,omitempty"` } type mtaBuildCommonPipelineEnvironment struct { @@ -245,6 +246,7 @@ func addMtaBuildFlags(cmd *cobra.Command, stepConfig *mtaBuildOptions) { cmd.Flags().StringSliceVar(&stepConfig.Profiles, "profiles", []string{}, "Defines list of maven build profiles to be used. profiles will overwrite existing values in the global settings xml at $M2_HOME/conf/settings.xml") cmd.Flags().StringVar(&stepConfig.BuildSettingsInfo, "buildSettingsInfo", os.Getenv("PIPER_buildSettingsInfo"), "build settings info is typically filled by the step automatically to create information about the build settings that were used during the mta build . This information is typically used for compliance related processes.") cmd.Flags().BoolVar(&stepConfig.CreateBOM, "createBOM", false, "Creates the bill of materials (BOM) using CycloneDX plugin.") + cmd.Flags().BoolVar(&stepConfig.EnableSetTimestamp, "enableSetTimestamp", true, "Enables setting the timestamp in the `mta.yaml` when it contains `${timestamp}`. Disable this when you want the MTA Deploy Service to do this instead.") } @@ -499,6 +501,15 @@ func mtaBuildMetadata() config.StepData { Aliases: []config.Alias{}, Default: false, }, + { + Name: "enableSetTimestamp", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"STEPS", "STAGES", "PARAMETERS"}, + Type: "bool", + Mandatory: false, + Aliases: []config.Alias{}, + Default: true, + }, }, }, Containers: []config.Container{ diff --git a/cmd/mtaBuild_test.go b/cmd/mtaBuild_test.go index a3812900d4..3f127c4944 100644 --- a/cmd/mtaBuild_test.go +++ b/cmd/mtaBuild_test.go @@ -1,6 +1,3 @@ -//go:build unit -// +build unit - package cmd import ( @@ -98,7 +95,7 @@ func TestMtaBuild(t *testing.T) { utilsMock := newMtaBuildTestUtilsBundle() - options := mtaBuildOptions{ApplicationName: "myApp", Platform: "CF", MtarName: "myName", Source: "./", Target: "./"} + options := mtaBuildOptions{ApplicationName: "myApp", Platform: "CF", MtarName: "myName", Source: "./", Target: "./", EnableSetTimestamp: true} utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}")) @@ -149,7 +146,7 @@ func TestMtaBuild(t *testing.T) { utilsMock := newMtaBuildTestUtilsBundle() - options := mtaBuildOptions{ApplicationName: "myApp"} + options := mtaBuildOptions{ApplicationName: "myApp", EnableSetTimestamp: true} utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}")) utilsMock.AddFile("mta.yaml", []byte("already there with-${timestamp}")) diff --git a/cmd/nexusUpload.go b/cmd/nexusUpload.go index 517b022563..16930b9ff5 100644 --- a/cmd/nexusUpload.go +++ b/cmd/nexusUpload.go @@ -2,14 +2,15 @@ package cmd import ( "fmt" - piperhttp "github.com/SAP/jenkins-library/pkg/http" - "github.com/pkg/errors" "io" "net/http" "os" "path/filepath" "strings" + piperhttp "github.com/SAP/jenkins-library/pkg/http" + "github.com/pkg/errors" + b64 "encoding/base64" "github.com/SAP/jenkins-library/pkg/command" diff --git a/cmd/npmExecuteScripts.go b/cmd/npmExecuteScripts.go index b3de55b92b..0b6cd4b18a 100644 --- a/cmd/npmExecuteScripts.go +++ b/cmd/npmExecuteScripts.go @@ -1,12 +1,15 @@ package cmd import ( + "encoding/json" "os" + "github.com/SAP/jenkins-library/pkg/build" "github.com/SAP/jenkins-library/pkg/buildsettings" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/npm" "github.com/SAP/jenkins-library/pkg/telemetry" + "github.com/SAP/jenkins-library/pkg/versioning" ) func npmExecuteScripts(config npmExecuteScriptsOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *npmExecuteScriptsCommonPipelineEnvironment) { @@ -85,9 +88,11 @@ func runNpmExecuteScripts(npmExecutor npm.Executor, config *npmExecuteScriptsOpt } commonPipelineEnvironment.custom.buildSettingsInfo = buildSettingsInfo + buildCoordinates := []versioning.Coordinates{} + if config.Publish { if len(config.BuildDescriptorList) > 0 { - err = npmExecutor.PublishAllPackages(config.BuildDescriptorList, config.RepositoryURL, config.RepositoryUsername, config.RepositoryPassword, config.PackBeforePublish) + err = npmExecutor.PublishAllPackages(config.BuildDescriptorList, config.RepositoryURL, config.RepositoryUsername, config.RepositoryPassword, config.PackBeforePublish, &buildCoordinates) if err != nil { return err } @@ -97,12 +102,25 @@ func runNpmExecuteScripts(npmExecutor npm.Executor, config *npmExecuteScriptsOpt return err } - err = npmExecutor.PublishAllPackages(packageJSONFiles, config.RepositoryURL, config.RepositoryUsername, config.RepositoryPassword, config.PackBeforePublish) + err = npmExecutor.PublishAllPackages(packageJSONFiles, config.RepositoryURL, config.RepositoryUsername, config.RepositoryPassword, config.PackBeforePublish, &buildCoordinates) if err != nil { return err } } } + if config.CreateBuildArtifactsMetadata { + if len(buildCoordinates) == 0 { + log.Entry().Warnf("unable to identify artifact coordinates for the npm packages published") + return nil + } + + var buildArtifacts build.BuildArtifacts + + buildArtifacts.Coordinates = buildCoordinates + jsonResult, _ := json.Marshal(buildArtifacts) + commonPipelineEnvironment.custom.npmBuildArtifacts = string(jsonResult) + } + return nil } diff --git a/cmd/npmExecuteScripts_generated.go b/cmd/npmExecuteScripts_generated.go index 47d2cb1eff..7359c8827f 100644 --- a/cmd/npmExecuteScripts_generated.go +++ b/cmd/npmExecuteScripts_generated.go @@ -22,26 +22,28 @@ import ( ) type npmExecuteScriptsOptions struct { - Install bool `json:"install,omitempty"` - RunScripts []string `json:"runScripts,omitempty"` - DefaultNpmRegistry string `json:"defaultNpmRegistry,omitempty"` - VirtualFrameBuffer bool `json:"virtualFrameBuffer,omitempty"` - ScriptOptions []string `json:"scriptOptions,omitempty"` - BuildDescriptorExcludeList []string `json:"buildDescriptorExcludeList,omitempty"` - BuildDescriptorList []string `json:"buildDescriptorList,omitempty"` - CreateBOM bool `json:"createBOM,omitempty"` - Publish bool `json:"publish,omitempty"` - RepositoryURL string `json:"repositoryUrl,omitempty"` - RepositoryPassword string `json:"repositoryPassword,omitempty"` - RepositoryUsername string `json:"repositoryUsername,omitempty"` - BuildSettingsInfo string `json:"buildSettingsInfo,omitempty"` - PackBeforePublish bool `json:"packBeforePublish,omitempty"` - Production bool `json:"production,omitempty"` + Install bool `json:"install,omitempty"` + RunScripts []string `json:"runScripts,omitempty"` + DefaultNpmRegistry string `json:"defaultNpmRegistry,omitempty"` + VirtualFrameBuffer bool `json:"virtualFrameBuffer,omitempty"` + ScriptOptions []string `json:"scriptOptions,omitempty"` + BuildDescriptorExcludeList []string `json:"buildDescriptorExcludeList,omitempty"` + BuildDescriptorList []string `json:"buildDescriptorList,omitempty"` + CreateBOM bool `json:"createBOM,omitempty"` + Publish bool `json:"publish,omitempty"` + RepositoryURL string `json:"repositoryUrl,omitempty"` + RepositoryPassword string `json:"repositoryPassword,omitempty"` + RepositoryUsername string `json:"repositoryUsername,omitempty"` + BuildSettingsInfo string `json:"buildSettingsInfo,omitempty"` + PackBeforePublish bool `json:"packBeforePublish,omitempty"` + Production bool `json:"production,omitempty"` + CreateBuildArtifactsMetadata bool `json:"createBuildArtifactsMetadata,omitempty"` } type npmExecuteScriptsCommonPipelineEnvironment struct { custom struct { buildSettingsInfo string + npmBuildArtifacts string } } @@ -52,6 +54,7 @@ func (p *npmExecuteScriptsCommonPipelineEnvironment) persist(path, resourceName value interface{} }{ {category: "custom", name: "buildSettingsInfo", value: p.custom.buildSettingsInfo}, + {category: "custom", name: "npmBuildArtifacts", value: p.custom.npmBuildArtifacts}, } errCount := 0 @@ -241,6 +244,7 @@ func addNpmExecuteScriptsFlags(cmd *cobra.Command, stepConfig *npmExecuteScripts cmd.Flags().StringVar(&stepConfig.BuildSettingsInfo, "buildSettingsInfo", os.Getenv("PIPER_buildSettingsInfo"), "build settings info is typically filled by the step automatically to create information about the build settings that were used during the npm build . This information is typically used for compliance related processes.") cmd.Flags().BoolVar(&stepConfig.PackBeforePublish, "packBeforePublish", false, "used for executing npm pack first, followed by npm publish. This two step maybe required in two cases. case 1) When building multiple npm packages (multiple package.json) please keep this parameter true and also see `buildDescriptorList` or `buildDescriptorExcludeList` to choose which package(s) to publish. case 2)when you are building a single npm (single `package.json` in your repo) / multiple npm (multiple package.json) scoped package(s) and have npm dependencies from the same scope.") cmd.Flags().BoolVar(&stepConfig.Production, "production", false, "used for omitting installation of dev. dependencies if true") + cmd.Flags().BoolVar(&stepConfig.CreateBuildArtifactsMetadata, "createBuildArtifactsMetadata", false, "metadata about the artifacts that are build and published , this metadata is generally used by steps downstream in the pipeline") } @@ -428,6 +432,15 @@ func npmExecuteScriptsMetadata() config.StepData { Aliases: []config.Alias{}, Default: false, }, + { + Name: "createBuildArtifactsMetadata", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"STEPS", "STAGES", "PARAMETERS"}, + Type: "bool", + Mandatory: false, + Aliases: []config.Alias{}, + Default: false, + }, }, }, Containers: []config.Container{ @@ -440,6 +453,7 @@ func npmExecuteScriptsMetadata() config.StepData { Type: "piperEnvironment", Parameters: []map[string]interface{}{ {"name": "custom/buildSettingsInfo"}, + {"name": "custom/npmBuildArtifacts"}, }, }, { diff --git a/cmd/npmExecuteScripts_test.go b/cmd/npmExecuteScripts_test.go index c98bf70960..af1b7f828a 100644 --- a/cmd/npmExecuteScripts_test.go +++ b/cmd/npmExecuteScripts_test.go @@ -158,40 +158,57 @@ func TestNpmExecuteScripts(t *testing.T) { t.Run("Call with createBOM", func(t *testing.T) { cfg := npmExecuteScriptsOptions{CreateBOM: true, RunScripts: []string{"ci-build", "ci-test"}} - options := npm.ExecutorOptions{DefaultNpmRegistry: cfg.DefaultNpmRegistry} - - utils := newNpmMockUtilsBundle() - utils.AddFile("package.json", []byte("{\"name\": \"Test\" }")) - utils.AddFile("src/package.json", []byte("{\"name\": \"Test\" }")) + utils := npm.NewNpmMockUtilsBundle() + utils.AddFile("package.json", []byte("{\"name\": \"Test\", \"scripts\": \"ci-build\" }")) + utils.AddFile("src/package.json", []byte("{\"name\": \"Test\", \"scripts\": \"ci-test\" }")) SetConfigOptions(ConfigCommandOptions{ OpenFile: config.OpenPiperFile, }) - npmExecutor := npm.Execute{Utils: &utils, Options: options} + npmExecutor := npm.NpmExecutorMock{Utils: utils, Config: npm.NpmConfig{Install: cfg.Install, RunScripts: cfg.RunScripts}} err := runNpmExecuteScripts(&npmExecutor, &cfg, &cpe) assert.NoError(t, err) }) - t.Run("Call with production", func(t *testing.T) { - cfg := npmExecuteScriptsOptions{Production: true, RunScripts: []string{"ci-build", "ci-test"}} + t.Run("fail if script not found", func(t *testing.T) { + cfg := npmExecuteScriptsOptions{RunScripts: []string{"ci-build"}} options := npm.ExecutorOptions{DefaultNpmRegistry: cfg.DefaultNpmRegistry} utils := newNpmMockUtilsBundle() utils.AddFile("package.json", []byte("{\"name\": \"Test\" }")) - utils.AddFile("src/package.json", []byte("{\"name\": \"Test\" }")) SetConfigOptions(ConfigCommandOptions{ OpenFile: config.OpenPiperFile, }) npmExecutor := npm.Execute{Utils: &utils, Options: options} + wantError := "could not find any package.json file with script : ci-build " + err := runNpmExecuteScripts(&npmExecutor, &cfg, &cpe) + assert.EqualErrorf(t, err, wantError, "expected to exit with error") + }) + + t.Run("Call with production", func(t *testing.T) { + + cfg := npmExecuteScriptsOptions{Production: true, RunScripts: []string{"ci-build", "ci-test"}} + + utils := npm.NewNpmMockUtilsBundle() + utils.AddFile("package.json", []byte("{\"name\": \"Test\", \"scripts\": \"ci-build\" }")) + utils.AddFile("src/package.json", []byte("{\"name\": \"Test\", \"scripts\": \"ci-test\" }")) + + SetConfigOptions(ConfigCommandOptions{ + OpenFile: config.OpenPiperFile, + }) + + npmExecutor := npm.NpmExecutorMock{Utils: utils, Config: npm.NpmConfig{Install: cfg.Install, RunScripts: cfg.RunScripts}} + err := runNpmExecuteScripts(&npmExecutor, &cfg, &cpe) assert.NoError(t, err) v := os.Getenv("NODE_ENV") assert.Equal(t, "production", v) }) + } diff --git a/cmd/piper.go b/cmd/piper.go index fa6f585363..65741c1d70 100644 --- a/cmd/piper.go +++ b/cmd/piper.go @@ -41,6 +41,7 @@ type GeneralConfigOptions struct { VaultServerURL string VaultNamespace string VaultPath string + TrustEngineToken string HookConfig HookConfiguration MetaDataResolver func() map[string]config.StepData GCPJsonKeyFilePath string @@ -51,10 +52,11 @@ type GeneralConfigOptions struct { // HookConfiguration contains the configuration for supported hooks, so far Sentry and Splunk are supported. type HookConfiguration struct { - SentryConfig SentryConfiguration `json:"sentry,omitempty"` - SplunkConfig SplunkConfiguration `json:"splunk,omitempty"` - PendoConfig PendoConfiguration `json:"pendo,omitempty"` - OIDCConfig OIDCConfiguration `json:"oidc,omitempty"` + SentryConfig SentryConfiguration `json:"sentry,omitempty"` + SplunkConfig SplunkConfiguration `json:"splunk,omitempty"` + PendoConfig PendoConfiguration `json:"pendo,omitempty"` + OIDCConfig OIDCConfiguration `json:"oidc,omitempty"` + TrustEngineConfig TrustEngineConfiguration `json:"trustengine,omitempty"` } // SentryConfiguration defines the configuration options for the Sentry logging system @@ -82,6 +84,12 @@ type OIDCConfiguration struct { RoleID string `json:",roleID,omitempty"` } +type TrustEngineConfiguration struct { + ServerURL string `json:"baseURL,omitempty"` + TokenEndPoint string `json:"tokenEndPoint,omitempty"` + TokenQueryParamName string `json:"tokenQueryParamName,omitempty"` +} + var rootCmd = &cobra.Command{ Use: "piper", Short: "Executes CI/CD steps from project 'Piper' ", @@ -369,6 +377,9 @@ func PrepareConfig(cmd *cobra.Command, metadata *config.StepData, stepName strin } myConfig.SetVaultCredentials(GeneralConfig.VaultRoleID, GeneralConfig.VaultRoleSecretID, GeneralConfig.VaultToken) + GeneralConfig.TrustEngineToken = os.Getenv("PIPER_trustEngineToken") + myConfig.SetTrustEngineToken(GeneralConfig.TrustEngineToken) + if len(GeneralConfig.StepConfigJSON) != 0 { // ignore config & defaults in favor of passed stepConfigJSON stepConfig = config.GetStepConfigWithJSON(flagValues, GeneralConfig.StepConfigJSON, filters) diff --git a/cmd/readPipelineEnv.go b/cmd/readPipelineEnv.go index 8e76ff54e0..a4c2ef8016 100644 --- a/cmd/readPipelineEnv.go +++ b/cmd/readPipelineEnv.go @@ -8,13 +8,14 @@ import ( "encoding/base64" "encoding/json" "fmt" + "io" + "os" + "path" + "github.com/SAP/jenkins-library/pkg/config" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperenv" "github.com/spf13/cobra" - "io" - "os" - "path" ) // ReadPipelineEnv reads the commonPipelineEnvironment from disk and outputs it as JSON diff --git a/cmd/readPipelineEnv_test.go b/cmd/readPipelineEnv_test.go index a3b846aec1..6efcb2ff61 100644 --- a/cmd/readPipelineEnv_test.go +++ b/cmd/readPipelineEnv_test.go @@ -1,9 +1,10 @@ package cmd import ( - "github.com/stretchr/testify/assert" "strings" "testing" + + "github.com/stretchr/testify/assert" ) func TestCpeEncryption(t *testing.T) { diff --git a/cmd/sonarExecuteScan_generated.go b/cmd/sonarExecuteScan_generated.go index 3620a877b9..23672d9587 100644 --- a/cmd/sonarExecuteScan_generated.go +++ b/cmd/sonarExecuteScan_generated.go @@ -331,6 +331,12 @@ func sonarExecuteScanMetadata() config.StepData { Name: "sonarTokenCredentialsId", Type: "secret", }, + + { + Name: "sonarTrustengineSecretName", + Type: "trustengineSecret", + Default: "sonar", + }, }, Scope: []string{"PARAMETERS"}, Type: "string", diff --git a/cmd/terraformExecute.go b/cmd/terraformExecute.go index 2389bc4903..e85344b729 100644 --- a/cmd/terraformExecute.go +++ b/cmd/terraformExecute.go @@ -3,6 +3,7 @@ package cmd import ( "bytes" "fmt" + "github.com/SAP/jenkins-library/pkg/command" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperutils" diff --git a/cmd/vaultRotateSecretId.go b/cmd/vaultRotateSecretId.go index 3844c40edd..c7d6602d93 100644 --- a/cmd/vaultRotateSecretId.go +++ b/cmd/vaultRotateSecretId.go @@ -81,11 +81,12 @@ func runVaultRotateSecretID(utils vaultRotateSecretIDUtils) error { return nil } - log.Entry().Debugf("Your secret ID is about to expire in %.0f", ttl.Round(time.Hour*24).Hours()/24) + log.Entry().Infof("Your secret ID is about to expire in %.0f", ttl.Round(time.Hour*24).Hours()/24) if ttl > time.Duration(config.DaysBeforeExpiry)*24*time.Hour { return nil } + log.Entry().Info("Rotating...") newSecretID, err := utils.GenerateNewAppRoleSecret(GeneralConfig.VaultRoleSecretID, roleName) diff --git a/cmd/version.go b/cmd/version.go index 07e449007c..f42e9ef3c3 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -2,9 +2,10 @@ package cmd import ( "fmt" + "os" + "github.com/SAP/jenkins-library/pkg/log" "github.com/spf13/cobra" - "os" ) // GitCommit ... diff --git a/cmd/whitesourceExecuteScan.go b/cmd/whitesourceExecuteScan.go index 4cea97dc07..1987466d13 100644 --- a/cmd/whitesourceExecuteScan.go +++ b/cmd/whitesourceExecuteScan.go @@ -308,7 +308,7 @@ func checkAndReportScanResults(ctx context.Context, config *ScanOptions, scan *w } if len(checkErrors) > 0 { - return reportPaths, fmt.Errorf(strings.Join(checkErrors, ": ")) + return reportPaths, errors.New(strings.Join(checkErrors, ": ")) } return reportPaths, nil } @@ -674,7 +674,7 @@ func checkSecurityViolations(ctx context.Context, config *ScanOptions, scan *ws. log.Entry().Debugf("Aggregated %v alerts for scanned projects", len(allAlerts)) } - reportPaths, errors := reportGitHubIssuesAndCreateReports( + reportPaths, e := reportGitHubIssuesAndCreateReports( ctx, config, utils, @@ -686,13 +686,13 @@ func checkSecurityViolations(ctx context.Context, config *ScanOptions, scan *ws. vulnerabilitiesCount, ) - allOccurredErrors = append(allOccurredErrors, errors...) + allOccurredErrors = append(allOccurredErrors, e...) if len(allOccurredErrors) > 0 { if vulnerabilitiesCount > 0 { log.SetErrorCategory(log.ErrorCompliance) } - return reportPaths, fmt.Errorf(strings.Join(allOccurredErrors, ": ")) + return reportPaths, errors.New(strings.Join(allOccurredErrors, ": ")) } return reportPaths, nil diff --git a/cmd/writePipelineEnv.go b/cmd/writePipelineEnv.go index 25d72000d1..cbc6842c06 100644 --- a/cmd/writePipelineEnv.go +++ b/cmd/writePipelineEnv.go @@ -8,11 +8,12 @@ import ( b64 "encoding/base64" "encoding/json" "fmt" - "github.com/SAP/jenkins-library/pkg/config" "io" "os" "path/filepath" + "github.com/SAP/jenkins-library/pkg/config" + "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperenv" "github.com/spf13/cobra" diff --git a/documentation/CODE_OF_CONDUCT.md b/documentation/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..84ded8eca4 --- /dev/null +++ b/documentation/CODE_OF_CONDUCT.md @@ -0,0 +1,86 @@ +# SAP Open Source Code of Conduct + +SAP adopts the [Contributor's Covenant 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) +across our open source projects to ensure a welcoming and open culture for everyone involved. + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [ospo@sap.com](mailto:ospo@sap.com) (SAP Open Source Program Office). All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/documentation/CONTRIBUTING_USING_GENAI.md b/documentation/CONTRIBUTING_USING_GENAI.md new file mode 100644 index 0000000000..1ed02c31e2 --- /dev/null +++ b/documentation/CONTRIBUTING_USING_GENAI.md @@ -0,0 +1,12 @@ +# Guideline for AI-generated code contributions to SAP Open Source Software Projects + +As artificial intelligence evolves, AI-generated code is becoming valuable for many software projects, including open-source initiatives. While we recognize the potential benefits of incorporating AI-generated content into our open-source projects there are certain requirements that need to be reflected and adhered to when making contributions. + +When using AI-generated code contributions in OSS Projects, their usage needs to align with Open-Source Software values and legal requirements. We have established these essential guidelines to help contributors navigate the complexities of using AI tools while maintaining compliance with open-source licenses and the broader [Open-Source Definition](https://opensource.org/osd). + +AI-generated code or content can be contributed to SAP Open Source Software projects if the following conditions are met: + +1. **Compliance with AI Tool Terms and Conditions**: Contributors must ensure that the AI tool's terms and conditions do not impose any restrictions on the tool's output that conflict with the project's open-source license or intellectual property policies. This includes ensuring that the AI-generated content adheres to the [Open-Source Definition](https://opensource.org/osd). +2. **Filtering Similar Suggestions**: Contributors must use features provided by AI tools to suppress responses that are similar to third-party materials or flag similarities. We only accept contributions from AI tools with such filtering options. If the AI tool flags any similarities, contributors must review and ensure compliance with the licensing terms of such materials before including them in the project. +3. **Management of Third-Party Materials**: If the AI tool's output includes pre-existing copyrighted materials, including open-source code authored or owned by third parties, contributors must verify that they have the necessary permissions from the original owners. This typically involves ensuring that there is an open-source license or public domain declaration that is compatible with the project's licensing policies. Contributors must also provide appropriate notice and attribution for these third-party materials, along with relevant information about the applicable license terms. +4. **Employer Policies Compliance**: If AI-generated content is contributed in the context of employment, contributors must also adhere to their employer’s policies. This ensures that all contributions are made with proper authorization and respect for relevant corporate guidelines. diff --git a/DEVELOPMENT.md b/documentation/DEVELOPMENT.md similarity index 74% rename from DEVELOPMENT.md rename to documentation/DEVELOPMENT.md index 8ef0ed8a79..2eefc6dc91 100644 --- a/DEVELOPMENT.md +++ b/documentation/DEVELOPMENT.md @@ -11,6 +11,7 @@ 1. [Release](#release) 1. [Pipeline Configuration](#pipeline-configuration) 1. [Security Setup](#security-setup) +1. [Best practices for writing groovy](#best-practices-for-writing-groovy) ## Getting started @@ -19,6 +20,8 @@ 1. Create [a GitHub account](https://github.com/join) 1. Setup [GitHub access via SSH](https://help.github.com/articles/connecting-to-github-with-ssh/) 1. [Create and checkout a repo fork](#checkout-your-fork) +1. [Editorconfig](#editorconfig) +1. [Commit message style](#commit-message-style) 1. Optional: [Get Jenkins related environment](#jenkins-environment) 1. Optional: [Get familiar with Jenkins Pipelines as Code](#jenkins-pipelines) @@ -59,6 +62,16 @@ git remote add upstream git@github.com:sap/jenkins-library.git git remote set-url --push upstream no_push ``` +### EditorConfig + +To ensure a common file format, there is a `.editorConfig` file [in place](../.editorconfig). To respect this file, [check](http://editorconfig.org/#download) if your editor does support it natively or you need to download a plugin. + +### Commit Message Style + +Write [meaningful commit messages](http://who-t.blogspot.de/2009/12/on-commit-messages.html) and [adhere to standard formatting](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). + +Good commit messages speed up the review process and help to keep this project maintainable in the long term. + ### Jenkins environment If you want to contribute also to the Jenkins-specific parts like @@ -258,7 +271,7 @@ httpClient.SetOptions(clientOptions) 1. [Global function pointers](#global-function-pointers) 1. [Test Parallelization](#test-parallelization) -Unit tests are done using basic `golang` means. +Unit tests are done using basic `golang` means. As the test files are tagged add the corresponding tag to the run command, as for example `go test -run ^TestRunAbapAddonAssemblyKitCheck$ github.com/SAP/jenkins-library/cmd -tags=unit`. In VSCode this can be done by adding the flag `"-tags=unit"` to the list of `"go.testFlags"` in the `settings.json` of the go extension. Additionally, we encourage you to use [github.com/stretchr/testify/assert](https://github.com/stretchr/testify/assert) in order to have slimmer assertions if you like. A good pattern to follow is this: @@ -694,3 +707,169 @@ All parts that are not relevant for signing were removed. ``` Add the three to four lines to you git config and this will do the necessary such that all your commits will be signed. + +## Best practices for writing groovy + +New steps should be written in go. + +### Coding pattern + +Pipeline steps must not make use of return values. The pattern for sharing parameters between pipeline steps or between a pipeline step and a pipeline script is sharing values via the [`commonPipelineEnvironment`](../vars/commonPipelineEnvironment.groovy). Since there is no return value from a pipeline step the return value of a pipeline step is already `void` rather than `def`. + +### Jenkins credential handling + +References to Jenkins credentials should have meaningful names. + +We are using the following approach for naming Jenkins credentials: + +For username/password credentials: +`CredentialsId` like e.g. `neoCredentialsId` + +For other cases we add further information to the name like: + +* `gitSshCredentialsId` for ssh credentials +* `githubTokenCredentialsId`for token/string credentials +* `gcpFileCredentialsId` for file credentials + +### Code Style + +Generally, the code should follow any stylistic and architectural guidelines prescribed by the project. In the absence of guidelines, mimic the styles and patterns in the existing code-base. + +The intention of this section is to describe the code style for this project. As reference document, the [Groovy's style guide](http://groovy-lang.org/style-guide.html) was taken. For further reading about Groovy's syntax and examples, please refer to this guide. + +This project is intended to run in Jenkins [[2]](https://jenkins.io/doc/book/getting-started/) as part of a Jenkins Pipeline [[3]](https://jenkins.io/doc/book/pipeline/). It is composed by Jenkins Pipeline's syntax, Groovy's syntax and Java's syntax. + +Some Groovy's syntax is not yet supported by Jenkins. It is also the intention of this section to remark which Groovy's syntax is not yet supported by Jenkins. + +As Groovy supports 99% of Java’s syntax [[1]](http://groovy-lang.org/style-guide.html), many Java developers tend to write Groovy code using Java's syntax. Such a developer should also consider the following code style for this project. + +#### General remarks + +Variables, methods, types and so on shall have meaningful self describing names. Doing so makes understanding code easier and requires less commenting. It helps people who did not write the code to understand it better. + +Code shall contain comments to explain the intention of the code when it is unclear what the intention of the author was. In such cases, comments should describe the "why" and not the "what" (that is in the code already). + +#### Omit semicolons + +#### Use the return keyword + +In Groovy it is optional to use the *return* keyword. Use explicitly the *return* keyword for better readability. + +#### Use def + +When using *def* in Groovy, the type is Object. Using *def* simplifies the code, for example imports are not needed, and therefore the development is faster. + +#### Do not use a visibility modifier for public classes and methods + +By default, classes and methods are public, the use of the public modifier is not needed. + +#### Do not omit parentheses for Groovy methods + +In Groovy is possible to omit parentheses for top-level expressions, but [Jenkins Pipeline's syntax](https://jenkins.io/doc/book/pipeline/syntax/) use a block, specifically `pipeline { }` as top-level expression [[4]](https://jenkins.io/doc/book/pipeline/syntax/). Do not omit parenthesis for Groovy methods because Jenkins will interpret the method as a Pipeline Step. Conversely, do omit parenthesis for Jenkins Pipeline's Steps. + +#### Omit the .class suffix + +In Groovy, the .class suffix is not needed. Omit the .class suffix for simplicity and better readability. + +e.g. `new ExpectedException().expect(AbortException.class)` + +--> `new ExpectedException().expect(AbortException)` + +#### Omit getters and setters + +When declaring a field without modifier inside a Groovy bean, the Groovy compiler generates a private field and a getter and setter. + +#### Do not initialize beans with named parameters + +Do not initialize beans with named parameters, because it is not supported by Jenkins: + +e.g. `Version javaVersion = new Version( major: 1, minor: 8)` + +Initialize beans using Java syntax: + +e.g. `Version javaVersion = new Version(1, 8)` + +Use named parameters for Jenkins Pipeline Steps: + +e.g. `sh returnStdout: true, script: command` + +#### Do not use *with()* operator + +The *with* operator is not yet supported by Jenkins, and it must not be used or encapsulated in a @NonCPS method. + +#### Use *==* operator + +Use Groovy’s `==` instead of Java `equals()` to avoid NullPointerExceptions. To compare the references of objects, instead of `==`, you should use `a.is(b)` [[1]](http://groovy-lang.org/style-guide.html). + +#### Use GStrings + +In Groovy, single quotes create Java Strings, and double quotes can create Java Strings or GStrings, depending if there is or not interpolation of variables [[1]](http://groovy-lang.org/style-guide.html). Using GStrings variable and string concatenation is more simple. + +#### Do not use curly braces {} for variables or variable.property + +For variables, or variable.property, drop the curly braces: + +e.g. `echo "[INFO] ${name} version ${version.version} is installed."` + +--> `echo "[INFO] $name version $version.version is installed."` + +#### Use 'single quotes' for Strings and constants + +#### Use "double quotes" for GStrings + +#### Use '''triple single quotes''' for multiline Strings + +#### Use """triple double quotes""" for multiline GStrings + +#### Use /slash/ for regular expressions + +This notation avoids to double escape backslashes, making easier working with regex. + +#### Use native syntax for data structures + +Use the native syntax for data structures provided by Groovy like lists, maps, regex, or ranges of values. + +#### Use aditional Groovy methods + +Use the additional methods provided by Groovy to manipulate String, Files, Streams, Collections, and other classes. +For a complete description of all available methods, please read the GDK API [[5]](http://groovy-lang.org/groovy-dev-kit.html). + +#### Use Groovy's switch + +Groovy’s switch accepts any kind of type, thereby is more powerful. In this case, the use of *def* instead of a type is necessary. + +#### Use alias for import + +In Groovy, it is possible to assign an alias to imported packages. Use alias for imported packages to avoid the use of fully-qualified names and increase readability. + +#### Use Groovy syntax to check objects + +In Groovy a null, void, equal to zero, or empty object evaluates to false, and if not, evaluates to true. Instead of writing null and size checks e.g. `if (name != null && name.length > 0) {}`, use just the object `if (name) {}`. + +#### Use *?.* operator + +Use the safe dereference operator *?.*, to simplify the code for accessing objects and object members safely. Using this operator, the Groovy compiler checks null objects and null object members, and returns *null* if the object or the object member is null and never throws a NullPointerException. + +#### Use *?:* operator + +Use Elvis operator *?:* to simplify default value validations. + +#### Use *any* keyword + +If the type of the exception thrown inside a try block is not important, catch any exception using the *any* keyword. + +#### Use *assert* + +To check parameters, return values, and more, use the assert statement. + +### References + +[1] Groovy's syntax: [http://groovy-lang.org/style-guide.html](http://groovy-lang.org/style-guide.html) + +[2] Jenkins: [https://jenkins.io/doc/book/getting-started/](https://jenkins.io/doc/book/getting-started/) + +[3] Jenkins Pipeline: [https://jenkins.io/doc/book/pipeline/](https://jenkins.io/doc/book/pipeline/) + +[4] Jenkins Pipeline's syntax: [https://jenkins.io/doc/book/pipeline/syntax/](https://jenkins.io/doc/book/pipeline/syntax/) + +[5] GDK: Groovy Development Kit: [http://groovy-lang.org/groovy-dev-kit.html](http://groovy-lang.org/groovy-dev-kit.html) diff --git a/documentation/docs/index.md b/documentation/docs/index.md index 081ce6d45a..e63e739e92 100644 --- a/documentation/docs/index.md +++ b/documentation/docs/index.md @@ -26,7 +26,7 @@ If you don't need to care about the underlying infrastructure of your pipelines, ![SAP CI/CD vs Project "Piper"](images/CICD_Piper.png "Solution Comparison") -The support infrastructure for SAP Continuous Integration and Delivery is provided by SAP according to the Service Level Agreements (SLAs). Project "Piper" offers community support using GitHub issues and pull requests. Users are free to contribute to the repository independently. See [Contributing](https://github.com/SAP/jenkins-library/blob/master/.github/CONTRIBUTING.md). +The support infrastructure for SAP Continuous Integration and Delivery is provided by SAP according to the Service Level Agreements (SLAs). Project "Piper" offers community support using GitHub issues and pull requests. Users are free to contribute to the repository independently. See [Contributing](https://github.com/SAP/jenkins-library/blob/master/CONTRIBUTING.md). For more information about the CI/CD solutions offered by SAP, see [SAP Solutions for Continuous Integration and Delivery](https://help.sap.com/docs/CICD_OVERVIEW/8cacec64ed854b2a88e9a0973e0f97a2/e9fa320181124fa9808d4446a1bf69dd.html). diff --git a/go.mod b/go.mod index 4706e6cdad..fb4bc48b80 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,6 @@ module github.com/SAP/jenkins-library -go 1.21 - -toolchain go1.21.9 - -// It is a locked dependency of github.com/buildpacks/lifecycle@v0.18.4. The maintainers may remove the lock -// in future releases. Check if 'replace' statement still there in their go.mod file. Remove line below if not. -replace github.com/moby/buildkit => github.com/moby/buildkit v0.11.6 +go 1.22.4 require ( cloud.google.com/go/storage v1.38.0 @@ -15,13 +9,14 @@ require ( github.com/Jeffail/gabs/v2 v2.6.1 github.com/Masterminds/sprig v2.22.0+incompatible github.com/antchfx/htmlquery v1.2.4 - github.com/aws/aws-sdk-go-v2/config v1.19.0 - github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0 + github.com/aws/aws-sdk-go-v2/config v1.27.31 + github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0 github.com/bmatcuk/doublestar v1.3.4 github.com/bndr/gojenkins v1.1.1-0.20240109173050-c316119c46d5 - github.com/buildpacks/lifecycle v0.18.4 + github.com/buildpacks/lifecycle v0.18.5 github.com/cloudevents/sdk-go/v2 v2.10.1 - github.com/docker/cli v24.0.6+incompatible + github.com/docker/cli v27.1.0+incompatible + github.com/docker/docker v27.1.1+incompatible github.com/evanphx/json-patch v5.7.0+incompatible github.com/getsentry/sentry-go v0.26.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 @@ -33,7 +28,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 github.com/go-playground/validator/v10 v10.14.1 github.com/google/go-cmp v0.6.0 - github.com/google/go-containerregistry v0.16.1 + github.com/google/go-containerregistry v0.19.0 github.com/google/go-github/v45 v45.2.0 github.com/google/uuid v1.6.0 github.com/hashicorp/go-retryablehttp v0.7.2 @@ -52,18 +47,18 @@ require ( github.com/pkg/errors v0.9.1 github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.8.0 + github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 - github.com/testcontainers/testcontainers-go v0.25.0 + github.com/testcontainers/testcontainers-go v0.33.0 github.com/xuri/excelize/v2 v2.4.1 - golang.org/x/mod v0.16.0 - golang.org/x/oauth2 v0.17.0 - golang.org/x/text v0.14.0 - google.golang.org/api v0.167.0 + golang.org/x/mod v0.17.0 + golang.org/x/oauth2 v0.18.0 + golang.org/x/text v0.16.0 + google.golang.org/api v0.169.0 gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v2 v2.4.0 - helm.sh/helm/v3 v3.14.0 + helm.sh/helm/v3 v3.14.2 mvdan.cc/xurls/v2 v2.4.0 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd ) @@ -73,42 +68,46 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 // indirect - github.com/Microsoft/hcsshim v0.11.4 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/apex/log v1.9.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16 // indirect + github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cloudflare/circl v1.3.3 // indirect + github.com/containerd/errdefs v0.1.0 // indirect github.com/containerd/log v0.1.0 // indirect - github.com/containerd/typeurl v1.0.2 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/containerd/typeurl/v2 v2.1.1 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/distribution/reference v0.5.0 // indirect + github.com/distribution/reference v0.6.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/go-jose/go-jose/v3 v3.0.1 // indirect + github.com/go-jose/go-jose/v3 v3.0.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/heroku/color v0.0.6 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect - github.com/moby/buildkit v0.12.2 // indirect + github.com/moby/buildkit v0.12.5 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/sys/user v0.1.0 // indirect github.com/oapi-codegen/runtime v1.0.0 // indirect - github.com/opencontainers/runc v1.1.9 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/shirou/gopsutil/v3 v3.23.8 // indirect + github.com/shirou/gopsutil/v3 v3.23.12 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/skeema/knownhosts v1.2.1 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect @@ -117,14 +116,13 @@ require ( go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.17.0 // indirect golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect - golang.org/x/tools v0.17.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240304161311-37d4d3c04a78 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect ) require ( cloud.google.com/go v0.112.1 // indirect - cloud.google.com/go/compute v1.24.0 // indirect + cloud.google.com/go/compute v1.25.1 // indirect cloud.google.com/go/iam v1.1.6 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect @@ -133,35 +131,34 @@ require ( github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect github.com/antchfx/xpath v1.2.0 // indirect github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect - github.com/aws/aws-sdk-go-v2 v1.21.2 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.43 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 // indirect - github.com/aws/smithy-go v1.15.0 // indirect + github.com/aws/aws-sdk-go-v2 v1.30.4 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.30 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.18 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 // indirect + github.com/aws/smithy-go v1.20.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/buildpacks/imgutil v0.0.0-20230919143643-4ec9360d5f02 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/containerd/containerd v1.7.11 // indirect + github.com/containerd/containerd v1.7.20 // indirect github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker v24.0.7+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.0 // indirect - github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect @@ -188,7 +185,7 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.2 // indirect - github.com/gorilla/mux v1.8.0 // indirect + github.com/gorilla/mux v1.8.1 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -206,7 +203,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.17.1 // indirect + github.com/klauspost/compress v1.17.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/magicsong/color-glog v0.0.1 // indirect @@ -229,7 +226,7 @@ require ( github.com/oklog/ulid v1.3.1 // indirect github.com/onsi/ginkgo v1.16.5 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc5 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c github.com/peterbourgon/diskv v2.0.1+incompatible // indirect @@ -250,16 +247,16 @@ require ( go.mongodb.org/mongo-driver v1.11.6 // indirect go.opencensus.io v0.24.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect - golang.org/x/crypto v0.22.0 + golang.org/x/crypto v0.25.0 golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 - golang.org/x/net v0.21.0 // indirect - golang.org/x/sync v0.6.0 - golang.org/x/sys v0.19.0 // indirect - golang.org/x/term v0.19.0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/sync v0.7.0 + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/grpc v1.62.0 // indirect + google.golang.org/grpc v1.64.1 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect @@ -271,7 +268,7 @@ require ( k8s.io/klog/v2 v2.110.1 // indirect k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect k8s.io/utils v0.0.0-20240102154912-e7106e64919e - oras.land/oras-go v1.2.4 // indirect + oras.land/oras-go v1.2.6 // indirect sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect diff --git a/go.sum b/go.sum index 0056522ab2..a03a5990bd 100644 --- a/go.sum +++ b/go.sum @@ -21,8 +21,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= -cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -92,18 +92,16 @@ github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYr github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= -github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/Microsoft/hcsshim v0.11.7 h1:vl/nj3Bar/CvJSYo7gIQPyRWc9f3c6IeSNavBTSZNZQ= +github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= @@ -132,53 +130,48 @@ github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:W github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA= -github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno= -github.com/aws/aws-sdk-go-v2/config v1.19.0 h1:AdzDvwH6dWuVARCl3RTLGRc4Ogy+N7yLFxVxXe1ClQ0= -github.com/aws/aws-sdk-go-v2/config v1.19.0/go.mod h1:ZwDUgFnQgsazQTnWfeLWk5GjeqTQTL8lMkoE1UXzxdE= -github.com/aws/aws-sdk-go-v2/credentials v1.13.43 h1:LU8vo40zBlo3R7bAvBVy/ku4nxGEyZe9N8MqAeFTzF8= -github.com/aws/aws-sdk-go-v2/credentials v1.13.43/go.mod h1:zWJBz1Yf1ZtX5NGax9ZdNjhhI4rgjfgsyk6vTY1yfVg= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 h1:PIktER+hwIG286DqXyvVENjgLTAwGgoeriLDD5C+YlQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13/go.mod h1:f/Ib/qYjhV2/qdsf79H3QP/eRE4AkVyEf6sk7XfZ1tg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 h1:nFBQlGtkbPzp/NjZLuFxRqmT91rLJkgvsEQs68h962Y= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 h1:JRVhO25+r3ar2mKGP7E0LDl8K9/G36gjlqca5iQbaqc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 h1:hze8YsjSh8Wl1rYa1CJpRmXP21BvOBuc76YhW0HsuQ4= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45/go.mod h1:lD5M20o09/LCuQ2mE62Mb/iSdSlCNuj6H5ci7tW7OsE= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23 h1:DWYZIsyqagnWL00f8M/SOr9fN063OEQWn9LLTbdYXsk= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23/go.mod h1:uIiFgURZbACBEQJfqTZPb/jxO7R+9LeoHUFudtIdeQI= -github.com/aws/aws-sdk-go-v2/service/ecr v1.20.2 h1:y6LX9GUoEA3mO0qpFl1ZQHj1rFyPWVphlzebiSt2tKE= -github.com/aws/aws-sdk-go-v2/service/ecr v1.20.2/go.mod h1:Q0LcmaN/Qr8+4aSBrdrXXePqoX0eOuYpJLbYpilmWnA= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2 h1:PpbXaecV3sLAS6rjQiaKw4/jyq3Z8gNzmoJupHAoBp0= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2/go.mod h1:fUHpGXr4DrXkEDpGAjClPsviWf+Bszeb0daKE0blxv8= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26 h1:CeuSeq/8FnYpPtnuIeLQEEvDv9zUjneuYi8EghMBdwQ= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26/go.mod h1:2UqAAwMUXKeRkAHIlDJqvMVgOWkUi/AUXPk/YIe+Dg4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25/go.mod h1:/95IA+0lMnzW6XzqYJRpjjsAbKEORVeO0anQqjd2CNU= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 h1:WWZA/I2K4ptBS1kg0kV1JbBtG/umed0vwHRrmcr9z7k= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37/go.mod h1:vBmDnwWXWxNPFRMmG2m/3MKOe+xEcMDo1tanpaWCcck= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0 h1:e2ooMhpYGhDnBfSvIyusvAwX7KexuZaHbQY2Dyei7VU= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0/go.mod h1:bh2E0CXKZsQN+faiKVqC40vfNMAWheoULBCnEgO9K+8= -github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0 h1:B1G2pSPvbAtQjilPq+Y7jLIzCOwKzuVEl+aBBaNG0AQ= -github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0/go.mod h1:ncltU6n4Nof5uJttDtcNQ537uNuwYqsZZQcpkd2/GUQ= -github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 h1:JuPGc7IkOP4AaqcZSIcyqLpFSqBWK32rM9+a1g6u73k= -github.com/aws/aws-sdk-go-v2/service/sso v1.15.2/go.mod h1:gsL4keucRCgW+xA85ALBpRFfdSLH4kHOVSnLMSuBECo= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 h1:HFiiRkf1SdaAmV3/BHOFZ9DjFynPHj8G/UIO1lQS+fk= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3/go.mod h1:a7bHA82fyUXOm+ZSWKU6PIoBxrjSprdLoM8xPYvzYVg= -github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 h1:0BkLfgeDjfZnZ+MhB3ONb01u9pwFYTCZVhlsSSBvlbU= -github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ= -github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8= -github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231003182221-725682229e60 h1:ONd54l3oubhjMPcj7HpjPWvlFI6WXsu0/W7DsKCPI9w= -github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231003182221-725682229e60/go.mod h1:eSn65Noe23f/Z7A2ESqw3dbhAFSEyzZf38nXcKVNxtE= +github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8= +github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 h1:70PVAiL15/aBMh5LThwgXdSQorVr91L127ttckI9QQU= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4/go.mod h1:/MQxMqci8tlqDH+pjmoLu1i0tbWCUP1hhyMRuFxpQCw= +github.com/aws/aws-sdk-go-v2/config v1.27.31 h1:kxBoRsjhT3pq0cKthgj6RU6bXTm/2SgdoUMyrVw0rAI= +github.com/aws/aws-sdk-go-v2/config v1.27.31/go.mod h1:z04nZdSWFPaDwK3DdJOG2r+scLQzMYuJeW0CujEm9FM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q= +github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16 h1:mimdLQkIX1zr8GIPY1ZtALdBQGxcASiBd2MOp8m/dMc= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16/go.mod h1:YHk6owoSwrIsok+cAH9PENCOGoH5PU2EllX4vLtSrsY= +github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2 h1:2RjzMZp/8PXJUMqiKkDSp7RVj6inF5DpVel35THjV+I= +github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2/go.mod h1:kdk+WJbHcGVbIlRQfSrKyuKkbWDdD8I9NScyS5vZ8eQ= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.4 h1:VjvjAxO4Hu/vRz7aNoMtnxi+WBRdyZPDAjBZjrIwQVo= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.4/go.mod h1:MaIyM8Niqa55SxzMACfiHVhC7xOr0wa9+pRcUWkGKV0= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.18 h1:GckUnpm4EJOAio1c8o25a+b3lVfwVzC9gnSBqiiNmZM= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.18/go.mod h1:Br6+bxfG33Dk3ynmkhsW2Z/t9D4+lRqdLDNCKi85w0U= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHCiSH0jyd6gROjlJtNwov0eGYNz8s8nFcR0jQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16 h1:jg16PhLPUiHIj8zYIW6bqzeQSuHVEiWnGA0Brz5Xv2I= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16/go.mod h1:Uyk1zE1VVdsHSU7096h/rwnXDzOzYQVl+FNPhPw7ShY= +github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0 h1:Wb544Wh+xfSXqJ/j3R4aX9wrKUoZsJNmilBYZb3mKQ4= +github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 h1:OMsEmCyz2i89XwRwPouAJvhj81wINh+4UK+k/0Yo/q8= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.5/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= +github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= +github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231213181459-b0fcec718dc6 h1:PlJRmqKlSlEUlwem1c3zdPaEMtJc/ktnV7naD5Qvsx4= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231213181459-b0fcec718dc6/go.mod h1:08sPJIlDHu4HwQ1xScPgsBWezvM6U10ghGKBJu0mowA= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -194,16 +187,10 @@ github.com/bradleyjkemp/cupaloy/v2 v2.7.0 h1:AT0vOjO68RcLyenLCHOGZzSNiuto7ziqzq6 github.com/bradleyjkemp/cupaloy/v2 v2.7.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/buildpacks/imgutil v0.0.0-20230919143643-4ec9360d5f02 h1:Ac/FoFzAhz34zIDvrC3ivShQgoywg/HrA+Kkcb13Mr4= github.com/buildpacks/imgutil v0.0.0-20230919143643-4ec9360d5f02/go.mod h1:Ade+4Q1OovFw6Zdzd+/UVaqWptZSlpnZ8n/vlkgS7M8= -github.com/buildpacks/lifecycle v0.18.4 h1:LGl/4guzU+57hn08W8RwjLLizYtuNfCZHtxn8TP2+bE= -github.com/buildpacks/lifecycle v0.18.4/go.mod h1:DxxfyFaCi9ovbbP2fhcKBlImfbTPiPEtM5UqSlD1TJ8= +github.com/buildpacks/lifecycle v0.18.5 h1:lfoUX8jYCUZ2/Tr2AopaRjinqDivkNkcTChzysQTo00= +github.com/buildpacks/lifecycle v0.18.5/go.mod h1:Kvuu9IWABPLXc6yHCMtbdmgrGEi7QEiVzi5GGtcAkW0= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= @@ -223,23 +210,27 @@ github.com/cloudevents/sdk-go/v2 v2.10.1/go.mod h1:GpCBmUj7DIRiDhVvsK5d6WCbgTWs8 github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/containerd/containerd v1.7.11 h1:lfGKw3eU35sjV0aG2eYZTiwFEY1pCzxdzicHP3SZILw= -github.com/containerd/containerd v1.7.11/go.mod h1:5UluHxHTX2rdvYuZ5OJTC5m/KJNs0Zs9wVoJm9zf5ZE= +github.com/containerd/containerd v1.7.20 h1:Sl6jQYk3TRavaU83h66QMbI2Nqg9Jm6qzwX57Vsn1SQ= +github.com/containerd/containerd v1.7.20/go.mod h1:52GsS5CwquuqPuLncsXwG0t2CiUce+KsNHJZQJvAgR0= github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM= +github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= -github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY= -github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= +github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -249,24 +240,26 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= -github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= -github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI= -github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= -github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/distribution/distribution/v3 v3.0.0-beta.1 h1:X+ELTxPuZ1Xe5MsD3kp2wfGUhc8I+MPfRis8dZ818Ic= +github.com/distribution/distribution/v3 v3.0.0-beta.1/go.mod h1:O9O8uamhHzWWQVTjuQpyYUVm/ShPHPUDgvQMpHGVBDs= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= -github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v27.1.0+incompatible h1:P0KSYmPtNbmx59wHZvG6+rjivhKDRA1BvvWM0f5DgHc= +github.com/docker/cli v27.1.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= -github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= +github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8= github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= @@ -287,8 +280,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -326,8 +317,8 @@ github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lK github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= -github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= +github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -498,8 +489,6 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= -github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= @@ -517,12 +506,11 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ= -github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= +github.com/google/go-containerregistry v0.19.0 h1:uIsMRBV7m/HDkDxE/nXMnv1q+lOOSPlQ/ywc5JbB8Ic= +github.com/google/go-containerregistry v0.19.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= github.com/google/go-github/v45 v45.2.0 h1:5oRLszbrkvxDDqBCNj2hjDZMKmvexaZ1xw/FCD+K3FI= github.com/google/go-github/v45 v45.2.0/go.mod h1:FObaZJEDSTa/WGCzZ2Z3eoCDXWJKMenWWTrd8jrta28= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -560,12 +548,14 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= -github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= -github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -591,7 +581,10 @@ github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjG github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= -github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw= +github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU= +github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= +github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hashicorp/vault/api v1.9.2 h1:YjkZLJ7K3inKgMZ0wzCU9OHqc+UqMQyXsPXnf3Cl2as= @@ -620,7 +613,6 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -641,8 +633,8 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g= -github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -717,8 +709,10 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/buildkit v0.11.6 h1:VYNdoKk5TVxN7k4RvZgdeM4GOyRvIi4Z8MXOY7xvyUs= -github.com/moby/buildkit v0.11.6/go.mod h1:GCqKfHhz+pddzfgaR7WmHVEE3nKKZMMDPpK8mh3ZLv4= +github.com/moby/buildkit v0.12.5 h1:RNHH1l3HDhYyZafr5EgstEu8aGNCwyfvMtrQDtjH9T0= +github.com/moby/buildkit v0.12.5/go.mod h1:YGwjA2loqyiYfZeEo8FtI7z4x5XponAaIWsWcSjWwso= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= @@ -727,6 +721,8 @@ github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vyg github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= +github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -769,10 +765,8 @@ github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= -github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM= -github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU= @@ -824,6 +818,12 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho= +github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U= +github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc= +github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ= +github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY= +github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c= github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj3nKI= github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o= @@ -847,8 +847,8 @@ github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4Qn github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= -github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= +github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -866,8 +866,8 @@ github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUr github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -893,8 +893,8 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/testcontainers/testcontainers-go v0.25.0 h1:erH6cQjsaJrH+rJDU9qIf89KFdhK0Bft0aEZHlYC3Vs= -github.com/testcontainers/testcontainers-go v0.25.0/go.mod h1:4sC9SiJyzD1XFi59q8umTQYWxnkweEc5OjVtTUlJzqQ= +github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw= +github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= @@ -934,12 +934,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= -github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= -github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= -github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= @@ -956,18 +950,40 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 h1:P+/g8GpuJGYbOp2tAdKrIPUX9JO02q8Q0YNlHolpibA= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0/go.mod h1:tIKj3DbO8N9Y2xo52og3irLsPI4GW02DSMtrVgNMgxg= +go.opentelemetry.io/contrib/exporters/autoexport v0.46.1 h1:ysCfPZB9AjUlMa1UHYup3c9dAOCMQX/6sxSfPBUoxHw= +go.opentelemetry.io/contrib/exporters/autoexport v0.46.1/go.mod h1:ha0aiYm+DOPsLHjh0zoQ8W8sLT+LJ58J3j47lGpSLrU= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0+5t/YynESZqsSyPz+7PAFdEop0dlN0+PkyHYo8oI= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0/go.mod h1:U707O40ee1FpQGyhvqnzmCJm1Wh6OX6GGBVn0E6Uyyk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 h1:bflGWrfYyuulcdxf14V6n9+CoQcu5SAAdHmDPAJnlps= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0/go.mod h1:qcTO4xHAxZLaLxPd60TdE88rxtItPHgHWqOhOGRr0as= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= +go.opentelemetry.io/otel/exporters/prometheus v0.44.0 h1:08qeJgaPC0YEBu2PQMbqU3rogTlyzpjhCI2b58Yn00w= +go.opentelemetry.io/otel/exporters/prometheus v0.44.0/go.mod h1:ERL2uIeBtg4TxZdojHUwzZfIFlUIjZtxubT5p4h1Gjg= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.44.0 h1:dEZWPjVN22urgYCza3PXRUGEyCB++y1sAqm6guWFesk= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.44.0/go.mod h1:sTt30Evb7hJB/gEk27qLb1+l9n4Tb8HvHkR0Wx3S6CU= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 h1:VhlEQAPp9R1ktYfrPk5SOryw1e9LDDTZCbIPFrho0ec= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0/go.mod h1:kB3ufRbfU+CQ4MlUcqtW8Z7YEOBeK2DJ6CmR5rYYF3E= go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0= +go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -988,7 +1004,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -998,8 +1013,9 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1037,8 +1053,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1084,16 +1100,17 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1107,8 +1124,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1176,8 +1193,10 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1185,8 +1204,10 @@ golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1199,8 +1220,10 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1259,8 +1282,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1283,8 +1306,8 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.167.0 h1:CKHrQD1BLRii6xdkatBDXyKzM0mkawt2QP+H3LtPmSE= -google.golang.org/api v0.167.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe/bSA= +google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY= +google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1325,10 +1348,10 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= -google.golang.org/genproto/googleapis/api v0.0.0-20240304161311-37d4d3c04a78 h1:SzXBGiWM1LNVYLCRP3e0/Gsze804l4jGoJ5lYysEO5I= -google.golang.org/genproto/googleapis/api v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 h1:DKU1r6Tj5s1vlU/moGhuGz7E3xRfwjdAfDzbsaQJtEY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1342,8 +1365,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1356,6 +1379,7 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -1388,10 +1412,10 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= -gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= -helm.sh/helm/v3 v3.14.0 h1:TaZIH6uOchn7L27ptwnnuHJiFrT/BsD4dFdp/HLT2nM= -helm.sh/helm/v3 v3.14.0/go.mod h1:2itvvDv2WSZXTllknfQo6j7u3VVgMAvm8POCDgYH424= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +helm.sh/helm/v3 v3.14.2 h1:V71fv+NGZv0icBlr+in1MJXuUIHCiPG1hW9gEBISTIA= +helm.sh/helm/v3 v3.14.2/go.mod h1:2itvvDv2WSZXTllknfQo6j7u3VVgMAvm8POCDgYH424= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1415,8 +1439,8 @@ k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCf k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= mvdan.cc/xurls/v2 v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc= mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg= -oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= -oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324= +oras.land/oras-go v1.2.6 h1:z8cmxQXBU8yZ4mkytWqXfo6tZcamPwjsuxYU81xJ8Lk= +oras.land/oras-go v1.2.6/go.mod h1:OVPc1PegSEe/K8YiLfosrlqlqTN9PUyFvOw5Y9gwrT8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/integration/integration_npm_test.go b/integration/integration_npm_test.go index 5dd25ff3b2..6083798abd 100644 --- a/integration/integration_npm_test.go +++ b/integration/integration_npm_test.go @@ -37,7 +37,7 @@ func TestNPMIntegrationRunScriptsWithOptions(t *testing.T) { //workaround to use test script util it is possible to set workdir for Exec call testScript := `#!/bin/sh cd /test -/piperbin/piper npmExecuteScripts --runScripts=start --scriptOptions=--tag,tag1 >test-log.txt 2>&1 +/piperbin/piper npmExecuteScripts --runScripts=start --scriptOptions=--tag,tag1 >test-log-runScriptWithOptions.txt 2>&1 ` os.WriteFile(filepath.Join(tempDir, "runPiper.sh"), []byte(testScript), 0700) @@ -60,9 +60,9 @@ cd /test assert.NoError(t, err) assert.Equal(t, 0, code) - content, err := os.ReadFile(filepath.Join(tempDir, "/test-log.txt")) + content, err := os.ReadFile(filepath.Join(tempDir, "/test-log-runScriptWithOptions.txt")) if err != nil { - t.Fatal("Could not read test-log.txt.", err) + t.Fatal("Could not read test-log-runScriptWithOptions.txt.", err) } output := string(content) assert.Contains(t, output, "info npmExecuteScripts - running command: npm run start -- --tag tag1") @@ -89,7 +89,7 @@ func TestNPMIntegrationRegistrySetInFlags(t *testing.T) { //workaround to use test script util it is possible to set workdir for Exec call testScript := `#!/bin/sh cd /test -/piperbin/piper npmExecuteScripts --install --runScripts=ci-build,ci-backend-unit-test --defaultNpmRegistry=https://foo.bar >test-log.txt 2>&1 +/piperbin/piper npmExecuteScripts --install --runScripts=ci-build --defaultNpmRegistry=https://foo.bar >test-log-registrySetInFlags.txt 2>&1 ` os.WriteFile(filepath.Join(tempDir, "runPiper.sh"), []byte(testScript), 0700) @@ -112,9 +112,9 @@ cd /test assert.NoError(t, err) assert.Equal(t, 0, code) - content, err := os.ReadFile(filepath.Join(tempDir, "/test-log.txt")) + content, err := os.ReadFile(filepath.Join(tempDir, "/test-log-registrySetInFlags.txt")) if err != nil { - t.Fatal("Could not read test-log.txt.", err) + t.Fatal("Could not read test-log-registrySetInFlags.txt.", err) } output := string(content) assert.Contains(t, output, "info npmExecuteScripts - https://foo.bar") @@ -140,7 +140,7 @@ func TestNPMIntegrationRegistrySetInNpmrc(t *testing.T) { //workaround to use test script util it is possible to set workdir for Exec call testScript := `#!/bin/sh cd /test -/piperbin/piper npmExecuteScripts --install --runScripts=ci-build,ci-backend-unit-test >test-log.txt 2>&1 +/piperbin/piper npmExecuteScripts --install --runScripts=ci-build >test-log-registrySetInNpmrc.txt 2>&1 ` os.WriteFile(filepath.Join(tempDir, "runPiper.sh"), []byte(testScript), 0700) @@ -163,9 +163,9 @@ cd /test assert.NoError(t, err) assert.Equal(t, 0, code) - content, err := os.ReadFile(filepath.Join(tempDir, "/test-log.txt")) + content, err := os.ReadFile(filepath.Join(tempDir, "/test-log-registrySetInNpmrc.txt")) if err != nil { - t.Fatal("Could not read test-log.txt.", err) + t.Fatal("Could not read test-log-registrySetInNpmrc.txt.", err) } output := string(content) assert.Contains(t, output, "info npmExecuteScripts - https://example.com") @@ -191,7 +191,7 @@ func TestNPMIntegrationRegistryWithTwoModules(t *testing.T) { //workaround to use test script util it is possible to set workdir for Exec call testScript := `#!/bin/sh cd /test -/piperbin/piper npmExecuteScripts --install --runScripts=ci-build,ci-backend-unit-test --defaultNpmRegistry=https://foo.bar >test-log.txt 2>&1 +/piperbin/piper npmExecuteScripts --install --runScripts=ci-build --defaultNpmRegistry=https://foo.bar >test-log-registryWithTwoModules.txt 2>&1 ` os.WriteFile(filepath.Join(tempDir, "runPiper.sh"), []byte(testScript), 0700) @@ -214,9 +214,9 @@ cd /test assert.NoError(t, err) assert.Equal(t, 0, code) - content, err := os.ReadFile(filepath.Join(tempDir, "/test-log.txt")) + content, err := os.ReadFile(filepath.Join(tempDir, "/test-log-registryWithTwoModules.txt")) if err != nil { - t.Fatal("Could not read test-log.txt.", err) + t.Fatal("Could not read test-log-registryWithTwoModules.txt.", err) } output := string(content) assert.Contains(t, output, "info npmExecuteScripts - https://example.com") diff --git a/integration/testdata/TestGolangIntegration/golang-project1/go.mod b/integration/testdata/TestGolangIntegration/golang-project1/go.mod index bd761d5a17..abe4430d88 100644 --- a/integration/testdata/TestGolangIntegration/golang-project1/go.mod +++ b/integration/testdata/TestGolangIntegration/golang-project1/go.mod @@ -1,5 +1,5 @@ module github.com/example/golang-app -go 1.21 +go 1.22.4 require github.com/gorilla/mux v1.8.0 diff --git a/integration/testdata/TestGolangIntegration/golang-project2/go.mod b/integration/testdata/TestGolangIntegration/golang-project2/go.mod index e43c18361e..e0e21c40a1 100644 --- a/integration/testdata/TestGolangIntegration/golang-project2/go.mod +++ b/integration/testdata/TestGolangIntegration/golang-project2/go.mod @@ -1,3 +1,3 @@ module github.com/example/golang-app -go 1.21 +go 1.22.4 diff --git a/pkg/abap/aakaas/componentVersion.go b/pkg/abap/aakaas/componentVersion.go index efdb24e91c..4d8dc6df99 100644 --- a/pkg/abap/aakaas/componentVersion.go +++ b/pkg/abap/aakaas/componentVersion.go @@ -21,7 +21,7 @@ func (c *ComponentVersion) ConstructComponentVersion(repo abaputils.Repository, if err := c.constructVersionable(repo.Name, repo.VersionYAML, conn, cvQueryURL); err != nil { return err } - if err := c.resolveNext(statusFilterCV); err != nil { + if err := c.resolveWildCards(statusFilterCV); err != nil { return err } diff --git a/pkg/abap/aakaas/productVersion.go b/pkg/abap/aakaas/productVersion.go index 25743c05de..8f5c585047 100644 --- a/pkg/abap/aakaas/productVersion.go +++ b/pkg/abap/aakaas/productVersion.go @@ -21,7 +21,7 @@ func (p *ProductVersion) ConstructProductversion(desc abaputils.AddonDescriptor, if err := p.constructVersionable(desc.AddonProduct, desc.AddonVersionYAML, conn, pvQueryURL); err != nil { return err } - if err := p.resolveNext(statusFilterPV); err != nil { + if err := p.resolveWildCards(statusFilterPV); err != nil { return err } return nil diff --git a/pkg/abap/aakaas/versionables.go b/pkg/abap/aakaas/versionables.go index d28ab46cc8..7ad2cf3c39 100644 --- a/pkg/abap/aakaas/versionables.go +++ b/pkg/abap/aakaas/versionables.go @@ -12,7 +12,8 @@ import ( "github.com/pkg/errors" ) -const wildCard string = "NEXT" +const wildCardNext string = "NEXT" +const wildCardMax string = "MAXX" const statusFilterCV string = "DeliveryStatus eq 'R'" const statusFilterPV string = "DeliveryStatus eq 'T' or DeliveryStatus eq 'P'" @@ -51,21 +52,31 @@ func (v *versionable) constructVersionable(name string, dottedVersionString stri return nil } +func (v *versionable) resolveWildCards(statusFilter string) error { + if err := v.resolveNext(statusFilter); err != nil { + return err + } + if err := v.resolveMax(statusFilter); err != nil { + return err + } + return nil +} + func (v *versionable) resolveNext(statusFilter string) error { - switch strings.Count(v.Version, wildCard) { + switch strings.Count(v.Version, wildCardNext) { case 0: return nil case 1: log.Entry().Info("Wildcard detected in dotted-version-string. Looking up highest existing package in AAKaaS...") var err error - switch wildCard { + switch wildCardNext { case v.TechRelease: - err = v.resolveRelease(statusFilter) + err = v.resolveRelease(statusFilter, 1) case v.TechSpLevel: - err = v.resolveSpLevel(statusFilter) + err = v.resolveSpLevel(statusFilter, 1) case v.TechPatchLevel: - err = v.resolvePatchLevel(statusFilter) + err = v.resolvePatchLevel(statusFilter, 1) } if err != nil { return err @@ -74,13 +85,32 @@ func (v *versionable) resolveNext(statusFilter string) error { return err } default: - return errors.New("The dotted-version-string must contain only one wildcard " + wildCard) + return errors.New("The dotted-version-string must contain only one wildcard " + wildCardNext) } return nil } -func (v *versionable) resolveRelease(statusFilter string) error { +func (v *versionable) resolveMax(statusFilter string) error { + if v.TechRelease == wildCardMax { + if err := v.resolveRelease(statusFilter, 0); err != nil { + return err + } + } + if v.TechSpLevel == wildCardMax { + if err := v.resolveSpLevel(statusFilter, 0); err != nil { + return err + } + } + if v.TechPatchLevel == wildCardMax { + if err := v.resolvePatchLevel(statusFilter, 0); err != nil { + return err + } + } + return nil +} + +func (v *versionable) resolveRelease(statusFilter string, increment int) error { filter := "Name eq '" + v.Name + "' and TechSpLevel eq '0000' and TechPatchLevel eq '0000' and ( " + statusFilter + " )" orderBy := "TechRelease desc" @@ -90,13 +120,13 @@ func (v *versionable) resolveRelease(statusFilter string) error { if newRelease, err := strconv.Atoi(queryResuult.TechRelease); err != nil { return err } else { - v.TechRelease = strconv.Itoa(newRelease + 1) + v.TechRelease = strconv.Itoa(newRelease + increment) return nil } } } -func (v *versionable) resolveSpLevel(statusFilter string) error { +func (v *versionable) resolveSpLevel(statusFilter string, increment int) error { filter := "Name eq '" + v.Name + "' and TechRelease eq '" + v.TechRelease + "' and TechPatchLevel eq '0000' and ( " + statusFilter + " )" orderBy := "TechSpLevel desc" @@ -106,13 +136,13 @@ func (v *versionable) resolveSpLevel(statusFilter string) error { if newSpLevel, err := strconv.Atoi(queryResuult.TechSpLevel); err != nil { return err } else { - v.TechSpLevel = fmt.Sprintf("%04d", newSpLevel+1) + v.TechSpLevel = fmt.Sprintf("%04d", newSpLevel+increment) return nil } } } -func (v *versionable) resolvePatchLevel(statusFilter string) error { +func (v *versionable) resolvePatchLevel(statusFilter string, increment int) error { filter := "Name eq '" + v.Name + "' and TechRelease eq '" + v.TechRelease + "' and TechSpLevel eq '" + v.TechSpLevel + "' and ( " + statusFilter + " )" orderBy := "TechPatchLevel desc" @@ -122,7 +152,7 @@ func (v *versionable) resolvePatchLevel(statusFilter string) error { if newPatchLevel, err := strconv.Atoi(queryResuult.TechPatchLevel); err != nil { return err } else { - v.TechPatchLevel = fmt.Sprintf("%04d", newPatchLevel+1) + v.TechPatchLevel = fmt.Sprintf("%04d", newPatchLevel+increment) return nil } } diff --git a/pkg/abap/aakaas/versionables_test.go b/pkg/abap/aakaas/versionables_test.go index 816a5da46a..e2b8991422 100644 --- a/pkg/abap/aakaas/versionables_test.go +++ b/pkg/abap/aakaas/versionables_test.go @@ -43,7 +43,7 @@ func TestCvResolve(t *testing.T) { }) t.Run("ComponentVersion NEXT Release Existing", func(t *testing.T) { mc.AddData(testDataAakaasCVGetReleaseExisting) - err := vers.constructVersionable("DummyComp", wildCard+".0.0", *conn, cvQueryURL) + err := vers.constructVersionable("DummyComp", wildCardNext+".0.0", *conn, cvQueryURL) assert.NoError(t, err) err = vers.resolveNext(statusFilterCV) assert.NoError(t, err) @@ -54,7 +54,7 @@ func TestCvResolve(t *testing.T) { }) t.Run("ComponentVersion NEXT Release Non Existing", func(t *testing.T) { mc.AddData(testDataAakaasCVGetReleaseNonExisting) - err := vers.constructVersionable("DummyComp", wildCard+".0.0", *conn, cvQueryURL) + err := vers.constructVersionable("DummyComp", wildCardNext+".0.0", *conn, cvQueryURL) assert.NoError(t, err) err = vers.resolveNext(statusFilterCV) assert.NoError(t, err) @@ -65,7 +65,7 @@ func TestCvResolve(t *testing.T) { }) t.Run("ComponentVersion NEXT SP Level Existing", func(t *testing.T) { mc.AddData(testDataAakaasCVGetSpLevelExisting) - err := vers.constructVersionable("DummyComp", "1."+wildCard+".0", *conn, cvQueryURL) + err := vers.constructVersionable("DummyComp", "1."+wildCardNext+".0", *conn, cvQueryURL) assert.NoError(t, err) err = vers.resolveNext(statusFilterCV) assert.NoError(t, err) @@ -77,7 +77,7 @@ func TestCvResolve(t *testing.T) { t.Run("ComponentVersion NEXT SP Level Non Existing", func(t *testing.T) { //This one should lead to an error later on as AOI is needed - anyway we can't just produce a differen package then customized... mc.AddData(testDataAakaasCVGetSpLevelNonExisting) - err := vers.constructVersionable("DummyComp", "1."+wildCard+".0", *conn, cvQueryURL) + err := vers.constructVersionable("DummyComp", "1."+wildCardNext+".0", *conn, cvQueryURL) assert.NoError(t, err) err = vers.resolveNext(statusFilterCV) assert.NoError(t, err) @@ -88,7 +88,7 @@ func TestCvResolve(t *testing.T) { }) t.Run("ComponentVersion NEXT Patch Level Existing", func(t *testing.T) { mc.AddData(testDataAakaasCVGetPatchLevelExisting) - err := vers.constructVersionable("DummyComp", "1.3."+wildCard, *conn, cvQueryURL) + err := vers.constructVersionable("DummyComp", "1.3."+wildCardNext, *conn, cvQueryURL) assert.NoError(t, err) err = vers.resolveNext(statusFilterCV) assert.NoError(t, err) @@ -100,7 +100,7 @@ func TestCvResolve(t *testing.T) { t.Run("ComponentVersion NEXT Patch Level Non Existing", func(t *testing.T) { //This one should lead to an error later on as AOI is needed - anyway we can't just produce a differen package then customized... mc.AddData(testDataAakaasCVGetPatchLevelNonExisting) - err := vers.constructVersionable("DummyComp", "1.3."+wildCard, *conn, cvQueryURL) + err := vers.constructVersionable("DummyComp", "1.3."+wildCardNext, *conn, cvQueryURL) assert.NoError(t, err) err = vers.resolveNext(statusFilterCV) assert.NoError(t, err) @@ -109,9 +109,10 @@ func TestCvResolve(t *testing.T) { assert.Equal(t, "0001", vers.TechPatchLevel) assert.Equal(t, "1.3.1", vers.Version) }) + t.Run("Product Version NEXT Release Existing", func(t *testing.T) { mc.AddData(testDataAakaasPVGetReleaseExisting) - err := vers.constructVersionable("DummyProd", wildCard+".0.0", *conn, pvQueryURL) + err := vers.constructVersionable("DummyProd", wildCardNext+".0.0", *conn, pvQueryURL) assert.NoError(t, err) err = vers.resolveNext(statusFilterPV) assert.NoError(t, err) @@ -120,9 +121,10 @@ func TestCvResolve(t *testing.T) { assert.Equal(t, "0000", vers.TechPatchLevel) assert.Equal(t, "2.0.0", vers.Version) }) + t.Run("Product Version NEXT Release Non Existing", func(t *testing.T) { mc.AddData(testDataAakaasPVGetReleaseNonExisting) - err := vers.constructVersionable("DummyProd", wildCard+".0.0", *conn, pvQueryURL) + err := vers.constructVersionable("DummyProd", wildCardNext+".0.0", *conn, pvQueryURL) assert.NoError(t, err) err = vers.resolveNext(statusFilterPV) assert.NoError(t, err) @@ -131,4 +133,92 @@ func TestCvResolve(t *testing.T) { assert.Equal(t, "0000", vers.TechPatchLevel) assert.Equal(t, "1.0.0", vers.Version) }) + + t.Run("Component Version MAX Release existing", func(t *testing.T) { + mc.AddData(testDataAakaasCVGetReleaseExisting) + err := vers.constructVersionable("DummyComp", wildCardMax+".0.0", *conn, cvQueryURL) + assert.NoError(t, err) + err = vers.resolveMax(statusFilterCV) + assert.NoError(t, err) + assert.Equal(t, "1", vers.TechRelease) + assert.Equal(t, "0000", vers.TechSpLevel) + assert.Equal(t, "0000", vers.TechPatchLevel) + }) + + t.Run("Component Version MAX Release non existing", func(t *testing.T) { + mc.AddData(testDataAakaasCVGetReleaseNonExisting) + err := vers.constructVersionable("DummyComp", wildCardMax+".0.0", *conn, cvQueryURL) + assert.NoError(t, err) + err = vers.resolveMax(statusFilterCV) + assert.NoError(t, err) + assert.Equal(t, "0", vers.TechRelease) + assert.Equal(t, "0000", vers.TechSpLevel) + assert.Equal(t, "0000", vers.TechPatchLevel) + }) + + t.Run("Component Version MAX SP Level existing", func(t *testing.T) { + mc.AddData(testDataAakaasCVGetSpLevelExisting) + err := vers.constructVersionable("DummyComp", "1."+wildCardMax+".0", *conn, cvQueryURL) + assert.NoError(t, err) + err = vers.resolveMax(statusFilterCV) + assert.NoError(t, err) + assert.Equal(t, "1", vers.TechRelease) + assert.Equal(t, "0007", vers.TechSpLevel) + assert.Equal(t, "0000", vers.TechPatchLevel) + }) + + t.Run("Component Version MAX SP Level non existing", func(t *testing.T) { + mc.AddData(testDataAakaasCVGetSpLevelNonExisting) + err := vers.constructVersionable("DummyComp", "1."+wildCardMax+".0", *conn, cvQueryURL) + assert.NoError(t, err) + err = vers.resolveMax(statusFilterCV) + assert.NoError(t, err) + assert.Equal(t, "1", vers.TechRelease) + assert.Equal(t, "0000", vers.TechSpLevel) + assert.Equal(t, "0000", vers.TechPatchLevel) + }) + + t.Run("Component Version MAX Patch Level existing", func(t *testing.T) { + mc.AddData(testDataAakaasCVGetPatchLevelExisting) + err := vers.constructVersionable("DummyComp", "1.3."+wildCardMax, *conn, cvQueryURL) + assert.NoError(t, err) + err = vers.resolveMax(statusFilterCV) + assert.NoError(t, err) + assert.Equal(t, "1", vers.TechRelease) + assert.Equal(t, "0003", vers.TechSpLevel) + assert.Equal(t, "0046", vers.TechPatchLevel) + }) + + t.Run("Component Version MAX Patch Level non existing", func(t *testing.T) { + mc.AddData(testDataAakaasCVGetPatchLevelNonExisting) + err := vers.constructVersionable("DummyComp", "1.3."+wildCardMax, *conn, cvQueryURL) + assert.NoError(t, err) + err = vers.resolveMax(statusFilterCV) + assert.NoError(t, err) + assert.Equal(t, "1", vers.TechRelease) + assert.Equal(t, "0003", vers.TechSpLevel) + assert.Equal(t, "0000", vers.TechPatchLevel) + }) + + t.Run("Product Version MAX Release existing", func(t *testing.T) { + mc.AddData(testDataAakaasPVGetReleaseExisting) + err := vers.constructVersionable("DummyProd", wildCardMax+".0.0", *conn, pvQueryURL) + assert.NoError(t, err) + err = vers.resolveMax(statusFilterPV) + assert.NoError(t, err) + assert.Equal(t, "1", vers.TechRelease) + assert.Equal(t, "0000", vers.TechSpLevel) + assert.Equal(t, "0000", vers.TechPatchLevel) + }) + + t.Run("Product Version MAX Release non existing", func(t *testing.T) { + mc.AddData(testDataAakaasPVGetReleaseNonExisting) + err := vers.constructVersionable("DummyProd", wildCardMax+".0.0", *conn, pvQueryURL) + assert.NoError(t, err) + err = vers.resolveMax(statusFilterPV) + assert.NoError(t, err) + assert.Equal(t, "0", vers.TechRelease) + assert.Equal(t, "0000", vers.TechSpLevel) + assert.Equal(t, "0000", vers.TechPatchLevel) + }) } diff --git a/pkg/abaputils/abaputils.go b/pkg/abaputils/abaputils.go index 2f43a003c6..fe805037a7 100644 --- a/pkg/abaputils/abaputils.go +++ b/pkg/abaputils/abaputils.go @@ -178,7 +178,7 @@ func GetHTTPResponse(requestType string, connectionDetails ConnectionDetailsHTTP return httpResponse, err } -// HandleHTTPError handles ABAP error messages which can occur when using OData services +// HandleHTTPError handles ABAP error messages which can occur when using OData V2 services // // The point of this function is to enrich the error received from a HTTP Request (which is passed as a parameter to this function). // Further error details may be present in the response body of the HTTP response. @@ -218,10 +218,11 @@ func HandleHTTPError(resp *http.Response, err error, message string, connectionD return errorCode, err } +// GetErrorDetailsFromResponse parses OData V2 Responses containing ABAP Error messages func GetErrorDetailsFromResponse(resp *http.Response) (errorString string, errorCode string, err error) { // Include the error message of the ABAP Environment system, if available - var abapErrorResponse AbapError + var abapErrorResponse AbapErrorODataV2 bodyText, readError := io.ReadAll(resp.Body) if readError != nil { return "", "", readError @@ -233,7 +234,7 @@ func GetErrorDetailsFromResponse(resp *http.Response) (errorString string, error } if _, ok := abapResp["error"]; ok { json.Unmarshal(*abapResp["error"], &abapErrorResponse) - if (AbapError{}) != abapErrorResponse { + if (AbapErrorODataV2{}) != abapErrorResponse { log.Entry().WithField("ErrorCode", abapErrorResponse.Code).Debug(abapErrorResponse.Message.Value) return abapErrorResponse.Message.Value, abapErrorResponse.Code, nil } @@ -311,12 +312,18 @@ type ConnectionDetailsHTTP struct { CertificateNames []string `json:"-"` } -// AbapError contains the error code and the error message for ABAP errors -type AbapError struct { +// AbapErrorODataV2 contains the error code and the error message for ABAP errors +type AbapErrorODataV2 struct { Code string `json:"code"` Message AbapErrorMessage `json:"message"` } +// AbapErrorODataV4 contains the error code and the error message for ABAP errors +type AbapErrorODataV4 struct { + Code string `json:"code"` + Message string `json:"message"` +} + // AbapErrorMessage contains the lanuage and value fields for ABAP errors type AbapErrorMessage struct { Lang string `json:"lang"` diff --git a/pkg/abaputils/sap_com_0948.go b/pkg/abaputils/sap_com_0948.go index ef25db3bb6..b006b6cead 100644 --- a/pkg/abaputils/sap_com_0948.go +++ b/pkg/abaputils/sap_com_0948.go @@ -7,6 +7,7 @@ import ( "net/http" "net/http/cookiejar" "reflect" + "regexp" "strings" "time" @@ -67,7 +68,7 @@ func (api *SAP_COM_0948) GetExecutionLog() (execLog ExecutionLog, err error) { resp, err := GetHTTPResponse("GET", connectionDetails, nil, api.client) if err != nil { log.SetErrorCategory(log.ErrorInfrastructure) - _, err = HandleHTTPError(resp, err, api.failureMessage, connectionDetails) + _, err = handleHTTPError(resp, err, api.failureMessage, connectionDetails) return execLog, err } defer resp.Body.Close() @@ -161,7 +162,7 @@ func (api *SAP_COM_0948) GetLogProtocol(logOverviewEntry LogResultsV2, page int) resp, err := GetHTTPResponse("GET", connectionDetails, nil, api.client) if err != nil { log.SetErrorCategory(log.ErrorInfrastructure) - _, err = HandleHTTPError(resp, err, api.failureMessage, connectionDetails) + _, err = handleHTTPError(resp, err, api.failureMessage, connectionDetails) return nil, 0, err } defer resp.Body.Close() @@ -185,7 +186,7 @@ func (api *SAP_COM_0948) GetLogOverview() (result []LogResultsV2, err error) { resp, err := GetHTTPResponse("GET", connectionDetails, nil, api.client) if err != nil { log.SetErrorCategory(log.ErrorInfrastructure) - _, err = HandleHTTPError(resp, err, api.failureMessage, connectionDetails) + _, err = handleHTTPError(resp, err, api.failureMessage, connectionDetails) return nil, err } defer resp.Body.Close() @@ -220,7 +221,7 @@ func (api *SAP_COM_0948) GetAction() (string, error) { resp, err := GetHTTPResponse("GET", connectionDetails, nil, api.client) if err != nil { log.SetErrorCategory(log.ErrorInfrastructure) - _, err = HandleHTTPError(resp, err, api.failureMessage, connectionDetails) + _, err = handleHTTPError(resp, err, api.failureMessage, connectionDetails) return "E", err } defer resp.Body.Close() @@ -248,7 +249,7 @@ func (api *SAP_COM_0948) GetRepository() (bool, string, error, bool) { swcConnectionDetails.URL = api.con.URL + api.path + api.softwareComponentEntity + api.getRepoNameForPath() resp, err := GetHTTPResponse("GET", swcConnectionDetails, nil, api.client) if err != nil { - _, errRepo := HandleHTTPError(resp, err, "Reading the Repository / Software Component failed", api.con) + _, errRepo := handleHTTPError(resp, err, "Reading the Repository / Software Component failed", api.con) return false, "", errRepo, false } defer resp.Body.Close() @@ -323,7 +324,7 @@ func (api *SAP_COM_0948) triggerRequest(cloneConnectionDetails ConnectionDetails } resp, err = GetHTTPResponse("POST", cloneConnectionDetails, jsonBody, api.client) if err != nil { - errorCode, err = HandleHTTPError(resp, err, "Triggering the action failed", api.con) + errorCode, err = handleHTTPError(resp, err, "Triggering the action failed", api.con) if slices.Contains(api.retryAllowedErrorCodes, errorCode) { // Error Code allows for retry continue @@ -366,7 +367,7 @@ func (api *SAP_COM_0948) initialRequest() error { // Loging into the ABAP System - getting the x-csrf-token and cookies resp, err := GetHTTPResponse("GET", headConnection, nil, api.client) if err != nil { - _, err = HandleHTTPError(resp, err, "Authentication on the ABAP system failed", api.con) + _, err = handleHTTPError(resp, err, "Authentication on the ABAP system failed", api.con) return err } defer resp.Body.Close() @@ -431,3 +432,62 @@ func (api *SAP_COM_0948) ConvertTime(logTimeStamp string) time.Time { } return t } + +func handleHTTPError(resp *http.Response, err error, message string, connectionDetails ConnectionDetailsHTTP) (string, error) { + + var errorText string + var errorCode string + var parsingError error + if resp == nil { + // Response is nil in case of a timeout + log.Entry().WithError(err).WithField("ABAP Endpoint", connectionDetails.URL).Error("Request failed") + + match, _ := regexp.MatchString(".*EOF$", err.Error()) + if match { + AddDefaultDashedLine(1) + log.Entry().Infof("%s", "A connection could not be established to the ABAP system. The typical root cause is the network configuration (firewall, IP allowlist, etc.)") + AddDefaultDashedLine(1) + } + + log.Entry().Infof("Error message: %s,", err.Error()) + } else { + + defer resp.Body.Close() + + log.Entry().WithField("StatusCode", resp.Status).WithField("User", connectionDetails.User).WithField("URL", connectionDetails.URL).Error(message) + + errorText, errorCode, parsingError = getErrorDetailsFromResponse(resp) + if parsingError != nil { + return "", err + } + abapError := errors.New(fmt.Sprintf("%s - %s", errorCode, errorText)) + err = errors.Wrap(abapError, err.Error()) + + } + return errorCode, err +} + +func getErrorDetailsFromResponse(resp *http.Response) (errorString string, errorCode string, err error) { + + // Include the error message of the ABAP Environment system, if available + var abapErrorResponse AbapErrorODataV4 + bodyText, readError := io.ReadAll(resp.Body) + if readError != nil { + return "", "", readError + } + var abapResp map[string]*json.RawMessage + errUnmarshal := json.Unmarshal(bodyText, &abapResp) + if errUnmarshal != nil { + return "", "", errUnmarshal + } + if _, ok := abapResp["error"]; ok { + json.Unmarshal(*abapResp["error"], &abapErrorResponse) + if (AbapErrorODataV4{}) != abapErrorResponse { + log.Entry().WithField("ErrorCode", abapErrorResponse.Code).Debug(abapErrorResponse.Message) + return abapErrorResponse.Message, abapErrorResponse.Code, nil + } + } + + return "", "", errors.New("Could not parse the JSON error response") + +} diff --git a/pkg/abaputils/sap_com_0948_test.go b/pkg/abaputils/sap_com_0948_test.go index 629f23c040..c0f33bdf3c 100644 --- a/pkg/abaputils/sap_com_0948_test.go +++ b/pkg/abaputils/sap_com_0948_test.go @@ -50,7 +50,7 @@ func TestRetry0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) api.setSleepTimeConfig(time.Nanosecond, 120*time.Nanosecond) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -66,7 +66,7 @@ func TestRetry0948(t *testing.T) { client := &ClientMock{ BodyList: []string{ `{ "status" : "R", "UUID" : "GUID" }`, - `{"error" : { "code" : "A4C_A2G/224", "message" : { "lang" : "de", "value" : "Error Text"} } }`, + `{"error" : { "code" : "A4C_A2G/224", "message" : "Error Text" } }`, `{ }`, }, Token: "myToken", @@ -80,8 +80,8 @@ func TestRetry0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) - api.setSleepTimeConfig(time.Nanosecond, 120*time.Nanosecond) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) + api.setSleepTimeConfig(time.Nanosecond, 20*time.Nanosecond) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -95,15 +95,15 @@ func TestRetry0948(t *testing.T) { client := &ClientMock{ BodyList: []string{ - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, `{ }`, }, Token: "myToken", @@ -124,12 +124,12 @@ func TestRetry0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) api.setSleepTimeConfig(time.Nanosecond, 20*time.Nanosecond) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") - api.(*SAP_COM_0948).maxRetries = 20 + api.(*SAP_COM_0948).maxRetries = 5 errAction := api.(*SAP_COM_0948).triggerRequest(ConnectionDetailsHTTP{User: "CC_USER", Password: "abc123", URL: "https://example.com/path"}, []byte("{}")) assert.ErrorContains(t, errAction, "HTTP 400: A4C_A2G/228 - Error Text") @@ -142,15 +142,15 @@ func TestRetry0948(t *testing.T) { client := &ClientMock{ BodyList: []string{ - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, - `{"error" : { "code" : "A4C_A2G/228", "message" : { "lang" : "de", "value" : "Error Text"} } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, + `{"error" : { "code" : "A4C_A2G/228", "message" : "Error Text" } }`, `{ }`, }, Token: "myToken", @@ -171,7 +171,7 @@ func TestRetry0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) api.setSleepTimeConfig(time.Nanosecond, 999*time.Nanosecond) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -200,7 +200,7 @@ func TestClone0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -223,7 +223,7 @@ func TestClone0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) api.setSleepTimeConfig(time.Nanosecond, 120*time.Nanosecond) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -252,7 +252,7 @@ func TestClone0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) api.setSleepTimeConfig(time.Nanosecond, 120*time.Nanosecond) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -317,7 +317,7 @@ func TestPull0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -339,7 +339,7 @@ func TestPull0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -363,7 +363,7 @@ func TestCheckout0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -385,7 +385,7 @@ func TestCheckout0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -409,7 +409,7 @@ func TestGetRepo0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -434,7 +434,7 @@ func TestCreateTag0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -456,7 +456,7 @@ func TestCreateTag0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -478,7 +478,7 @@ func TestCreateTag0948(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, err := apiManager.GetAPI(con, repo) + api, err := apiManager.GetAPI(conTest0948, repoTest0948) assert.NoError(t, err) assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type") @@ -565,7 +565,7 @@ func TestGetExecutionLog(t *testing.T) { apiManager := &SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Microsecond} - api, _ := apiManager.GetAPI(con, Repository{Name: "/DMO/REPO"}) + api, _ := apiManager.GetAPI(conTest0948, Repository{Name: "/DMO/REPO"}) results, errAction := api.GetExecutionLog() assert.NoError(t, errAction) diff --git a/pkg/blackduck/blackduck.go b/pkg/blackduck/blackduck.go index 029a29362b..8db4c94d41 100644 --- a/pkg/blackduck/blackduck.go +++ b/pkg/blackduck/blackduck.go @@ -18,6 +18,7 @@ import ( // ReportsDirectory defines the subfolder for the Blackduck reports which are generated const ReportsDirectory = "blackduck" +const maxLimit = 50 const ( HEADER_PROJECT_DETAILS_V4 = "application/vnd.blackducksoftware.project-detail-4+json" @@ -246,6 +247,39 @@ func NewClient(token, serverURL string, httpClient piperhttp.Sender) Client { // GetProject returns a project with a given name func (b *Client) GetProject(projectName string) (*Project, error) { + projects, err := b.getProjectByPagination(projectName, 0) + if err != nil { + return nil, err + } + // even if more than one projects found, let's return the first one with exact project name match + for _, project := range projects.Items { + if project.Name == projectName { + return &project, nil + } + } + + if projects.TotalCount > maxLimit { + offset := maxLimit + totalProjects := projects.TotalCount + for offset < totalProjects { + projects, err = b.getProjectByPagination(projectName, offset) + if err != nil { + return nil, err + } + // even if more than one projects found, let's return the first one with exact project name match + for _, project := range projects.Items { + if project.Name == projectName { + return &project, nil + } + } + offset += maxLimit + } + } + + return nil, fmt.Errorf("project '%v' not found", projectName) +} + +func (b *Client) getProjectByPagination(projectName string, offset int) (*Projects, error) { if !b.authenticationValid(time.Now()) { if err := b.authenticate(); err != nil { return nil, err @@ -253,11 +287,16 @@ func (b *Client) GetProject(projectName string) (*Project, error) { } headers := http.Header{} headers.Add("Accept", HEADER_PROJECT_DETAILS_V4) - respBody, err := b.sendRequest("GET", "/api/projects", map[string]string{"q": fmt.Sprintf("name:%v", projectName)}, nil, headers) + queryParams := map[string]string{ + "q": fmt.Sprintf("name:%v", projectName), + "limit": fmt.Sprint(maxLimit), + "offset": fmt.Sprint(offset), + "sort": "asc", + } + respBody, err := b.sendRequest("GET", "/api/projects", queryParams, nil, headers) if err != nil { return nil, errors.Wrapf(err, "failed to get project '%v'", projectName) } - projects := Projects{} err = json.Unmarshal(respBody, &projects) if err != nil { @@ -265,15 +304,7 @@ func (b *Client) GetProject(projectName string) (*Project, error) { } else if projects.TotalCount == 0 { return nil, fmt.Errorf("project '%v' not found", projectName) } - - // even if more than one projects found, let's return the first one with exact project name match - for _, project := range projects.Items { - if project.Name == projectName { - return &project, nil - } - } - - return nil, fmt.Errorf("project '%v' not found", projectName) + return &projects, nil } // GetProjectVersion returns a project version with a given name diff --git a/pkg/blackduck/blackduck_test.go b/pkg/blackduck/blackduck_test.go index 15b1190a13..8211b9e37c 100644 --- a/pkg/blackduck/blackduck_test.go +++ b/pkg/blackduck/blackduck_test.go @@ -95,8 +95,8 @@ func TestGetProject(t *testing.T) { t.Run("success", func(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ - "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/tokens/authenticate": authContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, }, header: map[string]http.Header{}, } @@ -106,7 +106,7 @@ func TestGetProject(t *testing.T) { assert.Equal(t, "SHC-PiperTest", project.Name) assert.Equal(t, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions", project.Metadata.Links[0].Href) headerExpected := http.Header{"Authorization": []string{"Bearer bearerTestToken"}, "Accept": {"application/vnd.blackducksoftware.project-detail-4+json"}} - assert.Equal(t, headerExpected, myTestClient.header["https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest"]) + assert.Equal(t, headerExpected, myTestClient.header["https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc"]) }) t.Run("failure - not found", func(t *testing.T) { @@ -115,7 +115,7 @@ func TestGetProject(t *testing.T) { "https://my.blackduck.system/api/tokens/authenticate": authContent, }, errorMessageForURL: map[string]string{ - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": "not found", + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": "not found", }, header: map[string]http.Header{}, } @@ -128,7 +128,7 @@ func TestGetProject(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": `{ + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": `{ "totalCount": 0, "items": [] }`, @@ -143,8 +143,8 @@ func TestGetProject(t *testing.T) { t.Run("failure - unmarshalling", func(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ - "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": "", + "https://my.blackduck.system/api/tokens/authenticate": authContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": "", }, header: map[string]http.Header{}, } @@ -159,7 +159,7 @@ func TestGetProjectVersion(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, }, header: map[string]http.Header{}, @@ -179,7 +179,7 @@ func TestGetProjectVersion(t *testing.T) { "https://my.blackduck.system/api/tokens/authenticate": authContent, }, errorMessageForURL: map[string]string{ - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": "not found", + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": "not found", }, header: map[string]http.Header{}, } @@ -191,8 +191,8 @@ func TestGetProjectVersion(t *testing.T) { t.Run("failure - version not found", func(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ - "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/tokens/authenticate": authContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, }, errorMessageForURL: map[string]string{ "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": "not found", @@ -207,8 +207,8 @@ func TestGetProjectVersion(t *testing.T) { t.Run("failure - 0 results", func(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ - "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/tokens/authenticate": authContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": `{ "totalCount": 0, "items": [] @@ -225,7 +225,7 @@ func TestGetProjectVersion(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": "", }, header: map[string]http.Header{}, @@ -241,7 +241,7 @@ func TestGetVulnerabilities(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/vunlerable-bom-components?limit=999&offset=0": `{ "totalCount": 1, @@ -273,7 +273,7 @@ func TestGetVulnerabilities(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/vunlerable-bom-components?limit=999&offset=0": `{"totalCount":0,"items":[]}`, }, @@ -289,7 +289,7 @@ func TestGetVulnerabilities(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/vunlerable-bom-components?limit=999&offset=0": "", }, @@ -306,7 +306,7 @@ func TestGetComponents(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components?limit=999&offset=0": `{ "totalCount": 2, @@ -333,7 +333,7 @@ func TestGetComponents(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components?limit=999&offset=0": `{ "totalCount": 0, @@ -351,7 +351,7 @@ func TestGetComponents(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components?limit=999&offset=0": "", }, @@ -369,7 +369,7 @@ func TestGetComponentsWithLicensePolicyRule(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components?filter=policyCategory%3Alicense&limit=999&offset=0": `{ "totalCount": 2, @@ -399,7 +399,7 @@ func TestGetComponentsWithLicensePolicyRule(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components?filter=policyCategory%3Alicense&limit=999&offset=0": `{ "totalCount": 0, @@ -417,9 +417,9 @@ func TestGetComponentsWithLicensePolicyRule(t *testing.T) { t.Run("Failure - unmarshalling", func(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ - "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, - "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, + "https://my.blackduck.system/api/tokens/authenticate": authContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, + "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components?filter=policyCategory%3Alicense&limit=999&offset=0": "", }, header: map[string]http.Header{}, @@ -436,7 +436,7 @@ func TestGetPolicyStatus(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/policy-status": `{ "overallStatus": "IN_VIOLATION", @@ -468,7 +468,7 @@ func TestGetPolicyStatus(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/policy-status": "", }, @@ -486,7 +486,7 @@ func TestGetProjectVersionLink(t *testing.T) { myTestClient := httpMockClient{ responseBodyForURL: map[string]string{ "https://my.blackduck.system/api/tokens/authenticate": authContent, - "https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent, + "https://my.blackduck.system/api/projects?limit=50&offset=0&q=name%3ASHC-PiperTest&sort=asc": projectContent, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent, }, header: map[string]http.Header{}, diff --git a/pkg/build/artifact.go b/pkg/build/artifact.go new file mode 100644 index 0000000000..392402ff47 --- /dev/null +++ b/pkg/build/artifact.go @@ -0,0 +1,7 @@ +package build + +import "github.com/SAP/jenkins-library/pkg/versioning" + +type BuildArtifacts struct { + Coordinates []versioning.Coordinates +} diff --git a/pkg/cnbutils/auth.go b/pkg/cnbutils/auth.go index 98a5b58b3b..3de6378d51 100644 --- a/pkg/cnbutils/auth.go +++ b/pkg/cnbutils/auth.go @@ -7,50 +7,76 @@ import ( "github.com/SAP/jenkins-library/pkg/log" "github.com/docker/cli/cli/config/configfile" + "github.com/docker/cli/cli/config/types" + "github.com/docker/docker/registry" ) -func GenerateCnbAuth(config string, utils BuildUtils) (string, error) { - var err error - dockerConfig := &configfile.ConfigFile{} +type DockerKeychain struct { + dockerConfig *configfile.ConfigFile +} - if config != "" { - log.Entry().Debugf("using docker config file %q", config) - dockerConfigJSON, err := utils.FileRead(config) - if err != nil { - return "", err - } +func (dk *DockerKeychain) ToCNBString() (string, error) { + if dk.dockerConfig == nil || len(dk.dockerConfig.GetAuthConfigs()) == 0 { + return "{}", nil + } - err = json.Unmarshal(dockerConfigJSON, dockerConfig) - if err != nil { - return "", err + cnbAuth := map[string]string{} + for reg, authConf := range dk.dockerConfig.GetAuthConfigs() { + registryHostname := registry.ConvertToHostname(reg) + log.Entry().Debugf("adding credentials for registry %q", registryHostname) + if authConf.RegistryToken != "" { + cnbAuth[registryHostname] = fmt.Sprintf("Bearer %s", authConf.RegistryToken) + + continue } - } - auth := map[string]string{} - for registry, value := range dockerConfig.AuthConfigs { - if value.Auth == "" && value.Username == "" && value.Password == "" { - log.Entry().Warnf("docker config.json contains empty credentials for registry %q. Either 'auth' or 'username' and 'password' have to be provided.", registry) + if authConf.Auth != "" { + cnbAuth[registryHostname] = fmt.Sprintf("Basic %s", authConf.Auth) + continue } - if value.Auth == "" { - value.Auth = encodeAuth(value.Username, value.Password) + if authConf.Username == "" && authConf.Password == "" { + log.Entry().Warnf("docker config.json contains empty credentials for registry %q. Either 'auth' or 'username' and 'password' have to be provided.", registryHostname) + + continue } - log.Entry().Debugf("Adding credentials for: registry %q", registry) - auth[registry] = fmt.Sprintf("Basic %s", value.Auth) + cnbAuth[registryHostname] = fmt.Sprintf("Basic %s", encodeAuth(authConf.Username, authConf.Password)) } - if len(auth) == 0 { - log.Entry().Warn("docker config file is empty!") - } + cnbAuthBytes, err := json.Marshal(&cnbAuth) + return string(cnbAuthBytes), err +} - cnbRegistryAuth, err := json.Marshal(auth) +func (dk *DockerKeychain) AuthExistsForImage(image string) bool { + var empty types.AuthConfig + conf, err := dk.dockerConfig.GetAuthConfig(registry.ConvertToHostname(image)) if err != nil { - return "", err + log.Entry().Errorf("failed to get auth config for the image %q, error: %s", image, err.Error()) + } + + return conf != empty +} + +func ParseDockerConfig(config string, utils BuildUtils) (*DockerKeychain, error) { + keychain := &DockerKeychain{ + dockerConfig: &configfile.ConfigFile{}, + } + if config != "" { + log.Entry().Debugf("using docker config file %q", config) + dockerConfigJSON, err := utils.FileRead(config) + if err != nil { + return nil, err + } + + err = json.Unmarshal(dockerConfigJSON, keychain.dockerConfig) + if err != nil { + return nil, err + } } - return string(cnbRegistryAuth), nil + return keychain, nil } func encodeAuth(username, password string) string { diff --git a/pkg/cnbutils/auth_test.go b/pkg/cnbutils/auth_test.go index 24ed900d03..d719664d0a 100644 --- a/pkg/cnbutils/auth_test.go +++ b/pkg/cnbutils/auth_test.go @@ -18,41 +18,61 @@ func TestGenerateCnbAuth(t *testing.T) { } t.Run("successfully generates cnb auth env variable", func(t *testing.T) { - mockUtils.AddFile("/test/valid_config.json", []byte("{\"auths\":{\"example.com\":{\"auth\":\"dXNlcm5hbWU6cGFzc3dvcmQ=\"}}}")) - auth, err := cnbutils.GenerateCnbAuth("/test/valid_config.json", mockUtils) + mockUtils.AddFile("/test/valid_config.json", []byte("{\"auths\":{\"https://example.com/\":{\"auth\":\"dXNlcm5hbWU6cGFzc3dvcmQ=\"}}}")) + auth, err := cnbutils.ParseDockerConfig("/test/valid_config.json", mockUtils) assert.NoError(t, err) - assert.Equal(t, "{\"example.com\":\"Basic dXNlcm5hbWU6cGFzc3dvcmQ=\"}", auth) + + authString, err := auth.ToCNBString() + assert.NoError(t, err) + assert.Equal(t, "{\"example.com\":\"Basic dXNlcm5hbWU6cGFzc3dvcmQ=\"}", authString) + assert.True(t, auth.AuthExistsForImage("example.com/foo/bar:123")) + assert.False(t, auth.AuthExistsForImage("docker.io/foo/bar")) }) t.Run("successfully generates cnb auth env variable from username and password", func(t *testing.T) { mockUtils.AddFile("/test/valid_config.json", []byte("{\"auths\":{\"example.com\":{\"username\":\"username\",\"password\":\"password\"}}}")) - auth, err := cnbutils.GenerateCnbAuth("/test/valid_config.json", mockUtils) + auth, err := cnbutils.ParseDockerConfig("/test/valid_config.json", mockUtils) + assert.NoError(t, err) + + authString, err := auth.ToCNBString() assert.NoError(t, err) - assert.Equal(t, "{\"example.com\":\"Basic dXNlcm5hbWU6cGFzc3dvcmQ=\"}", auth) + assert.Equal(t, "{\"example.com\":\"Basic dXNlcm5hbWU6cGFzc3dvcmQ=\"}", authString) + assert.True(t, auth.AuthExistsForImage("example.com/foo/bar:123")) + assert.False(t, auth.AuthExistsForImage("docker.io/foo/bar")) }) t.Run("skips registry with empty credentials", func(t *testing.T) { mockUtils.AddFile("/test/valid_config.json", []byte("{\"auths\":{\"example.com\":{}}}")) - auth, err := cnbutils.GenerateCnbAuth("/test/valid_config.json", mockUtils) + auth, err := cnbutils.ParseDockerConfig("/test/valid_config.json", mockUtils) assert.NoError(t, err) - assert.Equal(t, "{}", auth) + + authString, err := auth.ToCNBString() + assert.NoError(t, err) + assert.Equal(t, "{}", authString) + assert.False(t, auth.AuthExistsForImage("example.com/foo/bar:123")) + assert.False(t, auth.AuthExistsForImage("docker.io/foo/bar")) }) t.Run("successfully generates cnb auth env variable if docker config is not present", func(t *testing.T) { - auth, err := cnbutils.GenerateCnbAuth("", mockUtils) + auth, err := cnbutils.ParseDockerConfig("", mockUtils) + assert.NoError(t, err) + + authString, err := auth.ToCNBString() assert.NoError(t, err) - assert.Equal(t, "{}", auth) + assert.Equal(t, "{}", authString) + assert.False(t, auth.AuthExistsForImage("example.com/foo/bar:123")) + assert.False(t, auth.AuthExistsForImage("docker.io/foo/bar")) }) t.Run("fails if file not found", func(t *testing.T) { - _, err := cnbutils.GenerateCnbAuth("/not/found", mockUtils) + _, err := cnbutils.ParseDockerConfig("/not/found", mockUtils) assert.Error(t, err) assert.Equal(t, "could not read '/not/found'", err.Error()) }) t.Run("fails if file is invalid json", func(t *testing.T) { mockUtils.AddFile("/test/invalid_config.json", []byte("not a json")) - _, err := cnbutils.GenerateCnbAuth("/test/invalid_config.json", mockUtils) + _, err := cnbutils.ParseDockerConfig("/test/invalid_config.json", mockUtils) assert.Error(t, err) assert.Equal(t, "invalid character 'o' in literal null (expecting 'u')", err.Error()) }) diff --git a/pkg/cnbutils/copy_project.go b/pkg/cnbutils/copy_project.go index 1d20892afd..d7f423820f 100644 --- a/pkg/cnbutils/copy_project.go +++ b/pkg/cnbutils/copy_project.go @@ -1,6 +1,7 @@ package cnbutils import ( + "io/fs" "os" "path" "path/filepath" @@ -11,23 +12,82 @@ import ( ignore "github.com/sabhiram/go-gitignore" ) -func CopyProject(source, target string, include, exclude *ignore.GitIgnore, utils BuildUtils) error { - sourceFiles, _ := utils.Glob(path.Join(source, "**")) +func shouldBeFiltered(path string, knownSymlinks []string) bool { + for _, symlink := range knownSymlinks { + if strings.HasPrefix(path, symlink) { + return true + } + } + return false +} + +func filterSymlinks(sourceFiles []string, utils BuildUtils) ([]string, error) { + filteredFiles := []string{} + knownSymlinks := []string{} + + for _, sourceFile := range sourceFiles { + if shouldBeFiltered(sourceFile, knownSymlinks) { + continue + } + + isSymlink, err := symlinkExists(sourceFile, utils) + if err != nil { + return nil, err + } + + if isSymlink { + log.Entry().Debugf("Ignoring any path below %q", sourceFile) + knownSymlinks = append(knownSymlinks, sourceFile) + } + filteredFiles = append(filteredFiles, sourceFile) + } + return filteredFiles, nil +} + +func CopyProject(source, target string, include, exclude *ignore.GitIgnore, utils BuildUtils, follow bool) error { + sourceFiles, err := utils.Glob(path.Join(source, "**")) + if err != nil { + return err + } + + if !follow { + sourceFiles, err = filterSymlinks(sourceFiles, utils) + if err != nil { + return err + } + } + for _, sourceFile := range sourceFiles { relPath, err := filepath.Rel(source, sourceFile) if err != nil { log.SetErrorCategory(log.ErrorBuild) return errors.Wrapf(err, "Calculating relative path for '%s' failed", sourceFile) } + if !isIgnored(relPath, include, exclude) { target := path.Join(target, strings.ReplaceAll(sourceFile, source, "")) - dir, err := utils.DirExists(sourceFile) + + isSymlink, err := symlinkExists(sourceFile, utils) if err != nil { - log.SetErrorCategory(log.ErrorBuild) - return errors.Wrapf(err, "Checking file info '%s' failed", target) + return err } - if dir { + isDir, err := utils.DirExists(sourceFile) + if err != nil { + return err + } + + if isSymlink { + linkTarget, err := utils.Readlink(sourceFile) + if err != nil { + return err + } + log.Entry().Debugf("Creating symlink from %q to %q", target, linkTarget) + err = utils.Symlink(linkTarget, target) + if err != nil { + return err + } + } else if isDir { err = utils.MkdirAll(target, os.ModePerm) if err != nil { log.SetErrorCategory(log.ErrorBuild) @@ -41,12 +101,16 @@ func CopyProject(source, target string, include, exclude *ignore.GitIgnore, util return errors.Wrapf(err, "Copying '%s' to '%s' failed", sourceFile, target) } } - } } return nil } +func symlinkExists(path string, utils BuildUtils) (bool, error) { + lstat, err := utils.Lstat(path) + return lstat.Mode().Type() == fs.ModeSymlink, err +} + func copyFile(source, target string, utils BuildUtils) error { targetDir := filepath.Dir(target) @@ -56,13 +120,14 @@ func copyFile(source, target string, utils BuildUtils) error { } if !exists { - log.Entry().Debugf("Creating directory %s", targetDir) + log.Entry().Debugf("Creating directory '%s'", targetDir) err = utils.MkdirAll(targetDir, os.ModePerm) if err != nil { return err } } + log.Entry().Debugf("Copying '%s' to '%s'", source, target) _, err = utils.Copy(source, target) return err } diff --git a/pkg/cnbutils/copy_project_test.go b/pkg/cnbutils/copy_project_test.go index abd706fa4a..fcdd4e818b 100644 --- a/pkg/cnbutils/copy_project_test.go +++ b/pkg/cnbutils/copy_project_test.go @@ -13,27 +13,43 @@ import ( ) func TestCopyProject(t *testing.T) { - t.Run("copies file according to doublestart globs", func(t *testing.T) { + t.Run("copy project with following symlinks", func(t *testing.T) { mockUtils := &cnbutils.MockUtils{ FilesMock: &mock.FilesMock{}, } mockUtils.AddFile("workdir/src/test.yaml", []byte("")) mockUtils.AddFile("workdir/src/subdir1/test2.yaml", []byte("")) mockUtils.AddFile("workdir/src/subdir1/subdir2/test3.yaml", []byte("")) - err := cnbutils.CopyProject("workdir/src", "/dest", ignore.CompileIgnoreLines([]string{"**/*.yaml"}...), nil, mockUtils) + + mockUtils.AddDir("workdir/apps") + mockUtils.AddFile("workdir/apps/foo.yaml", []byte("")) + mockUtils.Symlink("workdir/apps", "/workdir/src/apps") + + err := cnbutils.CopyProject("workdir/src", "/dest", ignore.CompileIgnoreLines([]string{"**"}...), nil, mockUtils, true) assert.NoError(t, err) assert.True(t, mockUtils.HasCopiedFile("workdir/src/test.yaml", "/dest/test.yaml")) assert.True(t, mockUtils.HasCopiedFile("workdir/src/subdir1/test2.yaml", "/dest/subdir1/test2.yaml")) assert.True(t, mockUtils.HasCopiedFile("workdir/src/subdir1/subdir2/test3.yaml", "/dest/subdir1/subdir2/test3.yaml")) + assert.True(t, mockUtils.HasCopiedFile("workdir/src/apps", "/dest/apps")) }) - t.Run("copies file according to simple globs", func(t *testing.T) { + t.Run("copy project without following symlinks", func(t *testing.T) { mockUtils := &cnbutils.MockUtils{ FilesMock: &mock.FilesMock{}, } - mockUtils.AddFile("src/test.yaml", []byte("")) - err := cnbutils.CopyProject("src", "/dest", ignore.CompileIgnoreLines([]string{"*.yaml"}...), nil, mockUtils) + mockUtils.AddFile("workdir/src/test.yaml", []byte("")) + mockUtils.AddFile("workdir/src/subdir1/test2.yaml", []byte("")) + mockUtils.AddFile("workdir/src/subdir1/subdir2/test3.yaml", []byte("")) + + mockUtils.AddDir("workdir/apps") + mockUtils.AddFile("workdir/apps/foo.yaml", []byte("")) + mockUtils.Symlink("workdir/apps", "/workdir/src/apps") + + err := cnbutils.CopyProject("workdir/src", "/dest", ignore.CompileIgnoreLines([]string{"**/*.yaml"}...), nil, mockUtils, false) assert.NoError(t, err) - assert.True(t, mockUtils.HasCopiedFile("src/test.yaml", "/dest/test.yaml")) + assert.True(t, mockUtils.HasCopiedFile("workdir/src/test.yaml", "/dest/test.yaml")) + assert.True(t, mockUtils.HasCopiedFile("workdir/src/subdir1/test2.yaml", "/dest/subdir1/test2.yaml")) + assert.True(t, mockUtils.HasCopiedFile("workdir/src/subdir1/subdir2/test3.yaml", "/dest/subdir1/subdir2/test3.yaml")) + assert.True(t, mockUtils.HasCreatedSymlink("workdir/apps", "/workdir/src/apps")) }) } diff --git a/pkg/config/config.go b/pkg/config/config.go index e41873f898..e35aa589e7 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -11,6 +11,8 @@ import ( "regexp" "strings" + "github.com/SAP/jenkins-library/pkg/trustengine" + piperhttp "github.com/SAP/jenkins-library/pkg/http" "github.com/SAP/jenkins-library/pkg/log" @@ -21,16 +23,17 @@ import ( // Config defines the structure of the config files type Config struct { - CustomDefaults []string `json:"customDefaults,omitempty"` - General map[string]interface{} `json:"general"` - Stages map[string]map[string]interface{} `json:"stages"` - Steps map[string]map[string]interface{} `json:"steps"` - Hooks map[string]interface{} `json:"hooks,omitempty"` - defaults PipelineDefaults - initialized bool - accessTokens map[string]string - openFile func(s string, t map[string]string) (io.ReadCloser, error) - vaultCredentials VaultCredentials + CustomDefaults []string `json:"customDefaults,omitempty"` + General map[string]interface{} `json:"general"` + Stages map[string]map[string]interface{} `json:"stages"` + Steps map[string]map[string]interface{} `json:"steps"` + Hooks map[string]interface{} `json:"hooks,omitempty"` + defaults PipelineDefaults + initialized bool + accessTokens map[string]string + openFile func(s string, t map[string]string) (io.ReadCloser, error) + vaultCredentials VaultCredentials + trustEngineConfiguration trustengine.Configuration } // StepConfig defines the structure for merged step configuration @@ -270,6 +273,15 @@ func (c *Config) GetStepConfig(flagValues map[string]interface{}, paramJSON stri } } + // hooks need to have been loaded from the defaults before the server URL is known + err = c.setTrustEngineConfiguration(stepConfig.HookConfig) + if err != nil { + log.Entry().WithError(err).Debug("Trust Engine lookup skipped due to missing or incorrect configuration") + } else { + trustengineClient := trustengine.PrepareClient(&piperhttp.Client{}, c.trustEngineConfiguration) + resolveAllTrustEngineReferences(&stepConfig, append(parameters, ReportingParameters.Parameters...), c.trustEngineConfiguration, trustengineClient) + } + // finally do the condition evaluation post processing for _, p := range parameters { if len(p.Conditions) > 0 { diff --git a/pkg/config/trustengine.go b/pkg/config/trustengine.go new file mode 100644 index 0000000000..144804c18c --- /dev/null +++ b/pkg/config/trustengine.go @@ -0,0 +1,67 @@ +package config + +import ( + "errors" + + piperhttp "github.com/SAP/jenkins-library/pkg/http" + "github.com/SAP/jenkins-library/pkg/log" + "github.com/SAP/jenkins-library/pkg/trustengine" +) + +// const RefTypeTrustengineSecretFile = "trustengineSecretFile" +const RefTypeTrustengineSecret = "trustengineSecret" + +// resolveAllTrustEngineReferences retrieves all the step's secrets from the Trust Engine +func resolveAllTrustEngineReferences(config *StepConfig, params []StepParameters, trustEngineConfiguration trustengine.Configuration, client *piperhttp.Client) { + for _, param := range params { + if ref := param.GetReference(RefTypeTrustengineSecret); ref != nil { + if config.Config[param.Name] == "" { + log.Entry().Infof("Getting '%s' from Trust Engine", param.Name) + token, err := trustengine.GetToken(ref.Default, client, trustEngineConfiguration) + if err != nil { + log.Entry().Info(" failed") + log.Entry().WithError(err).Debugf("Couldn't get '%s' token from Trust Engine", ref.Default) + continue + } + log.RegisterSecret(token) + config.Config[param.Name] = token + log.Entry().Info(" succeeded") + } else { + log.Entry().Debugf("Skipping retrieval of '%s' from Trust Engine: parameter already set", param.Name) + } + } + } +} + +// setTrustEngineConfiguration sets the server URL for the Trust Engine by taking it from the hooks +func (c *Config) setTrustEngineConfiguration(hookConfig map[string]interface{}) error { + trustEngineHook, ok := hookConfig["trustengine"].(map[string]interface{}) + if !ok { + return errors.New("no Trust Engine hook configuration found") + } + if serverURL, ok := trustEngineHook["serverURL"].(string); ok { + c.trustEngineConfiguration.ServerURL = serverURL + } else { + return errors.New("no Trust Engine server URL found") + } + if tokenEndPoint, ok := trustEngineHook["tokenEndPoint"].(string); ok { + c.trustEngineConfiguration.TokenEndPoint = tokenEndPoint + } else { + return errors.New("no Trust Engine service endpoint found") + } + if tokenQueryParamName, ok := trustEngineHook["tokenQueryParamName"].(string); ok { + c.trustEngineConfiguration.TokenQueryParamName = tokenQueryParamName + } else { + return errors.New("no Trust Engine query parameter name found") + } + + if len(c.trustEngineConfiguration.Token) == 0 { + log.Entry().Debug("no Trust Engine token found") + } + return nil +} + +// SetTrustEngineToken sets the token for the Trust Engine +func (c *Config) SetTrustEngineToken(token string) { + c.trustEngineConfiguration.Token = token +} diff --git a/pkg/config/trustengine_test.go b/pkg/config/trustengine_test.go new file mode 100644 index 0000000000..c475a9e8b2 --- /dev/null +++ b/pkg/config/trustengine_test.go @@ -0,0 +1,74 @@ +//go:build unit +// +build unit + +package config + +import ( + "fmt" + piperhttp "github.com/SAP/jenkins-library/pkg/http" + "github.com/SAP/jenkins-library/pkg/trustengine" + "github.com/jarcoal/httpmock" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +const secretName = "sonar" +const secretNameInTrustEngine = "sonarTrustengineSecretName" +const testServerURL = "https://www.project-piper.io" +const testTokenEndPoint = "tokens" +const testTokenQueryParamName = "systems" +const mockSonarToken = "mockSonarToken" + +var testFullURL = fmt.Sprintf("%s/%s?%s=", testServerURL, testTokenEndPoint, testTokenQueryParamName) +var mockSingleTokenResponse = fmt.Sprintf("{\"sonar\": \"%s\"}", mockSonarToken) + +func TestTrustEngineConfig(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + httpmock.RegisterResponder(http.MethodGet, testFullURL+"sonar", httpmock.NewStringResponder(200, mockSingleTokenResponse)) + + stepParams := []StepParameters{createStepParam(secretName, RefTypeTrustengineSecret, secretNameInTrustEngine, secretName)} + + var trustEngineConfiguration = trustengine.Configuration{ + Token: "testToken", + ServerURL: testServerURL, + TokenEndPoint: testTokenEndPoint, + TokenQueryParamName: testTokenQueryParamName, + } + client := &piperhttp.Client{} + client.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true}) + + t.Run("Load secret from Trust Engine - secret not set yet by Vault or config.yml", func(t *testing.T) { + stepConfig := &StepConfig{Config: map[string]interface{}{ + secretName: "", + }} + + resolveAllTrustEngineReferences(stepConfig, stepParams, trustEngineConfiguration, client) + assert.Equal(t, mockSonarToken, stepConfig.Config[secretName]) + }) + + t.Run("Load secret from Trust Engine - secret already by Vault or config.yml", func(t *testing.T) { + stepConfig := &StepConfig{Config: map[string]interface{}{ + secretName: "aMockTokenFromVault", + }} + + resolveAllTrustEngineReferences(stepConfig, stepParams, trustEngineConfiguration, client) + assert.NotEqual(t, mockSonarToken, stepConfig.Config[secretName]) + }) +} + +func createStepParam(name, refType, trustengineSecretNameProperty, defaultSecretNameName string) StepParameters { + return StepParameters{ + Name: name, + Aliases: []Alias{}, + ResourceRef: []ResourceReference{ + { + Type: refType, + Name: trustengineSecretNameProperty, + Default: defaultSecretNameName, + }, + }, + } +} diff --git a/pkg/documentation/generator/parameters.go b/pkg/documentation/generator/parameters.go index bb66c832b9..1c9e9f6848 100644 --- a/pkg/documentation/generator/parameters.go +++ b/pkg/documentation/generator/parameters.go @@ -9,6 +9,14 @@ import ( "github.com/SAP/jenkins-library/pkg/config" ) +const ( + vaultBadge = "![Vault](https://img.shields.io/badge/-Vault-lightgrey)" + jenkinsOnlyBadge = "![Jenkins only](https://img.shields.io/badge/-Jenkins%20only-yellowgreen)" + secretBadge = "![Secret](https://img.shields.io/badge/-Secret-yellowgreen)" + trustengineBadge = "![Trust Engine](https://img.shields.io/badge/-Trust%20Engine-lightblue)" + deprecatedBadge = "![deprecated](https://img.shields.io/badge/-deprecated-red)" +) + // Replaces the Parameters placeholder with the content from the yaml func createParametersSection(stepData *config.StepData) string { @@ -85,7 +93,7 @@ func parameterFurtherInfo(paramName string, stepData *config.StepData, execution } if paramName == "script" { - return checkParameterInfo("[![Jenkins only](https://img.shields.io/badge/-Jenkins%20only-yellowgreen)](#) reference to Jenkins main pipeline script", true, executionEnvironment) + return checkParameterInfo(fmt.Sprintf("%s reference to Jenkins main pipeline script", jenkinsOnlyBadge), true, executionEnvironment) } // handle non-step parameters (e.g. Jenkins-specific parameters as well as execution environment parameters) @@ -93,11 +101,11 @@ func parameterFurtherInfo(paramName string, stepData *config.StepData, execution if !contains(stepParameterNames, paramName) { for _, secret := range stepData.Spec.Inputs.Secrets { if paramName == secret.Name && secret.Type == "jenkins" { - return checkParameterInfo("[![Jenkins only](https://img.shields.io/badge/-Jenkins%20only-yellowgreen)](#) id of credentials ([using credentials](https://www.jenkins.io/doc/book/using/using-credentials/))", true, executionEnvironment) + return checkParameterInfo(fmt.Sprintf("%s id of credentials ([using credentials](https://www.jenkins.io/doc/book/using/using-credentials/))", jenkinsOnlyBadge), true, executionEnvironment) } } if contains(jenkinsParams, paramName) { - return checkParameterInfo("[![Jenkins only](https://img.shields.io/badge/-Jenkins%20only-yellowgreen)](#)", false, executionEnvironment) + return checkParameterInfo(fmt.Sprintf("%s", jenkinsOnlyBadge), false, executionEnvironment) } return checkParameterInfo("", false, executionEnvironment) } @@ -107,14 +115,19 @@ func parameterFurtherInfo(paramName string, stepData *config.StepData, execution if paramName == param.Name { furtherInfo := "" if param.DeprecationMessage != "" { - furtherInfo += "![deprecated](https://img.shields.io/badge/-deprecated-red)" + furtherInfo += fmt.Sprintf("%s", deprecatedBadge) } if param.Secret { - secretInfo := "[![Secret](https://img.shields.io/badge/-Secret-yellowgreen)](#) pass via ENV or Jenkins credentials" - if param.GetReference("vaultSecret") != nil || param.GetReference("vaultSecretFile") != nil { - secretInfo = " [![Vault](https://img.shields.io/badge/-Vault-lightgrey)](#) [![Secret](https://img.shields.io/badge/-Secret-yellowgreen)](/) pass via ENV, Vault or Jenkins credentials" - + secretInfo := fmt.Sprintf("%s pass via ENV or Jenkins credentials", secretBadge) + + isVaultSecret := param.GetReference("vaultSecret") != nil || param.GetReference("vaultSecretFile") != nil + isTrustengineSecret := param.GetReference(config.RefTypeTrustengineSecret) != nil + if isVaultSecret && isTrustengineSecret { + secretInfo = fmt.Sprintf(" %s %s %s pass via ENV, Vault, Trust Engine or Jenkins credentials", vaultBadge, trustengineBadge, secretBadge) + } else if isVaultSecret { + secretInfo = fmt.Sprintf(" %s %s pass via ENV, Vault or Jenkins credentials", vaultBadge, secretBadge) } + for _, res := range param.ResourceRef { if res.Type == "secret" { secretInfo += fmt.Sprintf(" ([`%v`](#%v))", res.Name, strings.ToLower(res.Name)) @@ -329,24 +342,37 @@ func resourceReferenceDetails(resourceRef []config.ResourceReference) string { continue } - resourceDetails = addVaultResourceDetails(resource, resourceDetails) + if resource.Type == "vaultSecret" || resource.Type == "vaultSecretFile" { + resourceDetails = addVaultResourceDetails(resource, resourceDetails) + continue + } + if resource.Type == config.RefTypeTrustengineSecret { + resourceDetails = addTrustEngineResourceDetails(resource, resourceDetails) + } } return resourceDetails } func addVaultResourceDetails(resource config.ResourceReference, resourceDetails string) string { - if resource.Type == "vaultSecret" || resource.Type == "vaultSecretFile" { - resourceDetails += "
Vault resource:
" - resourceDetails += fmt.Sprintf("  name: `%v`
", resource.Name) - resourceDetails += fmt.Sprintf("  default value: `%v`
", resource.Default) - resourceDetails += "
Vault paths:
" - resourceDetails += "
    " - for _, rootPath := range config.VaultRootPaths { - resourceDetails += fmt.Sprintf("
  • `%s`
  • ", path.Join(rootPath, resource.Default)) - } - resourceDetails += "
" + resourceDetails += "
Vault resource:
" + resourceDetails += fmt.Sprintf("  name: `%v`
", resource.Name) + resourceDetails += fmt.Sprintf("  default value: `%v`
", resource.Default) + resourceDetails += "
Vault paths:
" + resourceDetails += "
    " + for _, rootPath := range config.VaultRootPaths { + resourceDetails += fmt.Sprintf("
  • `%s`
  • ", path.Join(rootPath, resource.Default)) } + resourceDetails += "
" + + return resourceDetails +} + +func addTrustEngineResourceDetails(resource config.ResourceReference, resourceDetails string) string { + resourceDetails += "
Trust Engine resource:
" + resourceDetails += fmt.Sprintf("  name: `%v`
", resource.Name) + resourceDetails += fmt.Sprintf("  value: `%v`
", resource.Default) + return resourceDetails } diff --git a/pkg/documentation/generator/parameters_test.go b/pkg/documentation/generator/parameters_test.go index adc9deaff9..97295bcde3 100644 --- a/pkg/documentation/generator/parameters_test.go +++ b/pkg/documentation/generator/parameters_test.go @@ -48,7 +48,7 @@ func TestCreateParameterOverview(t *testing.T) { expected := `| Name | Mandatory | Additional information | | ---- | --------- | ---------------------- | | [dockerImage](#dockerimage) | no | | -| [stashContent](#stashcontent) | no | [![Jenkins only](https://img.shields.io/badge/-Jenkins%20only-yellowgreen)](#) | +| [stashContent](#stashcontent) | no | ![Jenkins only](https://img.shields.io/badge/-Jenkins%20only-yellowgreen) | ` assert.Equal(t, expected, createParameterOverview(&stepData, true)) @@ -107,7 +107,7 @@ func TestParameterFurtherInfo(t *testing.T) { }, }, }, - contains: "![deprecated](https://img.shields.io/badge/-deprecated-red)[![Secret](https://img.shields.io/badge/-Secret-yellowgreen)](#)", + contains: "![deprecated](https://img.shields.io/badge/-deprecated-red)![Secret](https://img.shields.io/badge/-Secret-yellowgreen)", }, { paramName: "testSecret2", diff --git a/pkg/http/http.go b/pkg/http/http.go index affac535f6..2ae3f8cc80 100644 --- a/pkg/http/http.go +++ b/pkg/http/http.go @@ -316,9 +316,7 @@ func (c *Client) initializeHttpClient() *http.Client { if c.maxRetries > 0 { retryClient := retryablehttp.NewClient() - localLogger := log.Entry() - localLogger.Level = logrus.DebugLevel - retryClient.Logger = localLogger + retryClient.Logger = c.logger retryClient.HTTPClient.Timeout = c.maxRequestDuration retryClient.HTTPClient.Jar = c.cookieJar retryClient.RetryMax = c.maxRetries @@ -401,12 +399,13 @@ func (t *TransportWrapper) logRequest(req *http.Request) { log.Entry().Debugf("--> %v request to %v", req.Method, req.URL) log.Entry().Debugf("headers: %v", transformHeaders(req.Header)) log.Entry().Debugf("cookies: %v", transformCookies(req.Cookies())) - if t.doLogRequestBodyOnDebug && req.Body != nil { + if t.doLogRequestBodyOnDebug && req.Header.Get("Content-Type") == "application/octet-stream" { + // skip logging byte content as it's useless + } else if t.doLogRequestBodyOnDebug && req.Body != nil { var buf bytes.Buffer tee := io.TeeReader(req.Body, &buf) log.Entry().Debugf("body: %v", transformBody(tee)) req.Body = io.NopCloser(bytes.NewReader(buf.Bytes())) - log.Entry().Debugf("body: %v", transformBody(tee)) } log.Entry().Debug("--------------------------------") } diff --git a/pkg/kubernetes/helm.go b/pkg/kubernetes/helm.go index cc7fc1bdac..727127eece 100644 --- a/pkg/kubernetes/helm.go +++ b/pkg/kubernetes/helm.go @@ -167,6 +167,10 @@ func (h *HelmExecute) RunHelmUpgrade() error { helmParams = append(helmParams, "--wait", "--timeout", fmt.Sprintf("%vs", h.config.HelmDeployWaitSeconds)) + if len(h.config.KubeContext) > 0 { + helmParams = append(helmParams, "--kube-context", h.config.KubeContext) + } + if !h.config.KeepFailedDeployments { helmParams = append(helmParams, "--atomic") } @@ -238,6 +242,10 @@ func (h *HelmExecute) RunHelmInstall() error { helmParams = append(helmParams, "--namespace", h.config.Namespace) helmParams = append(helmParams, "--create-namespace") + if len(h.config.KubeContext) > 0 { + helmParams = append(helmParams, "--kube-context", h.config.KubeContext) + } + if !h.config.KeepFailedDeployments { helmParams = append(helmParams, "--atomic") } @@ -288,6 +296,9 @@ func (h *HelmExecute) RunHelmUninstall() error { if len(h.config.Namespace) <= 0 { return fmt.Errorf("namespace has not been set, please configure namespace parameter") } + if len(h.config.KubeContext) > 0 { + helmParams = append(helmParams, "--kube-context", h.config.KubeContext) + } helmParams = append(helmParams, "--namespace", h.config.Namespace) if h.config.HelmDeployWaitSeconds > 0 { helmParams = append(helmParams, "--wait", "--timeout", fmt.Sprintf("%vs", h.config.HelmDeployWaitSeconds)) diff --git a/pkg/mock/fileUtils.go b/pkg/mock/fileUtils.go index ab36a5d001..b8d13ff6cd 100644 --- a/pkg/mock/fileUtils.go +++ b/pkg/mock/fileUtils.go @@ -486,6 +486,10 @@ func (f *FilesMock) Stat(path string) (os.FileInfo, error) { }, nil } +func (f *FilesMock) Lstat(path string) (os.FileInfo, error) { + return f.Stat(path) +} + // Chmod changes the file mode for the entry at the given path func (f *FilesMock) Chmod(path string, mode os.FileMode) error { props, exists := f.files[f.toAbsPath(path)] @@ -540,8 +544,9 @@ func (f *FilesMock) Symlink(oldname, newname string) error { f.init() f.files[newname] = &fileProperties{ - isLink: true, - target: oldname, + isLink: true, + target: oldname, + content: &[]byte{}, } return nil @@ -700,3 +705,11 @@ func (f *FilesMockRelativeGlob) Glob(pattern string) ([]string, error) { sort.Strings(matches) return matches, nil } + +func (f *FilesMock) Readlink(name string) (string, error) { + properties, ok := f.files[name] + if ok && properties.isLink { + return properties.target, nil + } + return "", fmt.Errorf("could not retrieve target for %s", name) +} diff --git a/pkg/npm/mock.go b/pkg/npm/mock.go index 036d3f2e61..d162181335 100644 --- a/pkg/npm/mock.go +++ b/pkg/npm/mock.go @@ -5,6 +5,7 @@ package npm import ( "fmt" + "github.com/SAP/jenkins-library/pkg/versioning" "github.com/SAP/jenkins-library/pkg/mock" ) @@ -123,6 +124,6 @@ func (n *NpmExecutorMock) CreateBOM(packageJSONFiles []string) error { } // CreateBOM mock implementation -func (n *NpmExecutorMock) PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool) error { +func (n *NpmExecutorMock) PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool, buildCoordinates *[]versioning.Coordinates) error { return nil } diff --git a/pkg/npm/npm.go b/pkg/npm/npm.go index 4768a0247a..4c8130c9b6 100644 --- a/pkg/npm/npm.go +++ b/pkg/npm/npm.go @@ -11,6 +11,7 @@ import ( "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/versioning" ) const ( @@ -34,7 +35,7 @@ type Executor interface { FindPackageJSONFilesWithScript(packageJSONFiles []string, script string) ([]string, error) RunScriptsInAllPackages(runScripts []string, runOptions []string, scriptOptions []string, virtualFrameBuffer bool, excludeList []string, packagesList []string) error InstallAllDependencies(packageJSONFiles []string) error - PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool) error + PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool, buildCoordinates *[]versioning.Coordinates) error SetNpmRegistries() error CreateBOM(packageJSONFiles []string) error } @@ -157,8 +158,8 @@ func (exec *Execute) RunScriptsInAllPackages(runScripts []string, runOptions []s } if len(packagesWithScript) == 0 { - log.Entry().Warnf("could not find any package.json file with script " + script) - continue + return fmt.Errorf("could not find any package.json file with script : %s ", script) + } for _, packageJSON := range packagesWithScript { diff --git a/pkg/npm/npm_test.go b/pkg/npm/npm_test.go index b207a60d28..52ef6e085a 100644 --- a/pkg/npm/npm_test.go +++ b/pkg/npm/npm_test.go @@ -280,7 +280,7 @@ func TestNpm(t *testing.T) { options := ExecutorOptions{} runScripts := []string{"ci-lint", "ci-build"} - buildDescriptorList := []string{filepath.Join("src", "package.json")} + buildDescriptorList := []string{filepath.Join("src", "package.json"), "package.json"} exec := &Execute{ Utils: &utils, @@ -289,8 +289,8 @@ func TestNpm(t *testing.T) { err := exec.RunScriptsInAllPackages(runScripts, nil, nil, false, nil, buildDescriptorList) if assert.NoError(t, err) { - if assert.Equal(t, 2, len(utils.execRunner.Calls)) { - assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run", "ci-build"}}, utils.execRunner.Calls[1]) + if assert.Equal(t, 4, len(utils.execRunner.Calls)) { + assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run", "ci-lint"}}, utils.execRunner.Calls[1]) } } }) diff --git a/pkg/npm/publish.go b/pkg/npm/publish.go index 628729894f..660e1ae114 100644 --- a/pkg/npm/publish.go +++ b/pkg/npm/publish.go @@ -11,6 +11,7 @@ import ( "github.com/SAP/jenkins-library/pkg/log" CredentialUtils "github.com/SAP/jenkins-library/pkg/piperutils" + "github.com/SAP/jenkins-library/pkg/versioning" ) type npmMinimalPackageDescriptor struct { @@ -31,7 +32,7 @@ func (pd *npmMinimalPackageDescriptor) Scope() string { } // PublishAllPackages executes npm publish for all package.json files defined in packageJSONFiles list -func (exec *Execute) PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool) error { +func (exec *Execute) PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool, buildCoordinates *[]versioning.Coordinates) error { for _, packageJSON := range packageJSONFiles { log.Entry().Infof("triggering publish for %s", packageJSON) @@ -43,7 +44,7 @@ func (exec *Execute) PublishAllPackages(packageJSONFiles []string, registry, use return fmt.Errorf("package.json file '%s' not found: %w", packageJSON, err) } - err = exec.publish(packageJSON, registry, username, password, packBeforePublish) + err = exec.publish(packageJSON, registry, username, password, packBeforePublish, buildCoordinates) if err != nil { return err } @@ -52,7 +53,7 @@ func (exec *Execute) PublishAllPackages(packageJSONFiles []string, registry, use } // publish executes npm publish for package.json -func (exec *Execute) publish(packageJSON, registry, username, password string, packBeforePublish bool) error { +func (exec *Execute) publish(packageJSON, registry, username, password string, packBeforePublish bool, buildCoordinates *[]versioning.Coordinates) error { execRunner := exec.Utils.GetExecRunner() oldWorkingDirectory, err := exec.Utils.Getwd() @@ -202,6 +203,25 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p } } + options := versioning.Options{} + var utils versioning.Utils + + artifact, err := versioning.GetArtifact("npm", packageJSON, &options, utils) + if err != nil { + log.Entry().Warnf("unable to get artifact metdata : %v", err) + } else { + coordinate, err := artifact.GetCoordinates() + if err != nil { + log.Entry().Warnf("unable to get artifact coordinates : %v", err) + } else { + coordinate.BuildPath = filepath.Dir(packageJSON) + coordinate.URL = registry + coordinate.Packaging = "tgz" + + *buildCoordinates = append(*buildCoordinates, coordinate) + } + } + return nil } diff --git a/pkg/npm/publish_test.go b/pkg/npm/publish_test.go index 6ca7fdaaaf..782e1b7c5c 100644 --- a/pkg/npm/publish_test.go +++ b/pkg/npm/publish_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/SAP/jenkins-library/pkg/piperutils" + "github.com/SAP/jenkins-library/pkg/versioning" "github.com/stretchr/testify/assert" ) @@ -534,7 +535,8 @@ func TestNpmPublish(t *testing.T) { return nil } - err := exec.PublishAllPackages(test.packageDescriptors, test.registryURL, test.registryUser, test.registryPassword, test.packBeforePublish) + coordinates := []versioning.Coordinates{} + err := exec.PublishAllPackages(test.packageDescriptors, test.registryURL, test.registryUser, test.registryPassword, test.packBeforePublish, &coordinates) if len(test.wants.err) == 0 && assert.NoError(t, err) { if assert.NotEmpty(t, utils.execRunner.Calls) { diff --git a/pkg/orchestrator/jenkins.go b/pkg/orchestrator/jenkins.go index 1e21da34e2..9844e943dc 100644 --- a/pkg/orchestrator/jenkins.go +++ b/pkg/orchestrator/jenkins.go @@ -24,7 +24,7 @@ func newJenkinsConfigProvider() *jenkinsConfigProvider { // Configure initializes the Jenkins orchestrator with credentials func (j *jenkinsConfigProvider) Configure(opts *Options) error { j.client.SetOptions(piperHttp.ClientOptions{ - Username: opts.JenkinsUser, + Username: opts.JenkinsUsername, Password: opts.JenkinsToken, MaxRetries: 3, TransportTimeout: time.Second * 10, diff --git a/pkg/orchestrator/orchestrator.go b/pkg/orchestrator/orchestrator.go index 52619a7c16..56a715eff2 100644 --- a/pkg/orchestrator/orchestrator.go +++ b/pkg/orchestrator/orchestrator.go @@ -1,10 +1,12 @@ package orchestrator import ( - "github.com/SAP/jenkins-library/pkg/log" - "github.com/pkg/errors" "sync" "time" + + "github.com/pkg/errors" + + "github.com/SAP/jenkins-library/pkg/log" ) const ( @@ -60,10 +62,10 @@ type ( // Options used to set orchestrator specific settings. Options struct { - JenkinsUser string - JenkinsToken string - AzureToken string - GitHubToken string + JenkinsUsername string + JenkinsToken string + AzureToken string + GitHubToken string } PullRequestConfig struct { diff --git a/pkg/piperutils/fileUtils.go b/pkg/piperutils/fileUtils.go index 4cc5091ba6..ce54dc741b 100644 --- a/pkg/piperutils/fileUtils.go +++ b/pkg/piperutils/fileUtils.go @@ -43,6 +43,9 @@ type FileUtils interface { CurrentTime(format string) string Open(name string) (io.ReadWriteCloser, error) Create(name string) (io.ReadWriteCloser, error) + Readlink(name string) (string, error) + Stat(path string) (os.FileInfo, error) + Lstat(path string) (os.FileInfo, error) } // Files ... @@ -513,3 +516,13 @@ func (f Files) Open(name string) (io.ReadWriteCloser, error) { func (f Files) Create(name string) (io.ReadWriteCloser, error) { return os.Create(name) } + +// Readlink wraps os.Readlink +func (f Files) Readlink(name string) (string, error) { + return os.Readlink(name) +} + +// Readlink wraps os.Readlink +func (f Files) Lstat(path string) (os.FileInfo, error) { + return os.Lstat(path) +} diff --git a/pkg/reporting/pullRequestReport_test.go b/pkg/reporting/pullRequestReport_test.go index 02cf7e7cd4..d7ad4aa218 100644 --- a/pkg/reporting/pullRequestReport_test.go +++ b/pkg/reporting/pullRequestReport_test.go @@ -113,7 +113,7 @@ func TestCreateMarkdownReport(t *testing.T) { ErrorMessage: "", }, }, - expectedReport: "\n :x: **OSS related checks failed**\n :clipboard: Policies violated by added OSS components\n " + + expectedReport: "\n :x: **OSS related checks failed**\n :clipboard: Policies violated by added OSS components\n " + "\n \n
Component nameHigh Vulnerability Security IssueOutdatedFOSSLibraries" + "Test High Severity Vuln Filter
Chalk 1.1.3 (npmjs:chalk/1.1.3)010
Lodash " + "4.17.10 (npmjs:lodash/4.17.10)313
qs - QS Querystring 5.2.1 " + diff --git a/pkg/trustengine/trustengine.go b/pkg/trustengine/trustengine.go new file mode 100644 index 0000000000..99caf500ae --- /dev/null +++ b/pkg/trustengine/trustengine.go @@ -0,0 +1,135 @@ +package trustengine + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + + piperhttp "github.com/SAP/jenkins-library/pkg/http" + "github.com/SAP/jenkins-library/pkg/log" +) + +type Secret struct { + Token string + System string +} + +type Response struct { + Secrets []Secret +} + +type Configuration struct { + ServerURL string + TokenEndPoint string + TokenQueryParamName string + Token string +} + +// GetToken requests a single token +func GetToken(refName string, client *piperhttp.Client, trustEngineConfiguration Configuration) (string, error) { + secrets, err := GetSecrets([]string{refName}, client, trustEngineConfiguration) + if err != nil { + return "", errors.Wrap(err, "couldn't get token from trust engine") + } + for _, s := range secrets { + if s.System == refName { + return s.Token, nil + } + } + return "", errors.New("could not find token in trust engine response") +} + +// GetSecrets transforms the trust engine JSON response into trust engine secrets, and can be used to request multiple tokens +func GetSecrets(refNames []string, client *piperhttp.Client, trustEngineConfiguration Configuration) ([]Secret, error) { + var secrets []Secret + query := url.Values{ + trustEngineConfiguration.TokenQueryParamName: { + strings.Join(refNames, ","), + }, + } + response, err := getResponse(trustEngineConfiguration.ServerURL, trustEngineConfiguration.TokenEndPoint, query, client) + if err != nil { + return secrets, errors.Wrap(err, "getting secrets from trust engine failed") + } + for k, v := range response { + secrets = append(secrets, Secret{ + System: k, + Token: v}) + } + + return secrets, nil +} + +// getResponse returns a map of the JSON response that the trust engine puts out +func getResponse(serverURL, endpoint string, query url.Values, client *piperhttp.Client) (map[string]string, error) { + var secrets map[string]string + + rawURL, err := parseURL(serverURL, endpoint, query) + if err != nil { + return secrets, errors.Wrap(err, "parsing trust engine url failed") + } + header := make(http.Header) + header.Add("Accept", "application/json") + + log.Entry().Debugf(" with URL %s", rawURL) + response, err := client.SendRequest(http.MethodGet, rawURL, nil, header, nil) + if err != nil { + if response != nil { + // the body contains full error message which we want to log + defer response.Body.Close() + bodyBytes, bodyErr := io.ReadAll(response.Body) + if bodyErr == nil { + err = errors.Wrap(err, string(bodyBytes)) + } + } + return secrets, errors.Wrap(err, "getting response from trust engine failed") + } + defer response.Body.Close() + + err = json.NewDecoder(response.Body).Decode(&secrets) + if err != nil { + return secrets, errors.Wrap(err, "getting response from trust engine failed") + } + + return secrets, nil +} + +// parseURL creates the full URL for a Trust Engine GET request +func parseURL(serverURL, endpoint string, query url.Values) (string, error) { + rawFullEndpoint, err := url.JoinPath(serverURL, endpoint) + if err != nil { + return "", errors.New("error parsing trust engine URL") + } + fullURL, err := url.Parse(rawFullEndpoint) + if err != nil { + return "", errors.New("error parsing trust engine URL") + } + // commas and spaces shouldn't be escaped since the Trust Engine won't accept it + unescapedRawQuery, err := url.QueryUnescape(query.Encode()) + if err != nil { + return "", errors.New("error parsing trust engine URL") + } + fullURL.RawQuery = unescapedRawQuery + return fullURL.String(), nil +} + +// PrepareClient adds the Trust Engine authentication token to the client +func PrepareClient(client *piperhttp.Client, trustEngineConfiguration Configuration) *piperhttp.Client { + var logEntry *logrus.Entry + if logrus.GetLevel() < logrus.DebugLevel { + logger := logrus.New() + logger.SetOutput(io.Discard) + logEntry = logrus.NewEntry(logger) + } + client.SetOptions(piperhttp.ClientOptions{ + Token: fmt.Sprintf("Bearer %s", trustEngineConfiguration.Token), + Logger: logEntry, + }) + return client +} diff --git a/pkg/trustengine/trustengine_test.go b/pkg/trustengine/trustengine_test.go new file mode 100644 index 0000000000..d1ca1b1793 --- /dev/null +++ b/pkg/trustengine/trustengine_test.go @@ -0,0 +1,80 @@ +//go:build unit +// +build unit + +package trustengine + +import ( + "fmt" + "github.com/jarcoal/httpmock" + "net/http" + "testing" + + piperhttp "github.com/SAP/jenkins-library/pkg/http" + "github.com/stretchr/testify/assert" +) + +const testServerURL = "https://www.project-piper.io" +const testTokenEndPoint = "tokens" +const testTokenQueryParamName = "systems" +const mockSonarToken = "mockSonarToken" +const mockblackduckToken = "mockblackduckToken" +const errorMsg403 = "unauthorized to request token" + +var testFullURL = fmt.Sprintf("%s/%s?%s=", testServerURL, testTokenEndPoint, testTokenQueryParamName) +var mockSingleTokenResponse = fmt.Sprintf("{\"sonar\": \"%s\"}", mockSonarToken) +var mockTwoTokensResponse = fmt.Sprintf("{\"sonar\": \"%s\", \"blackduck\": \"%s\"}", mockSonarToken, mockblackduckToken) +var trustEngineConfiguration = Configuration{ + Token: "testToken", + ServerURL: testServerURL, + TokenEndPoint: testTokenEndPoint, + TokenQueryParamName: testTokenQueryParamName, +} + +func TestTrustEngine(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + t.Run("Get Sonar token - happy path", func(t *testing.T) { + httpmock.RegisterResponder(http.MethodGet, testFullURL+"sonar", httpmock.NewStringResponder(200, mockSingleTokenResponse)) + + client := &piperhttp.Client{} + client.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true}) + + token, err := GetToken("sonar", client, trustEngineConfiguration) + assert.NoError(t, err) + assert.Equal(t, mockSonarToken, token) + }) + + t.Run("Get multiple tokens - happy path", func(t *testing.T) { + httpmock.RegisterResponder(http.MethodGet, testFullURL+"sonar,blackduck", httpmock.NewStringResponder(200, mockTwoTokensResponse)) + + client := &piperhttp.Client{} + client.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true}) + + secrets, err := GetSecrets([]string{"sonar", "blackduck"}, client, trustEngineConfiguration) + + assert.NoError(t, err) + assert.Len(t, secrets, 2) + for _, s := range secrets { + switch system := s.System; system { + case "sonar": + assert.Equal(t, mockSonarToken, s.Token) + case "blackduck": + assert.Equal(t, mockblackduckToken, s.Token) + default: + continue + } + } + }) + + t.Run("Get Sonar token - 403 error", func(t *testing.T) { + httpmock.RegisterResponder(http.MethodGet, testFullURL+"sonar", httpmock.NewStringResponder(403, errorMsg403)) + + client := &piperhttp.Client{} + client.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true}) + + _, err := GetToken("sonar", client, trustEngineConfiguration) + assert.Error(t, err) + }) + +} diff --git a/pkg/vault/client.go b/pkg/vault/client.go index f9350958b0..ba1e14e929 100644 --- a/pkg/vault/client.go +++ b/pkg/vault/client.go @@ -169,9 +169,19 @@ func (v Client) GetKvSecret(path string) (map[string]string, error) { secretData := make(map[string]string, len(data)) for k, v := range data { - valueStr, ok := v.(string) - if ok { - secretData[k] = valueStr + switch t := v.(type) { + case string: + secretData[k] = t + case int: + secretData[k] = fmt.Sprintf("%d", t) + default: + jsonBytes, err := json.Marshal(t) + if err != nil { + log.Entry().Warnf("failed to parse Vault secret key %q, error: %s", k, err.Error()) + continue + } + + secretData[k] = string(jsonBytes) } } return secretData, nil diff --git a/pkg/vault/client_test.go b/pkg/vault/client_test.go index d95afd1f56..90a86b35bb 100644 --- a/pkg/vault/client_test.go +++ b/pkg/vault/client_test.go @@ -28,7 +28,6 @@ const ( ) func TestGetKV2Secret(t *testing.T) { - t.Run("Test missing secret", func(t *testing.T) { vaultMock := &mocks.VaultMock{} client := Client{vaultMock, &Config{}} @@ -47,21 +46,13 @@ func TestGetKV2Secret(t *testing.T) { vaultMock := &mocks.VaultMock{} setupMockKvV2(vaultMock) client := Client{vaultMock, &Config{}} - vaultMock.On("Read", secretAPIPath).Return(kv2Secret(SecretData{"key1": "value1"}), nil) + vaultMock.On("Read", secretAPIPath).Return(kv2Secret(SecretData{"key1": "value1", "key2": map[string]any{"subkey1": "subvalue2"}, "key3": 3, "key4": []string{"foo", "bar"}}), nil) secret, err := client.GetKvSecret(secretName) assert.NoError(t, err, "Expect GetKvSecret to succeed") assert.Equal(t, "value1", secret["key1"]) - - }) - - t.Run("field ignored when 'data' field can't be parsed", func(t *testing.T) { - vaultMock := &mocks.VaultMock{} - setupMockKvV2(vaultMock) - client := Client{vaultMock, &Config{}} - vaultMock.On("Read", secretAPIPath).Return(kv2Secret(SecretData{"key1": "value1", "key2": 5}), nil) - secret, err := client.GetKvSecret(secretName) - assert.NoError(t, err) - assert.Empty(t, secret["key2"]) + assert.Equal(t, `{"subkey1":"subvalue2"}`, secret["key2"]) + assert.Equal(t, "3", secret["key3"]) + assert.Equal(t, `["foo","bar"]`, secret["key4"]) }) t.Run("error is thrown when data field is missing", func(t *testing.T) { @@ -96,22 +87,11 @@ func TestGetKV1Secret(t *testing.T) { setupMockKvV1(vaultMock) client := Client{vaultMock, &Config{}} - vaultMock.On("Read", secretName).Return(kv1Secret(SecretData{"key1": "value1"}), nil) + vaultMock.On("Read", secretName).Return(kv1Secret(SecretData{"key1": "value1", "key2": 5}), nil) secret, err := client.GetKvSecret(secretName) assert.NoError(t, err) assert.Equal(t, "value1", secret["key1"]) - }) - - t.Run("Test parsing KV1 secrets", func(t *testing.T) { - vaultMock := &mocks.VaultMock{} - setupMockKvV1(vaultMock) - vaultMock.On("Read", secretName).Return(kv1Secret(SecretData{"key1": 5}), nil) - client := Client{vaultMock, &Config{}} - - secret, err := client.GetKvSecret(secretName) - assert.NoError(t, err) - assert.Empty(t, secret["key1"]) - + assert.Equal(t, "5", secret["key2"]) }) } diff --git a/pkg/versioning/versioning.go b/pkg/versioning/versioning.go index 471bd55846..1ea42b48f8 100644 --- a/pkg/versioning/versioning.go +++ b/pkg/versioning/versioning.go @@ -17,6 +17,8 @@ type Coordinates struct { ArtifactID string Version string Packaging string + BuildPath string + URL string } // Artifact defines the versioning operations for various build tools diff --git a/resources/com.sap.piper/pipeline/cloudSdkToGppConfigSettings.yml b/resources/com.sap.piper/pipeline/cloudSdkToGppConfigSettings.yml deleted file mode 100644 index a531a6fba8..0000000000 --- a/resources/com.sap.piper/pipeline/cloudSdkToGppConfigSettings.yml +++ /dev/null @@ -1,138 +0,0 @@ -# This file should be removed when existing cloud sdk consumers switched to general purpose pipeline -# This should be safe to do after Q2 2021 - -removedOrReplacedConfigKeys: - extensionRepository: - newConfigKey: "globalExtensionsRepository" - general: true - customMessage: "To configure a version please use globalExtensionsVersion. - You can also configure globalExtensionsRepositoryCredentialsId in case the extension repository is secured. - Please note that you can also configure these values as part of your custom defaults / shared configuration." - orgToken: - stages: ["whitesourceScan", "Security"] - customMessage: "The credentials ID for the WhiteSource org-token should to be moved to the step configuration of 'whitesourceExecuteScan'. - Store it as a 'Secret Text' in Jenkins and supply the ID the 'orgAdminUserTokenCredentialsId' field instead." - archiveDebugLog: - postAction: true - customMessage: "Please use the step configuration for debugReportArchive instead." - tmsUpload: - stages: ["productionDeployment", "Release"] - customMessage: "Please configure the step 'tmsUpload' instead. - Details can be found in the release notes at https://github.com/SAP/cloud-s4-sdk-pipeline/releases/tag/v39 as well as in the step documentation: https://sap.github.io/jenkins-library/steps/tmsUpload/." - sharedConfiguration: - newConfigKey: "customDefaults" - general: true - customMessage: "In addition please move it to the root level of the config file, i.e. before the 'general' section. - The value of this key needs to be a list of strings. - See also https://sap.github.io/jenkins-library/configuration/#custom-default-configuration for more information. - As an example for the necessary change, please consult the release notes of v33 of the Cloud SDK Pipeline at https://github.com/SAP/cloud-s4-sdk-pipeline/releases/tag/v33" - automaticVersioning: - general: true - customMessage: "Please configure the 'artifactPrepareVersion' step instead. - Details can be found in the release notes of v37 of the pipeline: https://github.com/SAP/cloud-s4-sdk-pipeline/releases/tag/v37" - sapNpmRegistry: - steps: ["executeNpm", "npmExecuteScripts", "npmExecuteLint", "mtaBuild"] - warnInsteadOfError: true - customMessage: "The parameter will be ignored during execution. - This configuration option was removed in version v41, since the packages of the public SAP NPM Registry were migrated to the default public registry at npmjs.org. - Please configure the defaultNpmRegistry parameter instead, in case a custom NPM registry configuration is required." - sendNotification: - postAction: true - customMessage: "Details can be found in the release notes of v43 of the Cloud SDK Pipeline: https://github.com/SAP/cloud-s4-sdk-pipeline/releases/tag/v43" - -requiredConfigKeys: - inferBuildTool: - general: true - customMessage: "Please specify 'inferBuildTool: true' in the general section of your .pipeline/config.yml file. - This will activate a number of features previously activated by the Cloud SDK Pipeline's default configuration." - -removedOrReplacedSteps: - executeMaven: - newStepName: "mavenExecute" - deployToCfWithCli: - newStepName: "cloudFoundryDeploy" - deployToNeoWithCli: - newStepName: "deployToNeoWithCli" - executeFortifyScan: - newStepName: "fortifyExecuteScan" - artifactSetVersion: - newStepName: "artifactPrepareVersion" - onlyCheckProjectConfig: true - customMessage: "Details can be found in the release notes of v37 of the Cloud SDK Pipeline: https://github.com/SAP/cloud-s4-sdk-pipeline/releases/tag/v37" - createHdiContainer: - customMessage: "The createHdiContainer step is no longer available. - If you still need the functionalities provided by this step, please open an issue at: https://github.com/SAP/cloud-s4-sdk-pipeline/issues/new?template=pipeline-issue.md - Apart from that it is also possible to implement an extension for the stage 'Integration' using the extensibility concept explained in the documentation: https://sap.github.io/jenkins-library/extensibility/" - checkJMeter: - customMessage: "The checkJMeter step is no longer available. - If you still need the functionalities provided by this step, please open an issue at: https://github.com/SAP/cloud-s4-sdk-pipeline/issues/new?template=pipeline-issue.md - Apart from that it is also possible to implement an extension for the stage 'Performance' using the extensibility concept explained in the documentation: https://sap.github.io/jenkins-library/extensibility/" - checkGatling: - newStepName: "gatlingExecuteTests" - -removedOrReplacedStages: - integrationTests: - newStageName: "Integration" - backendIntegrationTests: - newStageName: "Integration" - frontendIntegrationTests: - newStageName: "Integration" - staticCodeChecks: - customMessage: "Since version v32 of Cloud SDK Pipeline, it is required to migrate the configuration into your pom.xml file or to the configuration of the new step mavenExecuteStaticCodeChecks. - Details can be found in the release notes as well as in the step documentation: https://sap.github.io/jenkins-library/steps/mavenExecuteStaticCodeChecks/." - fortifyScan: - customMessage: "To configure Fortify please use the step configuration for fortifyExecuteScan. - Details can be found in the documentation: https://sap.github.io/jenkins-library/steps/fortifyExecuteScan/" - lint: - customMessage: "Since version v43 of Cloud SDK Pipeline, it is required to configure the step npmExecuteLint instead. - Details can be found in the release notes as well as in the step documentation: https://sap.github.io/jenkins-library/steps/npmExecuteLint/." - frontendUnitTests: - newStageName: "Additional Unit Tests" - npmAudit: - customMessage: "Details can be found in the release notes of v43 of the Cloud SDK Pipeline: https://github.com/SAP/cloud-s4-sdk-pipeline/releases/tag/v43" - s4SdkQualityChecks: - customMessage: "Details can be found in the release notes of v43 of the Cloud SDK Pipeline: https://github.com/SAP/cloud-s4-sdk-pipeline/releases/tag/v43" - sonarQubeScan: - newStageName: "Compliance" - customMessage: "Details can be found in the release notes of v43 of the Cloud SDK Pipeline: https://github.com/SAP/cloud-s4-sdk-pipeline/releases/tag/v43" - checkmarxScan: - newStageName: "Security" - customMessage: "To configure Checkmarx please use the step configuration for checkmarxExecuteScan. - Details can be found in the documentation: https://sap.github.io/jenkins-library/steps/checkmarxExecuteScan/" - detectScan: - newStageName: "Security" - customMessage: "To configure Synopsys Detect please use the step configuration for detectExecuteScan. - Details can be found in the documentation: https://sap.github.io/jenkins-library/steps/detectExecuteScan/" - additionalTools: - customMessage: "Details can be found in the release notes of v43 of the Cloud SDK Pipeline: https://github.com/SAP/cloud-s4-sdk-pipeline/releases/tag/v43" - build: - newStageName: "Build" - integration: - newStageName: "Integration" - additionalUnitTests: - newStageName: "Additional Unit Tests" - endToEndTests: - newStageName: "Acceptance" - performanceTests: - newStageName: "Performance" - security: - newStageName: "Security" - compliance: - newStageName: "Compliance" - artifactDeployment: - customMessage: "The General Purpose Pipeline does not execute the stage 'Artifact Deployment' and there is no alternative stage for the functionality." - productionDeployment: - newStageName: "Release" - -parameterTypeChanged: - appUrls: - oldType: "String" - newType: "List" - stages: ["productionDeployment", "endToEndTests", "Release", "Acceptance"] - -renamedNpmScript: - ci-integration-test: - newScriptName: "ci-it-backend" - ci-test: - newScriptName: "ci-frontend-unit-test" - warnInsteadOfError: true diff --git a/resources/metadata/abapAddonAssemblyKitCheck.yaml b/resources/metadata/abapAddonAssemblyKitCheck.yaml index a5f9463d99..d3d2e1ca64 100644 --- a/resources/metadata/abapAddonAssemblyKitCheck.yaml +++ b/resources/metadata/abapAddonAssemblyKitCheck.yaml @@ -91,6 +91,13 @@ spec: resourceRef: - name: commonPipelineEnvironment param: abap/addonDescriptor + - name: abapAddonAssemblyKitOriginHash + type: string + description: Origin Hash for restricted AAKaaS scenarios + scope: + - PARAMETERS + mandatory: false + secret: true outputs: resources: - name: commonPipelineEnvironment diff --git a/resources/metadata/abapEnvironmentCloneGitRepo.yaml b/resources/metadata/abapEnvironmentCloneGitRepo.yaml index 746c2c3a82..6a49f159fa 100644 --- a/resources/metadata/abapEnvironmentCloneGitRepo.yaml +++ b/resources/metadata/abapEnvironmentCloneGitRepo.yaml @@ -84,6 +84,10 @@ spec: - STAGES - STEPS - GENERAL + possibleValues: + - TOKEN + - BASIC + default: TOKEN - name: repositories type: string description: Specifies a YAML file containing the repositories configuration diff --git a/resources/metadata/azureBlobUpload.yaml b/resources/metadata/azureBlobUpload.yaml index ff6a0089ca..a022e533e4 100644 --- a/resources/metadata/azureBlobUpload.yaml +++ b/resources/metadata/azureBlobUpload.yaml @@ -19,8 +19,11 @@ spec: - PARAMETERS secret: true resourceRef: - - name: azureCredentialsId - type: secret + - type: vaultSecret + name: azureDevOpsVaultSecretName + default: azure-dev-ops + - type: secret + name: azureCredentialsId - name: filePath resourceRef: - name: commonPipelineEnvironment diff --git a/resources/metadata/mavenBuild.yaml b/resources/metadata/mavenBuild.yaml index e2ccfd7c7b..dc56fb3233 100644 --- a/resources/metadata/mavenBuild.yaml +++ b/resources/metadata/mavenBuild.yaml @@ -242,6 +242,14 @@ spec: - -Dmaven.main.skip=true - -Dmaven.test.skip=true - -Dmaven.install.skip=true + - name: createBuildArtifactsMetadata + type: bool + default: false + description: metadata about the artifacts that are build and published , this metadata is generally used by steps downstream in the pipeline + scope: + - STEPS + - STAGES + - PARAMETERS resources: - type: stash outputs: @@ -250,6 +258,7 @@ spec: type: piperEnvironment params: - name: custom/buildSettingsInfo + - name: custom/mavenBuildArtifacts - name: reports type: reports params: diff --git a/resources/metadata/mtaBuild.yaml b/resources/metadata/mtaBuild.yaml index b69bb6a8e0..acbe5c06a7 100644 --- a/resources/metadata/mtaBuild.yaml +++ b/resources/metadata/mtaBuild.yaml @@ -236,6 +236,14 @@ spec: - STAGES - PARAMETERS default: false + - name: enableSetTimestamp + type: bool + description: Enables setting the timestamp in the `mta.yaml` when it contains `${timestamp}`. Disable this when you want the MTA Deploy Service to do this instead. + scope: + - STEPS + - STAGES + - PARAMETERS + default: true outputs: resources: - name: commonPipelineEnvironment diff --git a/resources/metadata/npmExecuteScripts.yaml b/resources/metadata/npmExecuteScripts.yaml index 2dd39b941a..529c6d32ca 100644 --- a/resources/metadata/npmExecuteScripts.yaml +++ b/resources/metadata/npmExecuteScripts.yaml @@ -163,12 +163,21 @@ spec: - STEPS - STAGES - PARAMETERS + - name: createBuildArtifactsMetadata + type: bool + default: false + description: metadata about the artifacts that are build and published , this metadata is generally used by steps downstream in the pipeline + scope: + - STEPS + - STAGES + - PARAMETERS outputs: resources: - name: commonPipelineEnvironment type: piperEnvironment params: - name: custom/buildSettingsInfo + - name: custom/npmBuildArtifacts - name: reports type: reports params: diff --git a/resources/metadata/sonarExecuteScan.yaml b/resources/metadata/sonarExecuteScan.yaml index 43be0d24b0..db0e37e33c 100644 --- a/resources/metadata/sonarExecuteScan.yaml +++ b/resources/metadata/sonarExecuteScan.yaml @@ -53,6 +53,9 @@ spec: default: sonar - name: sonarTokenCredentialsId type: secret + - type: trustengineSecret + name: sonarTrustengineSecretName + default: sonar aliases: - name: sonarToken - name: organization diff --git a/src/com/sap/piper/PiperGoUtils.groovy b/src/com/sap/piper/PiperGoUtils.groovy index d3ca507e87..1206647d0d 100644 --- a/src/com/sap/piper/PiperGoUtils.groovy +++ b/src/com/sap/piper/PiperGoUtils.groovy @@ -30,7 +30,7 @@ class PiperGoUtils implements Serializable { if (steps.env.REPOSITORY_UNDER_TEST && steps.env.LIBRARY_VERSION_UNDER_TEST) { steps.echo("Running in a consumer test, building unit-under-test binary for verification.") - steps.dockerExecute(script: steps, dockerImage: 'golang:1.21', dockerOptions: '-u 0', dockerEnvVars: [ + steps.dockerExecute(script: steps, dockerImage: 'golang:1.22.4', dockerOptions: '-u 0', dockerEnvVars: [ REPOSITORY_UNDER_TEST: steps.env.REPOSITORY_UNDER_TEST, LIBRARY_VERSION_UNDER_TEST: steps.env.LIBRARY_VERSION_UNDER_TEST ]) { @@ -52,14 +52,13 @@ class PiperGoUtils implements Serializable { } } - def fallbackUrl = 'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master' + def fallbackUrl = 'https://github.com/SAP/jenkins-library/releases/latest/download/piper' def piperBinUrl = (version == 'master') ? fallbackUrl : "https://github.com/SAP/jenkins-library/releases/download/${version}/piper" boolean downloaded = downloadGoBinary(piperBinUrl) if (!downloaded) { //Inform that no Piper binary is available for used library branch steps.echo ("Not able to download go binary of Piper for version ${version}") - //Fallback to master version & throw error in case this fails steps.retry(12) { if (!downloadGoBinary(fallbackUrl)) { steps.sleep(10) diff --git a/test/groovy/com/sap/piper/PiperGoUtilsTest.groovy b/test/groovy/com/sap/piper/PiperGoUtilsTest.groovy index 461c91dfac..94d49b55ed 100644 --- a/test/groovy/com/sap/piper/PiperGoUtilsTest.groovy +++ b/test/groovy/com/sap/piper/PiperGoUtilsTest.groovy @@ -63,11 +63,11 @@ class PiperGoUtilsTest extends BasePiperTest { }) shellCallRule.setReturnValue('[ -x ./piper ]', 1) - shellCallRule.setReturnValue('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master\'', '200') + shellCallRule.setReturnValue('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper\'', '200') piperGoUtils.unstashPiperBin() assertThat(shellCallRule.shell.size(), is(4)) - assertThat(shellCallRule.shell[1].toString(), is('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master\'')) + assertThat(shellCallRule.shell[1].toString(), is('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper\'')) assertThat(shellCallRule.shell[2].toString(), is('chmod +x piper')) assertThat(shellCallRule.shell[3].toString(), is('./piper version')) } @@ -102,7 +102,7 @@ class PiperGoUtilsTest extends BasePiperTest { shellCallRule.setReturnValue('[ -x ./piper ]', 1) shellCallRule.setReturnValue('./piper version', "1.2.3") shellCallRule.setReturnValue('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/download/notAvailable/piper\'', '404') - shellCallRule.setReturnValue('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master\'', '200') + shellCallRule.setReturnValue('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper\'', '200') // this mocks utils.unstash - mimic stash not existing helper.registerAllowedMethod("unstash", [String.class], { stashFileName -> @@ -113,7 +113,7 @@ class PiperGoUtilsTest extends BasePiperTest { assertThat(shellCallRule.shell.size(), is(5)) assertThat(shellCallRule.shell[0].toString(), is('[ -x ./piper ]')) assertThat(shellCallRule.shell[1].toString(), is('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/download/notAvailable/piper\'')) - assertThat(shellCallRule.shell[2].toString(), is('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master\'')) + assertThat(shellCallRule.shell[2].toString(), is('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper\'')) assertThat(shellCallRule.shell[3].toString(), is('chmod +x piper')) assertThat(shellCallRule.shell[4].toString(), is ('./piper version')) } @@ -125,7 +125,7 @@ class PiperGoUtilsTest extends BasePiperTest { shellCallRule.setReturnValue('[ -x ./piper ]', 1) shellCallRule.setReturnValue('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/download/notAvailable/piper\'', '404') - shellCallRule.setReturnValue('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master\'', '500') + shellCallRule.setReturnValue('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper\'', '500') helper.registerAllowedMethod("unstash", [String.class], { stashFileName -> return [] @@ -142,7 +142,7 @@ class PiperGoUtilsTest extends BasePiperTest { shellCallRule.setReturnValue('[ -x ./piper ]', 1) shellCallRule.setReturnValue('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/download/notAvailable/piper\'', '404') - shellCallRule.setReturnValue('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master\'', '500') + shellCallRule.setReturnValue('curl --insecure --silent --retry 5 --retry-max-time 240 --location --write-out \'%{http_code}\' --output piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper\'', '500') helper.registerAllowedMethod("unstash", [String.class], { stashFileName -> return [] diff --git a/vars/abapEnvironmentPipelineStageIntegrationTests.groovy b/vars/abapEnvironmentPipelineStageIntegrationTests.groovy index eb9c591a8d..968680ad0b 100644 --- a/vars/abapEnvironmentPipelineStageIntegrationTests.groovy +++ b/vars/abapEnvironmentPipelineStageIntegrationTests.groovy @@ -51,6 +51,10 @@ void call(Map parameters = [:]) { echo "Deployment test of add-on product failed." throw e } finally { + if (config.confirmDeletion) { + input message: "Deployment test has been executed. Once you proceed, the test system will be deleted." + } + if (!config.debug) { cloudFoundryDeleteService script: parameters.script } @@ -67,9 +71,5 @@ void call(Map parameters = [:]) { e = new Error('Unsupoorted integration test option.') throw e } - - if (config.confirmDeletion) { - input message: "Deployment test has been executed. Once you proceed, the test system will be deleted." - } } } diff --git a/vars/commonPipelineEnvironment.groovy b/vars/commonPipelineEnvironment.groovy index b0997292b8..b44842d9ca 100644 --- a/vars/commonPipelineEnvironment.groovy +++ b/vars/commonPipelineEnvironment.groovy @@ -60,6 +60,7 @@ class commonPipelineEnvironment implements Serializable { String abapAddonDescriptor + private Map valueMap = [:] void setValue(String property, value) {