diff --git a/frontend/packages/dev-console/integration-tests/features/build-config/shipwright-build/shipwright-build-detail-page.feature b/frontend/packages/dev-console/integration-tests/features/build-config/shipwright-build/shipwright-build-detail-page.feature new file mode 100644 index 00000000000..20fcf02adb1 --- /dev/null +++ b/frontend/packages/dev-console/integration-tests/features/build-config/shipwright-build/shipwright-build-detail-page.feature @@ -0,0 +1,78 @@ +@odc-4981 +Feature: Shipwright build details page + As a user, I want check my Shipwright Build and see all related BuildRuns in a second tab. + + Background: + Given user has installed OpenShift Pipelines Operator + And user is at developer perspective + And user has created or selected namespace "aut-shipwright-build-details" + And user has installed Shipwright Operator + And user is at Add page + And user has created shipwright builds + + + @smoke + Scenario: Shipwright build page in dev perspective: SWB-01-TC01 + When user navigates to Builds in Developer perspective + And user clicks on "Shipwright Builds" tab + Then user will see Shipwright Builds + And user will see "Succeeded", "Failed" and "Unknown" in Filter list + + + @smoke + Scenario: Shipwright build page in admin perspective: SWB-01-TC02 + When user switches to Administrative perspective + And user clicks on Builds navigation in Administrative perspective + Then user will see "Shipwright Builds" tab + Then user will see "Shipwright BuildRuns" tab + + + @regression + Scenario: Shipwright build details page: SWB-01-TC03 + Given user is on Builds navigation in Developer perspective + When user clicks on "Shipwright Builds" tab + And user clicks on "buildpack-nodejs-build-heroku" build + Then user will see "Strategy", "Source URL" and "Output image" + And user will see "Status" section + + + @regression + Scenario: Event tab in build details page: SWB-01-TC04 + Given user is at Shipwright Builds details page for build "buildpack-nodejs-build-heroku" + When user clicks on Event tab + Then user will see events steaming + + + @regression + Scenario: Filter in Shipwright build runs page: SWB-01-TC05 + Given user is at Shipwright Builds details page for build "buildpack-nodejs-build-heroku" + When user clicks on "BuildRuns" tab + And user clicks on Filter + Then user will see "Pending", "Running", "Succeeded", "Failed" and "Unknown" options + + + @regression + Scenario: Shipwright build runs details page: SWB-01-TC06 + Given user is at Shipwright Builds details page for build "buildpack-nodejs-build-heroku" + When user clicks on "BuildRuns" tab + And user clicks on build run "buildpack-nodejs-build-heroku-1" + Then user will see "BuildRun details" section + And user will see "Conditions" section + And user will see "Status", "Build" and "BuildSpec details" section in BuildRun details + + + @regression + Scenario: Event tab in build details page: SWB-01-TC07 + Given user is at Shipwright Builds details page for build "buildpack-nodejs-build-heroku" + When user clicks on "BuildRuns" tab + And user clicks on build run "buildpack-nodejs-build-heroku-1" + And user clicks on Event tab + Then user will see events steaming + + + @regression + Scenario: Checking error for failed build runs : SWB-01-TC08 + Given user is at Shipwright Builds run page "buildpack-nodejs-build-heroku" + And user has a failed build run + When user clicks on Failed Status + Then user will see pop up with error message diff --git a/frontend/packages/dev-console/integration-tests/support/constants/global.ts b/frontend/packages/dev-console/integration-tests/support/constants/global.ts index 1cdc7f8a183..27fc2919309 100644 --- a/frontend/packages/dev-console/integration-tests/support/constants/global.ts +++ b/frontend/packages/dev-console/integration-tests/support/constants/global.ts @@ -37,6 +37,7 @@ export enum operators { ServiceBinding = 'Service Binding Operator', CrunchyPostgresforKubernetes = 'Crunchy Postgres for Kubernetes', QuayContainerSecurity = 'Quay Container Security', + ShipwrightOperator = 'Shipwright Operator', } export enum authenticationType { diff --git a/frontend/packages/dev-console/integration-tests/support/constants/pageTitle.ts b/frontend/packages/dev-console/integration-tests/support/constants/pageTitle.ts index 908fe6f0f1d..5b46c50e3f7 100644 --- a/frontend/packages/dev-console/integration-tests/support/constants/pageTitle.ts +++ b/frontend/packages/dev-console/integration-tests/support/constants/pageTitle.ts @@ -14,6 +14,7 @@ export const pageTitle = { Add: 'Add', GitOPs: 'GitOps', Observe: 'Observe', + Builds: 'Builds', BuildConfigs: 'Build Configs', Search: 'Search', HelmReleases: 'Helm Releases', @@ -54,4 +55,5 @@ export const pageTitle = { KnativeEventings: 'KnativeEventings', CreateRepository: 'Create Repository', CustomResourceDefinitions: 'CustomResourceDefinitions', + ShipwrightBuild: 'ShipwrightBuild', }; diff --git a/frontend/packages/dev-console/integration-tests/support/pageObjects/build-po.ts b/frontend/packages/dev-console/integration-tests/support/pageObjects/build-po.ts new file mode 100644 index 00000000000..b8cc5a4046e --- /dev/null +++ b/frontend/packages/dev-console/integration-tests/support/pageObjects/build-po.ts @@ -0,0 +1,22 @@ +export const buildPO = { + admin: { + buildTab: '[data-quickstart-id="qs-nav-builds"]', + nav: '[data-test="nav"]', + }, + filter: '[aria-label="Options menu"]', + filterList: '[aria-labelledby="Status"]', + pane: '.co-m-pane__body', + eventTab: '[data-test-id="horizontal-link-public~Events"]', + eventStream: '.co-sysevent-stream', + breadcrumb: '[aria-label="Breadcrumb"]', + failedFilter: '[data-test-row-filter="Failed"]', + dev: { + buildTab: '[aria-label="Builds"]', + }, + shipwrightBuild: { + shipwrightBuildsTab: '[data-test-id="horizontal-link-Shipwright Builds"]', + shipwrightBuildRunsTab: '[data-test-id="horizontal-link-BuildRuns"]', + statusText: '[data-test="status-text"]', + }, + popup: '[data-test="failure-popup"]', +}; diff --git a/frontend/packages/dev-console/integration-tests/support/pageObjects/global-po.ts b/frontend/packages/dev-console/integration-tests/support/pageObjects/global-po.ts index b17a8092d5b..ec75b9d4468 100644 --- a/frontend/packages/dev-console/integration-tests/support/pageObjects/global-po.ts +++ b/frontend/packages/dev-console/integration-tests/support/pageObjects/global-po.ts @@ -46,3 +46,4 @@ export const pagePO = { create: '[data-test="item-create"]', breadcrumb: '[aria-label="Breadcrumb"]', }; +export const resourceRow = '[data-test-rows="resource-row"]'; diff --git a/frontend/packages/dev-console/integration-tests/support/pageObjects/operators-po.ts b/frontend/packages/dev-console/integration-tests/support/pageObjects/operators-po.ts index 4916072649a..2e54a2acdf4 100644 --- a/frontend/packages/dev-console/integration-tests/support/pageObjects/operators-po.ts +++ b/frontend/packages/dev-console/integration-tests/support/pageObjects/operators-po.ts @@ -42,6 +42,8 @@ export const operatorsPO = { '[data-test="crunchy-postgres-operator-certified-operators-openshift-marketplace"]', quayContainerSecurity: '[data-test="container-security-operator-redhat-operators-openshift-marketplace"]', + shipwrightOperator: + '[data-test="shipwright-operator-community-operators-openshift-marketplace"]', }, subscription: { logo: 'h1.co-clusterserviceversion-logo__name__clusterserviceversion', @@ -57,6 +59,7 @@ export const operatorsPO = { knativeEventingLink: '[title="knativeeventings.operator.knative.dev"]', operatorStatus: '[data-test="status-text"]', checlusterCRLink: '[title="checlusters.org.eclipse.che"]', + shipwrightBuildLink: '[title="shipwrightbuilds.operator.shipwright.io"]', }, sidePane: { install: '[data-test-id="operator-install-btn"]', diff --git a/frontend/packages/dev-console/integration-tests/support/pages/app.ts b/frontend/packages/dev-console/integration-tests/support/pages/app.ts index 4f31a888b64..b12fd8891a4 100644 --- a/frontend/packages/dev-console/integration-tests/support/pages/app.ts +++ b/frontend/packages/dev-console/integration-tests/support/pages/app.ts @@ -113,7 +113,7 @@ export const navigateTo = (opt: devNavigationMenu) => { } case devNavigationMenu.Builds: { cy.get(devNavigationMenuPO.builds).click(); - detailsPage.titleShouldContain(pageTitle.BuildConfigs); + detailsPage.titleShouldContain(pageTitle.Builds); cy.testA11y('Builds Page in dev perspective'); break; } diff --git a/frontend/packages/dev-console/integration-tests/support/pages/functions/installOperatorOnCluster.ts b/frontend/packages/dev-console/integration-tests/support/pages/functions/installOperatorOnCluster.ts index 92664b569d6..9b1404f6313 100644 --- a/frontend/packages/dev-console/integration-tests/support/pages/functions/installOperatorOnCluster.ts +++ b/frontend/packages/dev-console/integration-tests/support/pages/functions/installOperatorOnCluster.ts @@ -1,5 +1,6 @@ import { modal } from '@console/cypress-integration-tests/views/modal'; import { pipelinesPage } from '@console/pipelines-plugin/integration-tests/support/pages'; +import { detailsPage } from '../../../../../integration-tests-cypress/views/details-page'; import { pageTitle, operators, switchPerspective } from '../../constants'; import { operatorsPO } from '../../pageObjects'; import { app, perspective, projectNameSpace, sidePane } from '../app'; @@ -139,6 +140,36 @@ const waitForPipelineTasks = (retries: number = 30) => { }); }; +const createShipwrightBuild = () => { + projectNameSpace.selectProject(Cypress.env('NAMESPACE')); + cy.get('body').then(($body) => { + if ($body.find(operatorsPO.installOperators.search)) { + cy.get(operatorsPO.installOperators.search) + .clear() + .type(operators.ShipwrightOperator); + } + }); + cy.get(operatorsPO.installOperators.shipwrightBuildLink).click({ force: true }); + cy.get('body').then(($body) => { + if ($body.text().includes('Page Not Found')) { + cy.reload(); + } + }); + detailsPage.titleShouldContain(pageTitle.ShipwrightBuild); + app.waitForLoad(); + cy.get('body').then(($body) => { + if ($body.find('[role="grid"]').length > 0) { + cy.log(`${pageTitle.ShipwrightBuild} already subscribed`); + } else { + cy.byTestID('item-create').click(); + detailsPage.titleShouldContain(pageTitle.ShipwrightBuild); + cy.byTestID('create-dynamic-form').click(); + cy.byLegacyTestID('details-actions').should('be.visible'); + cy.contains('Ready', { timeout: 150000 }).should('be.visible'); + } + }); +}; + const performPostInstallationSteps = (operator: operators): void => { switch (operator) { case operators.ServerlessOperator: @@ -168,6 +199,10 @@ const performPostInstallationSteps = (operator: operators): void => { cy.log(`Performing Web Terminal post-installation steps`); waitForCRDs(operators.WebTerminalOperator); break; + case operators.ShipwrightOperator: + cy.log(`Performing Shipwright Operator post-installation steps`); + createShipwrightBuild(); + break; default: cy.log(`Nothing to do in post-installation steps`); } diff --git a/frontend/packages/dev-console/integration-tests/support/pages/operators-page.ts b/frontend/packages/dev-console/integration-tests/support/pages/operators-page.ts index 23607961864..7ce1e3fabf3 100644 --- a/frontend/packages/dev-console/integration-tests/support/pages/operators-page.ts +++ b/frontend/packages/dev-console/integration-tests/support/pages/operators-page.ts @@ -171,6 +171,11 @@ export const operatorsPage = { cy.get(operatorsPO.operatorHub.quayContainerSecurity).click(); break; } + case 'Shipwright Operator': + case operators.ShipwrightOperator: { + cy.get(operatorsPO.operatorHub.shipwrightOperator).click(); + break; + } default: { throw new Error('operator is not available'); } diff --git a/frontend/packages/dev-console/integration-tests/support/step-definitions/builds/shipwright-build-detail-page.ts b/frontend/packages/dev-console/integration-tests/support/step-definitions/builds/shipwright-build-detail-page.ts new file mode 100644 index 00000000000..676d27d8521 --- /dev/null +++ b/frontend/packages/dev-console/integration-tests/support/step-definitions/builds/shipwright-build-detail-page.ts @@ -0,0 +1,178 @@ +import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'; +import { devNavigationMenu, switchPerspective } from '../../constants'; +import { buildPO } from '../../pageObjects/build-po'; +import { resourceRow } from '../../pageObjects/global-po'; +import { navigateTo, perspective } from '../../pages'; + +When('user has created shipwright builds', () => { + cy.exec( + `oc apply -n ${Cypress.env('NAMESPACE')} -f testData/builds/shipwrightBuildStrategies.yaml`, + { + failOnNonZeroExit: false, + }, + ); + + const yamlFileName = `testData/builds/shipwrightBuild.yaml`; + cy.exec(`oc apply -n ${Cypress.env('NAMESPACE')} -f ${yamlFileName}`, { + failOnNonZeroExit: false, + }).then(function(result) { + cy.log(result.stdout); + }); +}); + +When('user navigates to Builds in Developer perspective', () => { + navigateTo(devNavigationMenu.Builds); +}); + +When('user switches to Administrative perspective', () => { + perspective.switchTo(switchPerspective.Administrator); +}); + +When('user clicks on Builds navigation in Administrative perspective', () => { + cy.get(buildPO.admin.buildTab) + .should('be.visible') + .click(); +}); + +Then('user will see {string} tab', (tab: string) => { + cy.get(buildPO.admin.nav) + .contains(tab) + .should('be.visible'); +}); + +Given('user is on Builds navigation in Developer perspective', () => { + navigateTo(devNavigationMenu.Builds); +}); + +Then('user will see {string}, {string} and {string} in Filter list', (el1, el2, el3: string) => { + cy.get(buildPO.filter) + .should('be.visible') + .click(); + cy.get(buildPO.filterList) + .should('contain', el1) + .and('contain', el2) + .and('contain', el3); +}); + +When('user clicks on {string} tab', (tab: string) => { + cy.byLegacyTestID(`horizontal-link-${tab}`) + .should('be.visible') + .click(); +}); + +When('user clicks on Event tab', () => { + cy.get(buildPO.eventTab) + .should('be.visible') + .click(); +}); + +When('user will see Shipwright Builds', () => { + cy.get(buildPO.dev.buildTab).should('be.visible'); +}); + +When('user clicks on {string} build', (build: string) => { + cy.byLegacyTestID(`${build}`) + .should('be.visible') + .click(); +}); + +When('user will see {string}, {string} and {string}', (el1, el2, el3: string) => { + cy.get(buildPO.pane) + .should('contain', el1) + .and('contain', el2) + .and('contain', el3); +}); + +Then('user will see events steaming', () => { + cy.get(buildPO.eventStream).should('be.visible'); +}); + +Given('user is at Shipwright Builds details page for build {string}', (buildName: string) => { + navigateTo(devNavigationMenu.Builds); + cy.get(buildPO.shipwrightBuild.shipwrightBuildsTab) + .should('be.visible') + .click(); + cy.byLegacyTestID(`${buildName}`) + .should('be.visible') + .click(); + cy.get('[aria-label="Breadcrumb"]').should('contain', 'Build details'); +}); + +When('user clicks on Filter', () => { + cy.get(buildPO.filter) + .should('be.visible') + .click(); +}); + +When( + 'user will see {string}, {string}, {string}, {string} and {string} options', + (el1, el2, el3, el4, el5: string) => { + cy.get(buildPO.filterList) + .should('contain', el1) + .and('contain', el2) + .and('contain', el3) + .and('contain', el4) + .and('contain', el5); + }, +); + +When('user clicks on build run {string}', (buildRun: string) => { + cy.byLegacyTestID(`${buildRun}`).click(); +}); + +Then('user will see {string} section', (section: string) => { + cy.get(`[data-test-section-heading="${section}"]`).should('be.visible'); +}); + +Then( + 'user will see {string}, {string} and {string} section in BuildRun details', + (el1, el2, el3: string) => { + cy.get(buildPO.pane) + .should('contain', el1) + .and('contain', el2) + .and('contain', el3); + }, +); + +Given('user is at Shipwright Builds run page {string}', (buildName: string) => { + navigateTo(devNavigationMenu.Builds); + cy.get(buildPO.shipwrightBuild.shipwrightBuildsTab) + .should('be.visible') + .click(); + cy.byLegacyTestID(`${buildName}`) + .should('be.visible') + .click(); + cy.get(buildPO.shipwrightBuild.shipwrightBuildRunsTab) + .should('be.visible') + .click(); +}); + +When('user has a failed build run', () => { + cy.exec(`oc apply -n ${Cypress.env('NAMESPACE')} -f testData/builds/shipwrightBuildRun.yaml`, { + failOnNonZeroExit: false, + }); + cy.byLegacyTestID('buildpack-nodejs-build-heroku-1') + .should('be.visible') + .click(); + cy.byLegacyTestID('breadcrumb-link-0') + .should('be.visible') + .click(); + cy.get(buildPO.filter) + .should('be.visible') + .click(); + cy.get(buildPO.failedFilter) + .should('be.visible') + .click(); + cy.get(resourceRow).should('be.visible'); +}); + +When('user clicks on Failed Status', () => { + cy.get(buildPO.shipwrightBuild.statusText) + .first() + .should('be.visible') + .click(); +}); + +Then('user will see pop up with error message', () => { + cy.get(buildPO.popup).should('be.visible'); +}); diff --git a/frontend/packages/dev-console/integration-tests/support/step-definitions/common/operators.ts b/frontend/packages/dev-console/integration-tests/support/step-definitions/common/operators.ts index 7b2984a5301..9570aaa6200 100644 --- a/frontend/packages/dev-console/integration-tests/support/step-definitions/common/operators.ts +++ b/frontend/packages/dev-console/integration-tests/support/step-definitions/common/operators.ts @@ -27,3 +27,7 @@ Given( Given('user has installed Quay Container Security Operator', () => { verifyAndInstallOperator(operators.QuayContainerSecurity); }); + +Given('user has installed Shipwright Operator', () => { + verifyAndInstallOperator(operators.ShipwrightOperator); +}); diff --git a/frontend/packages/dev-console/integration-tests/testData/builds/shipwrightBuild.yaml b/frontend/packages/dev-console/integration-tests/testData/builds/shipwrightBuild.yaml new file mode 100644 index 00000000000..b4aabd94719 --- /dev/null +++ b/frontend/packages/dev-console/integration-tests/testData/builds/shipwrightBuild.yaml @@ -0,0 +1,29 @@ +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildpack-nodejs-build-heroku +spec: + source: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: source-build + strategy: + name: buildpacks-v3-heroku + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/buildpack-nodejs-build-heroku +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildpack-nodejs-build-heroku-1 +spec: + buildRef: + name: buildpack-nodejs-build-heroku +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildpack-nodejs-build-heroku-2 +spec: + buildRef: + name: buildpack-nodejs-build-heroku diff --git a/frontend/packages/dev-console/integration-tests/testData/builds/shipwrightBuildRun.yaml b/frontend/packages/dev-console/integration-tests/testData/builds/shipwrightBuildRun.yaml new file mode 100644 index 00000000000..919bb011078 --- /dev/null +++ b/frontend/packages/dev-console/integration-tests/testData/builds/shipwrightBuildRun.yaml @@ -0,0 +1,14 @@ +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildpack-nodejs-buildrun-123 +spec: + buildSpec: + source: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: source-build + strategy: + kind: BuildStrategy + name: buildpacks-v3 + output: + image: image-registry.openshift-image-registry.svc:5000/christoph/buildpack-nodejs-build:latest diff --git a/frontend/packages/dev-console/integration-tests/testData/builds/shipwrightBuildStrategies.yaml b/frontend/packages/dev-console/integration-tests/testData/builds/shipwrightBuildStrategies.yaml new file mode 100644 index 00000000000..69d6bf2c365 --- /dev/null +++ b/frontend/packages/dev-console/integration-tests/testData/builds/shipwrightBuildStrategies.yaml @@ -0,0 +1,897 @@ +# Based on https://github.com/shipwright-io/build/releases/download/v0.9.0/sample-strategies.yaml +# +# - Changed ClusterBuildStrategy to BuildStrategy, add namespace `build-examples` +# - Removed all securityContext sections +# - Removed `prepare` (chown -R 1000:1000 /tekton/home) from +# buildpacks-v3, +# buildpacks-v3-heroku, +# buildkit +# ko +# - Removed `seccomp` annotation in `buildkit-build` +# + +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: buildah +spec: + buildSteps: + - name: build-and-push + image: quay.io/containers/buildah:v1.23.1 + workingDir: $(params.shp-source-root) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + # Parse parameters + context= + dockerfile= + image= + buildArgs=() + inBuildArgs=false + registriesBlock="" + inRegistriesBlock=false + registriesInsecure="" + inRegistriesInsecure=false + registriesSearch="" + inRegistriesSearch=false + tlsVerify=true + while [[ $# -gt 0 ]]; do + arg="$1" + shift + if [ "${arg}" == "--context" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + context="$1" + shift + elif [ "${arg}" == "--dockerfile" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + dockerfile="$1" + shift + elif [ "${arg}" == "--image" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + image="$1" + shift + elif [ "${arg}" == "--build-args" ]; then + inBuildArgs=true + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-block" ]; then + inRegistriesBlock=true + inBuildArgs=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-insecure" ]; then + inRegistriesInsecure=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-search" ]; then + inRegistriesSearch=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + elif [ "${inBuildArgs}" == "true" ]; then + buildArgs+=("--build-arg" "${arg}") + elif [ "${inRegistriesBlock}" == "true" ]; then + registriesBlock="${registriesBlock}'${arg}', " + elif [ "${inRegistriesInsecure}" == "true" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + # This assumes that the image is passed before the insecure registries which is fair in this context + if [[ ${image} == ${arg}/* ]]; then + tlsVerify=false + fi + elif [ "${inRegistriesSearch}" == "true" ]; then + registriesSearch="${registriesSearch}'${arg}', " + else + echo "Invalid usage" + exit 1 + fi + done + # Verify the existence of the context directory + if [ ! -d "${context}" ]; then + echo -e "The context directory '${context}' does not exist." + echo -n "ContextDirNotFound" > '$(results.shp-error-reason.path)' + echo -n "The context directory '${context}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + cd "${context}" + # Verify the existence of the Dockerfile + if [ ! -f "${dockerfile}" ]; then + echo -e "The Dockerfile '${dockerfile}' does not exist." + echo -n "DockerfileNotFound" > '$(results.shp-error-reason.path)' + echo -n "The Dockerfile '${dockerfile}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + echo "[INFO] Creating registries config file..." + if [ "${registriesSearch}" != "" ]; then + cat <>/tmp/registries.conf + [registries.search] + registries = [${registriesSearch::-2}] + EOF + fi + if [ "${registriesInsecure}" != "" ]; then + cat <>/tmp/registries.conf + [registries.insecure] + registries = [${registriesInsecure::-2}] + EOF + fi + if [ "${registriesBlock}" != "" ]; then + cat <>/tmp/registries.conf + [registries.block] + registries = [${registriesBlock::-2}] + EOF + fi + # Building the image + echo "[INFO] Building image ${image}" + buildah bud "${buildArgs[@]}" \ + --registries-conf=/tmp/registries.conf \ + --tag="${image}" \ + --file="${dockerfile}" \ + . + # Push the image + echo "[INFO] Pushing image ${image}" + buildah push \ + --digestfile='$(results.shp-image-digest.path)' \ + --tls-verify="${tlsVerify}" \ + "${image}" \ + "docker://${image}" + # That's the separator between the shell script and its args + - -- + - --context + - $(params.shp-source-context) + - --dockerfile + - $(build.dockerfile) + - --image + - $(params.shp-output-image) + - --build-args + - $(params.build-args[*]) + - --registries-block + - $(params.registries-block[*]) + - --registries-insecure + - $(params.registries-insecure[*]) + - --registries-search + - $(params.registries-search[*]) + resources: + limits: + cpu: "1" + memory: 2Gi + requests: + cpu: 250m + memory: 65Mi + parameters: + - name: build-args + description: "The values for the args in the Dockerfile. Values must be in the format KEY=VALUE." + type: array + defaults: [] + - name: registries-block + description: The registries that need to block pull access. + type: array + defaults: [] + - name: registries-insecure + description: The fully-qualified name of insecure registries. An insecure registry is one that does not have a valid SSL certificate or only supports HTTP. + type: array + defaults: [] + - name: registries-search + description: The registries for searching short name images such as `golang:latest`. + type: array + defaults: + - docker.io + - quay.io + +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: buildkit +spec: + parameters: + - name: build-args + description: "The values for the ARGs in the Dockerfile. Values must be in the format KEY=VALUE." + type: array + defaults: [] + - name: cache + description: "Configure BuildKit's cache usage. Allowed values are 'disabled' and 'registry'. The default is 'registry'." + type: string + default: registry + - name: insecure-registry + type: string + description: "Enables the push to an insecure registry" + default: "false" + - name: platforms + description: "Build the image for different platforms. By default, the image is built for the platform used by the FROM image. If that is present for multiple platforms, then it is built for the environment's platform." + type: array + defaults: [] + - name: secrets + description: "The secrets to pass to the build. Values must be in the format ID=FILE_CONTENT." + type: array + defaults: [] + buildSteps: + - name: build-and-push + image: moby/buildkit:nightly-rootless + imagePullPolicy: Always + workingDir: $(params.shp-source-root) + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: HOME + value: /tekton/home + # See https://github.com/moby/buildkit/blob/master/docs/rootless.md#about---oci-worker-no-process-sandbox for more information + - name: BUILDKITD_FLAGS + value: --oci-worker-no-process-sandbox + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_DOCKERFILE + value: $(params.DOCKERFILE) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + - name: PARAM_INSECURE_REGISTRY + value: $(params.insecure-registry) + - name: PARAM_CACHE + value: $(params.cache) + command: + - /bin/ash + args: + - -c + - | + set -euo pipefail + # Verify the existence of the context directory + if [ ! -d "${PARAM_SOURCE_CONTEXT}" ]; then + echo -e "The context directory '${PARAM_SOURCE_CONTEXT}' does not exist." + echo -n "ContextDirNotFound" > '$(results.shp-error-reason.path)' + echo -n "The context directory '${PARAM_SOURCE_CONTEXT}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + # Prepare the file arguments + DOCKERFILE_PATH="${PARAM_SOURCE_CONTEXT}/${PARAM_DOCKERFILE}" + DOCKERFILE_DIR="$(dirname "${DOCKERFILE_PATH}")" + DOCKERFILE_NAME="$(basename "${DOCKERFILE_PATH}")" + # Verify the existence of the Dockerfile + if [ ! -f "${DOCKERFILE_PATH}" ]; then + echo -e "The Dockerfile '${DOCKERFILE_PATH}' does not exist." + echo -n "DockerfileNotFound" > '$(results.shp-error-reason.path)' + echo -n "The Dockerfile '${DOCKERFILE_PATH}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + # We only have ash here and therefore no bash arrays to help add dynamic arguments (the build-args) to the build command. + echo "#!/bin/ash" > /tmp/run.sh + echo "set -euo pipefail" >> /tmp/run.sh + echo "buildctl-daemonless.sh \\" >> /tmp/run.sh + echo "build \\" >> /tmp/run.sh + echo "--progress=plain \\" >> /tmp/run.sh + echo "--frontend=dockerfile.v0 \\" >> /tmp/run.sh + echo "--opt=filename=\"${DOCKERFILE_NAME}\" \\" >> /tmp/run.sh + echo "--local=context=\"${PARAM_SOURCE_CONTEXT}\" \\" >> /tmp/run.sh + echo "--local=dockerfile=\"${DOCKERFILE_DIR}\" \\" >> /tmp/run.sh + echo "--output=type=image,name=\"${PARAM_OUTPUT_IMAGE}\",push=true,registry.insecure=\"${PARAM_INSECURE_REGISTRY}\" \\" >> /tmp/run.sh + if [ "${PARAM_CACHE}" == "registry" ]; then + echo "--export-cache=type=inline \\" >> /tmp/run.sh + echo "--import-cache=type=registry,ref=\"${PARAM_OUTPUT_IMAGE}\" \\" >> /tmp/run.sh + elif [ "${PARAM_CACHE}" == "disabled" ]; then + echo "--no-cache \\" >> /tmp/run.sh + else + echo -e "An invalid value for the parameter 'cache' has been provided: '${PARAM_CACHE}'. Allowed values are 'disabled' and 'registry'." + echo -n "InvalidParameterValue" > '$(results.shp-error-reason.path)' + echo -n "An invalid value for the parameter 'cache' has been provided: '${PARAM_CACHE}'. Allowed values are 'disabled' and 'registry'." > '$(results.shp-error-message.path)' + exit 1 + fi + stage="" + platforms="" + for a in "$@" + do + if [ "${a}" == "--build-args" ]; then + stage=build-args + elif [ "${a}" == "--platforms" ]; then + stage=platforms + elif [ "${a}" == "--secrets" ]; then + stage=secrets + elif [ "${stage}" == "build-args" ]; then + echo "--opt=\"build-arg:${a}\" \\" >> /tmp/run.sh + elif [ "${stage}" == "platforms" ]; then + if [ "${platforms}" == "" ]; then + platforms="${a}" + else + platforms="${platforms},${a}" + fi + elif [ "${stage}" == "secrets" ]; then + # Split ID=FILE_CONTENT into variables id and data + # using head because the data could be multiline + id="$(echo "${a}" | head -1 | sed 's/=.*//')" + # This is hacky, we remove the suffix ${id}= from all lines of the data. + # If the data would be multiple lines and a line would start with ${id}= + # then we would remove it. We could force users to give us the secret + # base64 encoded. But ultimately, the best solution might be if the user + # mounts the secret and just gives us the path here. + data="$(echo "${a}" | sed "s/^${id}=//")" + # Write the secret data into a temporary file, once we have volume support + # in the build strategy, we should use a memory based emptyDir for this. + echo -n "${data}" > "/tmp/secret_${id}" + # Add the secret argument + echo "--secret id=${id},src="/tmp/secret_${id}" \\" >> /tmp/run.sh + fi + done + if [ "${platforms}" != "" ]; then + echo "--opt=\"platform=${platforms}\" \\" >> /tmp/run.sh + fi + echo "--metadata-file /tmp/image-metadata.json" >> /tmp/run.sh + chmod +x /tmp/run.sh + /tmp/run.sh + # Store the image digest + grep containerimage.digest /tmp/image-metadata.json | sed -E 's/.*containerimage.digest":\s*"([^"]*).*/\1/' | tr -d '\n' > '$(results.shp-image-digest.path)' + # That's the separator between the shell script and its args + - -- + - --build-args + - $(params.build-args[*]) + - --platforms + - $(params.platforms[*]) + - --secrets + - $(params.secrets[*]) + +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: buildpacks-v3-heroku +spec: + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.4" + buildSteps: + - name: build-and-push + image: heroku/buildpacks:18 + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - "set -euo pipefail\n\necho \"> Processing environment variables...\"\nENV_DIR=\"/platform/env\"\n\nenvs=($(env))\n\n# Denying the creation of non required files from system environments.\n# The creation of a file named PATH (corresponding to PATH system environment)\n# caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world)\nblock_list=(\"PATH\" \"HOSTNAME\" \"PWD\" \"_\" \"SHLVL\" \"HOME\" \"\")\n\nfor env in \"${envs[@]}\"; do\n blocked=false\n\n IFS='=' read -r key value string <<< \"$env\"\n\n for str in \"${block_list[@]}\"; do\n if [[ \"$key\" == \"$str\" ]]; then\n blocked=true\n break\n fi\n done\n\n if [ \"$blocked\" == \"false\" ]; then\n path=\"${ENV_DIR}/${key}\"\n echo -n \"$value\" > \"$path\"\n fi\ndone\n\nLAYERS_DIR=/tmp/layers\nCACHE_DIR=/tmp/cache\n\nmkdir \"$CACHE_DIR\" \"$LAYERS_DIR\"\n\nfunction anounce_phase {\n printf \"===> %s\\n\" \"$1\" \n}\n\nanounce_phase \"DETECTING\"\n/cnb/lifecycle/detector -app=\"${PARAM_SOURCE_CONTEXT}\" -layers=\"$LAYERS_DIR\"\n\nanounce_phase \"ANALYZING\"\n/cnb/lifecycle/analyzer -layers=\"$LAYERS_DIR\" -cache-dir=\"$CACHE_DIR\" \"${PARAM_OUTPUT_IMAGE}\"\n\nanounce_phase \"RESTORING\"\n/cnb/lifecycle/restorer -cache-dir=\"$CACHE_DIR\"\n\nanounce_phase \"BUILDING\"\n/cnb/lifecycle/builder -app=\"${PARAM_SOURCE_CONTEXT}\" -layers=\"$LAYERS_DIR\"\n\nexporter_args=( -layers=\"$LAYERS_DIR\" -report=/tmp/report.toml -cache-dir=\"$CACHE_DIR\" -app=\"${PARAM_SOURCE_CONTEXT}\")\ngrep -q \"buildpack-default-process-type\" \"$LAYERS_DIR/config/metadata.toml\" || exporter_args+=( -process-type web ) \n\nanounce_phase \"EXPORTING\"\n/cnb/lifecycle/exporter \"${exporter_args[@]}\" \"${PARAM_OUTPUT_IMAGE}\"\n\n# Store the image digest\ngrep digest /tmp/report.toml | tr -d ' \\\"\\n' | sed s/digest=// > \"$(results.shp-image-digest.path)\"\n" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: buildpacks-v3 +spec: + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.4" + buildSteps: + - name: build-and-push + image: docker.io/paketobuildpacks/builder:full + imagePullPolicy: Always + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - "set -euo pipefail\n\necho \"> Processing environment variables...\"\nENV_DIR=\"/platform/env\"\n\nenvs=($(env))\n\n# Denying the creation of non required files from system environments.\n# The creation of a file named PATH (corresponding to PATH system environment)\n# caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world)\nblock_list=(\"PATH\" \"HOSTNAME\" \"PWD\" \"_\" \"SHLVL\" \"HOME\" \"\")\n\nfor env in \"${envs[@]}\"; do\n blocked=false\n\n IFS='=' read -r key value string <<< \"$env\"\n\n for str in \"${block_list[@]}\"; do\n if [[ \"$key\" == \"$str\" ]]; then\n blocked=true\n break\n fi\n done\n\n if [ \"$blocked\" == \"false\" ]; then\n path=\"${ENV_DIR}/${key}\"\n echo -n \"$value\" > \"$path\"\n fi\ndone\n\nLAYERS_DIR=/tmp/layers\nCACHE_DIR=/tmp/cache\n\nmkdir \"$CACHE_DIR\" \"$LAYERS_DIR\"\n\nfunction anounce_phase {\n printf \"===> %s\\n\" \"$1\" \n}\n\nanounce_phase \"DETECTING\"\n/cnb/lifecycle/detector -app=\"${PARAM_SOURCE_CONTEXT}\" -layers=\"$LAYERS_DIR\"\n\nanounce_phase \"ANALYZING\"\n/cnb/lifecycle/analyzer -layers=\"$LAYERS_DIR\" -cache-dir=\"$CACHE_DIR\" \"${PARAM_OUTPUT_IMAGE}\"\n\nanounce_phase \"RESTORING\"\n/cnb/lifecycle/restorer -cache-dir=\"$CACHE_DIR\"\n\nanounce_phase \"BUILDING\"\n/cnb/lifecycle/builder -app=\"${PARAM_SOURCE_CONTEXT}\" -layers=\"$LAYERS_DIR\"\n\nexporter_args=( -layers=\"$LAYERS_DIR\" -report=/tmp/report.toml -cache-dir=\"$CACHE_DIR\" -app=\"${PARAM_SOURCE_CONTEXT}\")\ngrep -q \"buildpack-default-process-type\" \"$LAYERS_DIR/config/metadata.toml\" || exporter_args+=( -process-type web ) \n\nanounce_phase \"EXPORTING\"\n/cnb/lifecycle/exporter \"${exporter_args[@]}\" \"${PARAM_OUTPUT_IMAGE}\"\n\n# Store the image digest\ngrep digest /tmp/report.toml | tr -d ' \\\"\\n' | sed s/digest=// > \"$(results.shp-image-digest.path)\"\n" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + +--- +# This Build Strategy will intentionally fail if the image has any +# critical CVEs. It will not be pushed into the destination registry +# if any critical vulnerabilities are found. +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: kaniko-trivy +spec: + buildSteps: + - name: kaniko-build + image: gcr.io/kaniko-project/executor:v1.8.1 + workingDir: $(params.shp-source-root) + env: + - name: HOME + value: /tekton/home + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --skip-tls-verify=true + - --dockerfile=$(build.dockerfile) + - --context=$(params.shp-source-context) + - --destination=$(params.shp-output-image) + - --oci-layout-path=/kaniko/oci-image-layout + - --snapshotMode=redo + - --no-push + - --tarPath + - /kaniko/tar-image/image.tar + volumeMounts: + - name: layout + mountPath: /kaniko/oci-image-layout + - name: tar + mountPath: /kaniko/tar-image + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + - name: trivy-scan + image: docker.io/aquasec/trivy:0.25.3 + volumeMounts: + - mountPath: /image/ + name: tar + command: + - trivy + args: + - image + - --exit-code=1 + - --severity=CRITICAL + - --input + - /image/image.tar + env: + - name: HOME + value: /tekton/home + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + - name: crane-push + image: gcr.io/go-containerregistry/crane:v0.8.0 + volumeMounts: + - mountPath: /image/ + name: tar + command: + - crane + args: + - push + - /image/image.tar + - $(params.shp-output-image) + env: + - name: HOME + value: /tekton/home + - name: results + image: registry.access.redhat.com/ubi8/ubi-minimal + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + # Store the image digest + grep digest /kaniko/oci-image-layout/index.json | sed -E 's/.*sha256([^"]*).*/sha256\1/' | tr -d '\n' > "$(results.shp-image-digest.path)" + # Store the image size + du -b -c /kaniko/oci-image-layout/blobs/sha256/* | tail -1 | sed 's/\s*total//' | tr -d '\n' > "$(results.shp-image-size.path)" + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + volumeMounts: + - name: layout + mountPath: /kaniko/oci-image-layout + +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: kaniko +spec: + buildSteps: + - name: build-and-push + image: gcr.io/kaniko-project/executor:v1.8.1 + workingDir: $(params.shp-source-root) + env: + - name: HOME + value: /tekton/home + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --skip-tls-verify=true + - --dockerfile=$(build.dockerfile) + - --context=$(params.shp-source-context) + - --destination=$(params.shp-output-image) + - --oci-layout-path=/kaniko/oci-image-layout + - --snapshotMode=redo + - --push-retry=3 + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + volumeMounts: + - name: layout + mountPath: /kaniko/oci-image-layout + - name: results + image: registry.access.redhat.com/ubi8/ubi-minimal + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + # Store the image digest + grep digest /kaniko/oci-image-layout/index.json | sed -E 's/.*sha256([^"]*).*/sha256\1/' | tr -d '\n' > "$(results.shp-image-digest.path)" + # Store the image size + du -b -c /kaniko/oci-image-layout/blobs/sha256/* | tail -1 | sed 's/\s*total//' | tr -d '\n' > "$(results.shp-image-size.path)" + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + volumeMounts: + - name: layout + mountPath: /kaniko/oci-image-layout + +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: ko +spec: + parameters: + - name: go-flags + description: "Value for the GOFLAGS environment variable." + default: "" + - name: go-version + description: "Version of Go, must match a tag from https://hub.docker.com/_/golang?tab=tags" + default: "1.17" + - name: ko-version + description: "Version of ko, must be either 'latest', or a release name from https://github.com/google/ko/releases" + default: latest + - name: package-directory + description: "The directory inside the context directory containing the main package." + default: "." + - name: target-platform + description: "Target platform to be built. For example: 'linux/arm64'. Multiple platforms can be provided separated by comma, for example: 'linux/arm64,linux/amd64'. The value 'all' will build all platforms supported by the base image. The value 'current' will build the platform on which the build runs." + default: current + buildSteps: + - name: build-and-push + image: golang:$(params.go-version) + imagePullPolicy: Always + workingDir: $(params.shp-source-root) + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: HOME + value: /tekton/home + - name: GOFLAGS + value: $(params.go-flags) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_TARGET_PLATFORM + value: $(params.target-platform) + - name: PARAM_PACKAGE_DIRECTORY + value: $(params.package-directory) + - name: PARAM_KO_VERSION + value: $(params.ko-version) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + # Parse image URL to extract repository and tag, must work with + # - a URL without a tag and a port: registry/image + # - a URL without a tag but a port: registry:port/image + # - a URL with a tag but without a port: registry/image:tag + # - a URL with both a tag and a port: registry:port/image:tag + REPO= + TAG= + IFS=':' read -ra PARTS <<< "${PARAM_OUTPUT_IMAGE}" + for PART in "${PARTS[@]}"; do + if [ "${REPO}" == "" ]; then + REPO="${PART}" + elif [[ "${PART}" == *"/"* ]]; then + REPO="${REPO}:${PART}" + elif [ "${TAG}" == "" ]; then + TAG="${PART}" + else + REPO="${REPO}:${TAG}" + TAG="${PART}" + fi + done + # Determine the ko version + KO_VERSION="${PARAM_KO_VERSION}" + if [ "${KO_VERSION}" == "latest" ]; then + KO_VERSION=$(curl --silent "https://api.github.com/repos/google/ko/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + fi + # Create one variable with v-suffix and one without as we need both for the download URL + if [[ ${KO_VERSION} = v* ]]; then + KO_VERSION_WITH_V=${KO_VERSION} + KO_VERSION_WITHOUT_V=${KO_VERSION:1} + else + KO_VERSION_WITH_V=v${KO_VERSION} + KO_VERSION_WITHOUT_V=${KO_VERSION} + fi + # Download ko to the temp directory + curl -f -s -L "https://github.com/google/ko/releases/download/${KO_VERSION_WITH_V}/ko_${KO_VERSION_WITHOUT_V}_$(uname)_$(uname -m | sed 's/aarch64/arm64/').tar.gz" | tar xzf - -C /tmp ko + # Determine the platform + PLATFORM="${PARAM_TARGET_PLATFORM}" + if [ "${PLATFORM}" == "current" ]; then + PLATFORM="$(uname | tr '[:upper:]' '[:lower:]')/$(uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/')" + fi + # Print version information + go version + echo "ko version $(/tmp/ko version)" + # Run ko + export GOROOT="$(go env GOROOT)" + export KO_DOCKER_REPO="${REPO}" + pushd "${PARAM_SOURCE_CONTEXT}" > /dev/null + if [ "${TAG}" == "" ]; then + /tmp/ko publish "${PARAM_PACKAGE_DIRECTORY}" --bare --oci-layout-path=/tmp/layout --platform="${PLATFORM}" + else + /tmp/ko publish "${PARAM_PACKAGE_DIRECTORY}" --bare --oci-layout-path=/tmp/layout --platform="${PLATFORM}" --tags="${TAG}" + fi + popd > /dev/null + # Store the image digest + grep digest /tmp/layout/index.json | sed -E 's/.*sha256([^"]*).*/sha256\1/' | tr -d '\n' > '$(results.shp-image-digest.path)' + # Store the image size + du -b -c /tmp/layout/blobs/sha256/* | tail -1 | sed 's/\s*total//' | tr -d '\n' > '$(results.shp-image-size.path)' + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: source-to-image-redhat +spec: + buildSteps: + - name: s2i-generate + image: registry.redhat.io/ocp-tools-43-tech-preview/source-to-image-rhel8:latest + workingDir: $(params.shp-source-root) + args: + - build + - $(params.shp-source-context) + - $(build.builder.image) + - $(params.shp-output-image) + - --as-dockerfile=/s2i/Dockerfile + volumeMounts: + - name: s2i + mountPath: /s2i + - name: buildah + image: quay.io/containers/buildah:v1.23.1 + workingDir: /s2i + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + # Parse parameters + image= + registriesBlock="" + inRegistriesBlock=false + registriesInsecure="" + inRegistriesInsecure=false + registriesSearch="" + inRegistriesSearch=false + tlsVerify=true + while [[ $# -gt 0 ]]; do + arg="$1" + shift + if [ "${arg}" == "--image" ]; then + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + image="$1" + shift + elif [ "${arg}" == "--registries-block" ]; then + inRegistriesBlock=true + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-insecure" ]; then + inRegistriesInsecure=true + inRegistriesBlock=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-search" ]; then + inRegistriesSearch=true + inRegistriesBlock=false + inRegistriesInsecure=false + elif [ "${inRegistriesBlock}" == "true" ]; then + registriesBlock="${registriesBlock}'${arg}', " + elif [ "${inRegistriesInsecure}" == "true" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + # This assumes that the image is passed before the insecure registries which is fair in this context + if [[ ${image} == ${arg}/* ]]; then + tlsVerify=false + fi + elif [ "${inRegistriesSearch}" == "true" ]; then + registriesSearch="${registriesSearch}'${arg}', " + else + echo "Invalid usage" + exit 1 + fi + done + echo "[INFO] Creating registries config file..." + if [ "${registriesSearch}" != "" ]; then + cat <>/tmp/registries.conf + [registries.search] + registries = [${registriesSearch::-2}] + EOF + fi + if [ "${registriesInsecure}" != "" ]; then + cat <>/tmp/registries.conf + [registries.insecure] + registries = [${registriesInsecure::-2}] + EOF + fi + if [ "${registriesBlock}" != "" ]; then + cat <>/tmp/registries.conf + [registries.block] + registries = [${registriesBlock::-2}] + EOF + fi + # Building the image + echo "[INFO] Building image ${image}" + buildah bud \ + --registries-conf=/tmp/registries.conf \ + --tag="${image}" + # Push the image + echo "[INFO] Pushing image ${image}" + buildah push \ + --digestfile='$(results.shp-image-digest.path)' \ + --tls-verify="${tlsVerify}" \ + "docker://${image}" + # That's the separator between the shell script and its args + - -- + - --image + - $(params.shp-output-image) + - --registries-block + - $(params.registries-block[*]) + - --registries-insecure + - $(params.registries-insecure[*]) + - --registries-search + - $(params.registries-search[*]) + volumeMounts: + - name: s2i + mountPath: /s2i + parameters: + - name: registries-block + description: The registries that need to block pull access. + type: array + defaults: [] + - name: registries-insecure + description: The fully-qualified name of insecure registries. An insecure registry is one that does not have a valid SSL certificate or only supports HTTP. + type: array + defaults: [] + - name: registries-search + description: The registries for searching short name images such as `golang:latest`. + type: array + defaults: + - docker.io + - quay.io + +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: source-to-image +spec: + buildSteps: + - command: + - /usr/local/bin/s2i + - build + - $(params.shp-source-context) + - $(build.builder.image) + - '--as-dockerfile' + - /gen-source/Dockerfile.gen + image: quay.io/openshift-pipeline/s2i:nightly + imagePullPolicy: Always + name: s2i-build-as-dockerfile + volumeMounts: + - mountPath: /gen-source + name: gen-source + workingDir: $(params.shp-source-root) + - args: + - '--skip-tls-verify=true' + - '--dockerfile=/gen-source/Dockerfile.gen' + - '--context=/gen-source' + - '--destination=$(params.shp-output-image)' + - '--oci-layout-path=/kaniko/oci-image-layout' + - '--snapshotMode=redo' + - '--push-retry=3' + command: + - /kaniko/executor + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: HOME + value: /tekton/home + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + image: gcr.io/kaniko-project/executor:v1.8.1 + name: build-and-push + volumeMounts: + - mountPath: /gen-source + name: gen-source + - name: layout + mountPath: /kaniko/oci-image-layout + workingDir: /gen-source + - name: results + image: registry.access.redhat.com/ubi8/ubi-minimal + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + # Store the image digest + grep digest /kaniko/oci-image-layout/index.json | sed -E 's/.*sha256([^"]*).*/sha256\1/' | tr -d '\n' > "$(results.shp-image-digest.path)" + # Store the image size + du -b -c /kaniko/oci-image-layout/blobs/sha256/* | tail -1 | sed 's/\s*total//' | tr -d '\n' > "$(results.shp-image-size.path)" + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + volumeMounts: + - name: layout + mountPath: /kaniko/oci-image-layout diff --git a/frontend/packages/shipwright-plugin/src/components/buildrun-status/BuildRunStatus.tsx b/frontend/packages/shipwright-plugin/src/components/buildrun-status/BuildRunStatus.tsx index be63f949ac4..bd59b2556eb 100644 --- a/frontend/packages/shipwright-plugin/src/components/buildrun-status/BuildRunStatus.tsx +++ b/frontend/packages/shipwright-plugin/src/components/buildrun-status/BuildRunStatus.tsx @@ -66,7 +66,7 @@ const BuildRunStatus: React.FC<{ buildRun: BuildRun }> = ({ buildRun }) => { {status === ComputedBuildRunStatus.FAILED ? ( <> -
{failedCondition.reason}
+
{failedCondition.reason}
{failedCondition.message} ) : null}