Skip to content

SimonGolms/ods-quickstarter-fe-ionic-react-vite-playwright

Repository files navigation

OpenDevStack - Quickstarter - Frontend Ionic React Vite Playwright

An advanced OpenDevStack Frontend Quickstarter to build mobile and desktop apps with the ionic framework, react, vite and playwright.

Version License: Apache-2.0 Maintenance Conventional Commits Prerequisite Npm Prerequisite Node

Features ✨

  • Ionic/React with Typescript for building cross-platform native and web app
  • Single-Sign-On (SSO) for user authentication and authorization with Azure Active Directory
  • OpenDevStack (ODS) CI/CD configuration out of the box with the basic setup for Docker (incl. injecting Runtime Variables), Jenkins (incl. feature environments, release-manager rollout) and OpenShift (managed with Helm)
    • Ionic Appflow (coming soon)
  • Setup for Vite, Playwright, ESlint, Stylelint, Prettier, commitlint, Husky (git hooks) and semantic versioning for a better developer experience

Provision Quickstarter πŸš€

For an official ODS Quickstarter, the provisioning app takes care of the provisioning in combination with the Jenkinsfile in the associated Quickstarter template. However, since this is an extended Quickstarter, which is developed independently and decoupled from ODS, the necessary steps of the provisioning app and Jenkins itself must be performed, which are covered in this section.

Prerequisites

To provision this Quickstarter, you need a deployed ODS project with the corresponding *-cd, *-dev and *-test projects in the OpenShift 4 dev cluster, the *-prod project in the OpenShift 4 prod cluster and the associated Bitbucket project.

Setup Quickstarter

1. Get Source Code

  • Option 1 (recommended): Clone the repository

    git clone https://github.com/SimonGolms/ods-quickstarter-fe-ionic-react-vite-playwright.git
    cd ods-quickstarter-fe-ionic-react-vite-playwright
  • Option 2: Download the repository

    curl --location --remote-name https://github.com/SimonGolms/ods-quickstarter-fe-ionic-react-vite-playwright/archive/refs/heads/main.tar.gz && \
    tar -xvzf main.tar.gz && \
    rm main.tar.gz
    cd ods-quickstarter-fe-ionic-react-vite-playwright-main

2. Set Project Id

To make the Quickstarter available in your project, the corresponding project id is required. With the following command all files are checked. The placeholder PROJECTID is searched and replaced by the actual project id.

Replace YOUR_PROJECT_ID with your project id, e.g. foo

# IMPORTANT: Keep your project id in lowercase.
find . -type f -exec sed --expression 's/PROJECTID/YOUR_PROJECT_ID/g' --in-place {} +

πŸ›‘ IMPORTANT: This and the other commands also replace the placeholders in the other sections of the documentation. It is therefore recommended to continue with the README in the downloaded source code. Otherwise, please be aware that you have to replace the placeholder PROJECTID with your project id for each further command.

3. Set Component Id

Replace YOUR_COMPONENT_ID with your component id, e.g. app, frontend, etc.

# IMPORTANT: Keep your component id in lowercase.
find . -type f -exec sed --expression 's/COMPONENTID/YOUR_COMPONENT_ID/g' --in-place {} +

4. Set OpenShift dev domain URLs

Replace YOUR_OPENSHIFT_DOMAIN_DEV with your OpenShift 4 Dev Cluster Domain, e.g. dev.ocp.company.com

How do I find out the YOUR_OPENSHIFT_DOMAIN_DEV value?

Go to your *-cd project of your OpenShift 4 Dev Cluster in the browser and look at the URL properly. Extract the YOUR_OPENSHIFT_DOMAIN_DEV as follows:

https://console-openshift-console.apps.dev.ocp.company.com/topology/ns/PROJECTID-cd ◄── Your url

https://console-openshift-console.apps.   dev.ocp.company.com   /topology/ns/PROJECTID-cd
                  β–²                                 β–²                     β–²
                  β”‚                                 β”‚                     └─── Pathname
                  β”‚                                 └── YOUR_OPENSHIFT_DOMAIN_DEV
                  └─ Application Sub Domain
find . -type f -exec sed --expression 's/OPENSHIFT_DOMAIN_DEV/YOUR_OPENSHIFT_DOMAIN_DEV/g' --in-place {} +

5. Set OpenShift prod domain URLs

Replace YOUR_OPENSHIFT_DOMAIN_PROD with your OpenShift 4 Dev Cluster Domain, e.g. prod.ocp.company.com

How do I find out the YOUR_OPENSHIFT_DOMAIN_PROD value?

Go to your *-prod project of your OpenShift 4 Dev Cluster in the browser and look at the URL properly. Extract the YOUR_OPENSHIFT_DOMAIN_PROD as follows:

https://console-openshift-console.apps.dev.ocp.company.com/topology/ns/PROJECTID-cd ◄── Your url

https://console-openshift-console.apps.   dev.ocp.company.com   /topology/ns/PROJECTID-cd
                  β–²                                 β–²                     β–²
                  β”‚                                 β”‚                     └─── Pathname
                  β”‚                                 └── YOUR_OPENSHIFT_DOMAIN_PROD
                  └─ Application Sub Domain
find . -type f -exec sed --expression 's/OPENSHIFT_DOMAIN_PROD/YOUR_OPENSHIFT_DOMAIN_PROD/g' --in-place {} +

6. Set BitBucket domain URL

Replace YOUR_BITBUCKET_DOMAIN with your BitBucket Domain, e.g. bitbucket.company.com

How do I find out the YOUR_BITBUCKET_DOMAIN value?

Go to your BitBucket project in the browser and look at the URL properly. Extract the YOUR_BITBUCKET_DOMAIN as follows:

https://bitbucket.company.com/projects/PROJECTID ◄── Your url

https://   bitbucket.company.com   /projects/PROJECTID
  β–²                β–²                     β–²
  β”‚                β”‚                     └─── Pathname
  β”‚                └── YOUR_BITBUCKET_DOMAIN
  └─ Protocol
find . -type f -exec sed --expression 's/BITBUCKET_DOMAIN/YOUR_BITBUCKET_DOMAIN/g' --in-place {} +

7. Remove template resources

rm -rf .git .github CHANGELOG.md

8. Install helm cli

Helm is a package manager for Kubernetes that configures and deploys applications and services on a Kubernetes/OpenShift cluster. Think of it like apt/yum/homebrew for Kubernetes. It uses Helm charts to simplify the development and deployment process.

helm will be used later in the pre-commit git hook for linting the application Helm charts.

# Install helm cli
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# Verify successfully installed helm version
helm version

More Information: https://helm.sh/docs/intro/install/

9. Install oc cli

With the OpenShift command-line interface (CLI), the oc command, you can create applications and manage OpenShift Container Platform projects from a terminal.

oc will be used by helm and for further configuration and housekeeping tasks.

To be compatible with the latest OpenShift Container Platform (OCP) version, the binary is downloaded and installed from the associated OpenShift Container Platform.

# Install oc cli
curl -O https://downloads-openshift-console.apps.OPENSHIFT_DOMAIN_DEV/amd64/linux/oc.tar && \
tar -xvf oc.tar && rm oc.tar && \
sudo mv oc /usr/local/bin/

# Verify successfully installed oc version
oc version

More Information: https://docs.openshift.com/container-platform/4.9/cli_reference/openshift_cli/getting-started-cli.html

10. Setup Bitbucket Code Repository

  1. Create BitBucket Repository

    • Replace USER@COMPANY.COM with an authorized (administrative) user with access to the Bitbucket project
    # For security reasons (e.g. terminal history) --user 'USERNAME:PASSWORD' should be avoided.
    # Instead, a prompt will show up for the password if --user 'USERNAME' is used!
    curl --data '{"defaultBranch":"master","description":"πŸ“± Repo of COMPONENTID from PROJECTID that is build with ionic and react","name":"PROJECTID-COMPONENTID"}' \
      --header "Content-Type: application/json" \
      --request POST \
      --url https://BITBUCKET_DOMAIN/rest/api/1.0/projects/PROJECTID/repos/ \
      --user USER@COMPANY.COM
  2. Get trigger secret from the webhook proxy

    # Login to OpenShift dev instance
    oc login --server=https://api.OPENSHIFT_DOMAIN_DEV:6443 --token=123...456
    
    # Get trigger secret 'webhook-proxy' in plaintext
    oc get secret webhook-proxy --namespace PROJECTID-cd --output jsonpath='{.data.trigger-secret}' | base64 -d | xargs
  3. Create Webhook

    • Replace TRIGGER_SECRET with the obtained trigger secret from previous step.
    • Replace USER@COMPANY.COM with an authorized (administrative) user with access to the Bitbucket project
    # For security reasons (e.g. terminal history) --user 'USERNAME:PASSWORD' should be avoided.
    # Instead, a prompt will show up for the password if --user 'USERNAME' is used!
    curl --data '{"active":true,"configuration":{},"events":["pr:merged","repo:refs_changed","pr:declined","pr:deleted"],"name":"Jenkins","url":"https://webhook-proxy-PROJECTID-cd.apps.OPENSHIFT_DOMAIN_DEV?trigger_secret=TRIGGER_SECRET"}' \
      --header "Content-Type: application/json" \
      --request POST \
      --url https://BITBUCKET_DOMAIN/rest/api/1.0/projects/PROJECTID/repos/PROJECTID-COMPONENTID/webhooks \
      --user USER@COMPANY.COM
  4. Publish to Bitbucket Code Repository

    # Requires git v2.31.1
    git init --initial-branch=master
    git add --all
    git commit -m "chore: initial version"
    git remote add origin https://BITBUCKET_DOMAIN/scm/PROJECTID/PROJECTID-COMPONENTID.git
    # Before you push your first commit, make sure that no credentials are in the README as a result of the previous steps.
    # You might also delete unnecessary content in this context, like the 'Provision Quickstarter' section of this README.
    git push -u origin HEAD:master

Verify successfully provision

If the provisioning was successful, the previous push of the first commit should have triggered the first build process in Jenkins in the meantime, which can be viewed under the following link: https://jenkins-PROJECTID-cd.apps.OPENSHIFT_DOMAIN_DEV/job/PROJECTID-cd/job/PROJECTID-cd-COMPONENTID-master/

Feature Environment

A new feature environment is created by the associated git branch name, e.g. feature/next.

# Creates and switch to new branch from the current branch
git checkout -b feature/next

# Add empty commit in case the previous commit includes '[skip ci]'
git commit -m "chore: create feature-next environment" --allow-empty

# Push the new branch to the remote repository
git push -u origin feature/next

A new Jenkins build should have been created and can be followed under the following link: https://jenkins-PROJECTID-cd.apps.OPENSHIFT_DOMAIN_DEV/job/PROJECTID-cd/job/PROJECTID-cd-COMPONENTID-feature-next/

Assuming the Jenkins build has been successfully completed, the application should have been created in the OpenShift 4 project PROJECTID-dev as a new HelmRelease resource and should be accessible under the following link: https://PROJECTID-COMPONENTID-feature-next.apps.OPENSHIFT_DOMAIN_DEV

Release to dev, test and prod

  1. Update your metadata.yml in your release manager repository

    # Example metadata.yml
    id: PROJECTID
    name: Project PROJECTID
    description: Description of PROJECTID
    
    environments:
      prod:
        apiUrl: api.OPENSHIFT_DOMAIN_PROD:6443
        credentialsId: PROJECTID-cd-PROJECTID-prod
    
    repositories:
      - id: COMPONENTID
        branch: master
        url: https://bitbucket.biscrum.com/scm/PROJECTID/PROJECTID-COMPONENTID.git
    
    services:
      bitbucket:
        credentials:
          id: PROJECTID-cd-cd-user-with-password
      # jira:
      #   credentials:
      #     id: PROJECTID-cd-cd-user-with-password
      nexus:
        repository:
          name: leva-documentation
  2. Go to the Jenkins build of the release manager and start a new build process in the dev environment. Assuming the release has been successfully completed, the application should have been created in the OpenShift 4 project PROJECTID-dev as a new HelmRelease resource and should be accessible under the following link: https://PROJECTID-COMPONENTID-dev.apps.OPENSHIFT_DOMAIN_DEV

  3. Before you can deploy a release into qa/test environment, you need to merge the release branch into your master branch to pass the checks in the Jenkins shared library stage odsOrchestrationPipeline, see comment in metadata.yml for more details:

    # Switch to master branch
    git checkout master
    
    # Merge the remote release branch into master without opening a text editor and accept the auto-generated message
    git merge origin/release/<VERSION> --no-edit
    
    # Push the changes to the remote repository
    git push
  4. Go to the Jenkins build of the release manager and start a new build process in the qa/test environment. Assuming the release has been successfully completed, the application should have been created in the OpenShift 4 project PROJECTID-test as a new HelmRelease resource and should be accessible under the following link: https://PROJECTID-COMPONENTID-test.apps.OPENSHIFT_DOMAIN_DEV

  5. Go to the Jenkins build of the release manager and start a new build process in the prod environment. Assuming the release has been successfully completed, the application should have been created in the OpenShift 4 project PROJECTID-prod as a new HelmRelease resource and should be accessible under the following link: https://PROJECTID-COMPONENTID.apps.OPENSHIFT_DOMAIN_DEV


Technology Stack πŸ’»

Programming Language

TypeScript JavaScript HTML CSS3 npm Node.js Markdown

Frameworks and libraries

Ionic React React Router Redux Toolkit RTK Query Azure msal-react

Testing:

Playwright

Tracking:

N/A

Linter:

ESLint Stylelint Prettier Commitlint

Compiler:

vitejs

CI/CD

OpenDevStack Jenkins Helm Semantic Release Husky

Hosting

RedHat OpenShift v4.11 Docker Nginx

Dev Environment

WSL2

IDEs/Editors:

Visual Studio Code

Version Control

Git Bitbucket

Social

MS Teams


Prerequisites ☝️

  1. Azure App Registration

    Make sure you have an existing Azure App registry that has a single-page application (SPA) redirect to http://localhost/.

    Ideally you have one Azure App registry per environment (dev/test/prod) with at least the following SPA redirects:

    • Dev: http://localhost/, https://PROJECTID-COMPONENTID-dev.apps.OPENSHIFT_DOMAIN_DEV
    • Test: http://localhost/, https://PROJECTID-COMPONENTID-test.apps.OPENSHIFT_DOMAIN_DEV
    • Prod: http://localhost/, https://PROJECTID-COMPONENTID.apps.OPENSHIFT_DOMAIN_PROD

    Update the following entries with the Application (client) ID and Directory (tenant) ID from the corresponding app registry environment

    1. Replace YOUR_CLIENT_ID_DEV with the Application (client) ID from your app registration for the dev environment

      find \( -wholename "./.env" -or -wholename "./chart/values.dev.yaml" -or -wholename "./Jenkinsfile" \) -exec sed --expression 's/11111111-2222-3333-4444-555555555dev/YOUR_CLIENT_ID_DEV/g' --in-place {} +
    2. Replace YOUR_CLIENT_ID_TEST with the Application (client) ID from your app registration for the test environment

      find -wholename "./chart/values.test.yaml" -exec sed --expression 's/11111111-2222-3333-4444-55555555test/YOUR_CLIENT_ID_TEST/g' --in-place {} +
    3. Replace YOUR_CLIENT_ID_PROD with the Application (client) ID from your app registration for the prod environment

      find -wholename "./chart/values.prod.yaml" -exec sed --expression 's/11111111-2222-3333-4444-55555555prod/YOUR_CLIENT_ID_PROD/g' --in-place {} +
    4. Replace YOUR_TENANT_ID with the Directory (tenant) ID from your app registration, which is basically the same for per environment (dev/test/prod)

      find \( -wholename "./.env" -or -wholename "./chart/values.*.yaml" -or -wholename "./Jenkinsfile" \) -exec sed --expression 's/common/YOUR_TENANT_ID/g' --in-place {} +

More information: https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-spa-app-registration

Local Development πŸ‘¨β€πŸ’»

Requirements

  • Helm v3+
  • Node.js v16+
  • NPM v8+
  • oc v4.9+

Using NVM

# Install latest LTS Version (v16+) with the latest npm version (v8+)
nvm install --lts --latest-npm

Set Environment Variables

Create appropriate .env file from .env.template.

cp .env.template .env

Ask your colleagues which values are currently necessary!

Install Dependencies

npm install

Start Development Server

npm run start

Starts the development server and makes your application accessible at localhost:8100. Changes in the application code will be hot-reloaded.

Create Production Build (Web)

npm run build

The app is built for optimal performance: assets are minified and served gzipped.

Run tests

npm run test

Docker

Create Docker Image

npm run build
mv build docker
docker build -t PROJECTID-COMPONENTID -f docker/Dockerfile docker

In case the command RUN apk update && apk upgrade cannot be executed (e.g. working behind a proxy), uncomment it for the moment.

Start Docker Image

docker run -p 8080:8080 --env-file .env PROJECTID-COMPONENTID

Starts the nginx server and makes your application accessible at localhost:8080.

Continuous Integration/Continuous Delivery (CI/CD) ♾️

This CI/CD setup has been developed for the 'trunk-based development' approach.

[...] Trunk-based development is a version control management practice where developers merge small, frequent updates to a core β€œtrunk” or main branch. [...] Trunk-based development is far more simplified since it focuses on the main branch as the source of fixes and releases. In trunk-based development the main branch is assumed to always be stable, without issues, and ready to deploy [...]. - https://www.atlassian.com/continuous-delivery/continuous-integration/trunk-based-development

Master Branch

The master branch is your only real source-of-true πŸ“œ and should always reflect the state as found in all three environments.

It is recommended not to merge any changes into the master-branch before a new release is triggered. Otherwise there is the risk of not being able to perform a hotfix immediately. The only solution remains a corresponding Git Strategy to restore the old state, import the necessary hotfix changes, release and then add the reset changes again.

With each commit, the source code in the master branch is checked for its releasability and tagged at the end with a new semantic version based on the git commit history.

%% If the Mermaid Diagram is not rendered (as is the case on BitBucket), it can be viewed at https://mermaid.live/
flowchart TB
    subgraph openshift-dev["OpenShift (DEV)"]
        subgraph ods
            subgraph sonarqube["SonarQube"]
                direction TB
                ods-DC-sonarqube["sonarqube (DeploymentConfig)"]:::classDeploymentConfig <-. Port 9000 .-> ods-S-sonarqube["sonarqube (Service)"]:::classService <-. Port 9000 .-> ods-RT-sonarqube["sonarqube (Route)\nhttps://sonarqube-ods.apps.OPENSHIFT_DOMAIN_DEV"]:::classRoute
            end
        end
        subgraph aqua
            aqua-aqua["Aqua Container Security"]
        end
        subgraph PROJECTID-cd
            subgraph webhook-proxy
                direction TB
                cd-DC-webhook-proxy["webhook-proxy (DeploymentConfig)"]:::classDeploymentConfig <-. Port 8080 .-> cd-S-webhook-proxy["webhook-proxy (Service)"]:::classService <-. Port 8080 .-> cd-RT-webhook-proxy["webhook-proxy (Route)\nhttps://webhook-proxy-PROJECTID-cd.apps.OPENSHIFT_DOMAIN_DEV"]:::classRoute
            end
            subgraph Jenkins
                subgraph Jenkinsfile
                    stageInitialize-->stageInstallDependency-->stageVersioning-->stageWorkaroundFindOpenShiftImageOrElse --> stageAnalyzeCode-->odsComponentStageScanWithSonar-->stageBuild-->stageDeploy-->odsComponentStageBuildOpenShiftImage-->stageWorkaroundUnitTest-->stageWorkaroundRolloutDeployment-->stageRelease
                end
            end
            subgraph cd-IS-PROJECTID-COMPONENTID-master["PROJECTID-COMPONENTID-master (Image Stream)"]
                cd-IST-PROJECTID-COMPONENTID-master["PROJECTID-COMPONENTID-master:v1.4.2"]:::classImageStreamTag
            end
        end
    end
    subgraph BitBucket
        subgraph bb-project-PROJECTID["PROJECTID (Project)"]
            subgraph bb-project-PROJECTID-COMPONENTID["PROJECTID-COMPONENTID (Repo)"]
                bb-project-PROJECTID-COMPONENTID-branch-master["master (Branch)"]
            end
        end
    end


aqua-aqua -- scan --> cd-IST-PROJECTID-COMPONENTID-master
bb-project-PROJECTID-COMPONENTID -- trigger --> webhook-proxy -- trigger --> Jenkins
bb-project-PROJECTID-COMPONENTID-branch-master -- pull --> Jenkinsfile
odsComponentStageBuildOpenShiftImage -- push --> cd-IST-PROJECTID-COMPONENTID-master
odsComponentStageBuildOpenShiftImage -. trigger .-> aqua-aqua -. result .-> odsComponentStageBuildOpenShiftImage
odsComponentStageScanWithSonar -. trigger .-> sonarqube -. result .-> odsComponentStageScanWithSonar
stageRelease -- "push (v1.4.2)" --> bb-project-PROJECTID-COMPONENTID-branch-master

%% stlyes
classDef classBitBucket fill:#2684FF22,stroke:#2684FF,stroke-width:4px
classDef classBitBucketProject fill:#2684FF22,stroke:#2684FF
classDef classBuildConfig fill:#00408022,stroke:#004080
classDef classDeployment fill:#00408022,stroke:#004080
classDef classDeploymentConfig fill:#00408022,stroke:#004080
classDef classHelmRelease fill:#2b9af322,stroke:#2b9af3
classDef classImageStream fill:#2b9af322,stroke:#2b9af3
classDef classImageStreamTag fill:#2b9af322,stroke:#2b9af3
classDef classOcpProject fill:#ffffff00,stroke:#f00,stroke-width:2px
classDef classOcpResource fill:#ffffff00,stroke:#06c,stroke-width:2px
classDef classOpenShift fill:#ffffff00,stroke:#f00,stroke-width:4px
classDef classRoute fill:#2b9af322,stroke:#2b9af3
classDef classService fill:#6ca10022,stroke:#6ca100

class BitBucket classBitBucket
class bb-project-PROJECTID,bb-project-PROJECTID-COMPONENTID classBitBucketProject
class cd-IS-PROJECTID-COMPONENTID-master classImageStream
class aqua,ods,PROJECTID-cd,PROJECTID-dev classOcpProject
class aqua-aqua,Jenkins,Jenkinsfile,sonarqube,webhook-proxy classOcpResource
class openshift-dev classOpenShift

Feature Environments

With each new feature/* branch created, a new environment is created in the OpenShift Project PROJECTID-cd. Different stages are processed in the Jenkinsfile and finally rolled out and managed via Helm.

Please be aware that a new route (e.g. https://PROJECTID-COMPONENTID-feature-next.apps.OPENSHIFT_DOMAIN_DEV) is created for each new feature environment. If this is required for the SSO login, it must be specified as a new valid redirect URL in the app registration.

%% If the Mermaid Diagram is not rendered (as is the case on BitBucket), it can be viewed at https://mermaid.live/
flowchart TB
    subgraph openshift-dev["OpenShift (DEV)"]
        subgraph ods
            subgraph sonarqube["SonarQube"]
                direction TB
                ods-DC-sonarqube["sonarqube (DeploymentConfig)"]:::classDeploymentConfig <-. Port 9000 .-> ods-S-sonarqube["sonarqube (Service)"]:::classService <-. Port 9000 .-> ods-RT-sonarqube["sonarqube (Route)\nhttps://sonarqube-ods.apps.OPENSHIFT_DOMAIN_DEV"]:::classRoute
            end
        end
        subgraph PROJECTID-cd
            subgraph webhook-proxy
                direction TB
                cd-DC-webhook-proxy["webhook-proxy (DeploymentConfig)"]:::classDeploymentConfig <-. Port 8080 .-> cd-S-webhook-proxy["webhook-proxy (Service)"]:::classService <-. Port 8080 .-> cd-RT-webhook-proxy["webhook-proxy (Route)\nhttps://webhook-proxy-PROJECTID-cd.apps.OPENSHIFT_DOMAIN_DEV"]:::classRoute
            end
            subgraph Jenkins
                subgraph Jenkinsfile
                    stageInitialize-->stageInstallDependency-->stageVersioning-->stageWorkaroundFindOpenShiftImageOrElse -->|orElse| stageAnalyzeCode-->odsComponentStageScanWithSonar-->stageBuild-->stageDeploy-->odsComponentStageBuildOpenShiftImage-->stageWorkaroundUnitTest-->stageWorkaroundRolloutDeployment-->stageRelease
                end
            end
            subgraph cd-IS-PROJECTID-COMPONENTID-feature-next["PROJECTID-COMPONENTID-feature-next (Image Stream)"]
                cd-IST-PROJECTID-COMPONENTID-feature-next["PROJECTID-COMPONENTID-feature-next:hash"]:::classImageStreamTag
            end
        end
        subgraph PROJECTID-dev
            subgraph dev-HR-PROJECTID-COMPONENTID-feature-next["PROJECTID-COMPONENTID-feature-next (Helm Release)"]
                dev-D-COMPONENTID["COMPONENTID (Deployment)"]:::classDeployment <-. Port 8080 .-> dev-S-COMPONENTID["COMPONENTID (Service)"]:::classService <-. Port 8080 .-> dev-RT-COMPONENTID["COMPONENTID (Route)\nhttps://PROJECTID-COMPONENTID-feature-next.apps.OPENSHIFT_DOMAIN_DEV"]:::classRoute
            end
        end
    end
    subgraph bitbucket["BitBucket"]
        subgraph bitbucket-PROJECTID["PROJECTID (Project)"]
            subgraph bitbucket-PROJECTID-COMPONENTID["PROJECTID-COMPONENTID (Repo)"]
                bitbucket-PROJECTID-COMPONENTID-branch-feature-next["feature-next (Branch)"]
            end
        end
    end

bitbucket-PROJECTID-COMPONENTID -- trigger --> webhook-proxy -- trigger --> Jenkins
bitbucket-PROJECTID-COMPONENTID-branch-feature-next -- pull --> Jenkinsfile
cd-IST-PROJECTID-COMPONENTID-feature-next --> dev-D-COMPONENTID
odsComponentStageBuildOpenShiftImage -- push --> cd-IST-PROJECTID-COMPONENTID-feature-next
odsComponentStageScanWithSonar <-.-> sonarqube
stageWorkaroundRolloutDeployment -- stageRolloutWithHelm --> dev-HR-PROJECTID-COMPONENTID-feature-next

%% stlyes
classDef classBitBucket fill:#2684FF22,stroke:#2684FF,stroke-width:4px
classDef classBitBucketProject fill:#2684FF22,stroke:#2684FF
classDef classBuildConfig fill:#00408022,stroke:#004080
classDef classDeployment fill:#00408022,stroke:#004080
classDef classDeploymentConfig fill:#00408022,stroke:#004080
classDef classHelmRelease fill:#2b9af322,stroke:#2b9af3
classDef classImageStream fill:#2b9af322,stroke:#2b9af3
classDef classImageStreamTag fill:#2b9af322,stroke:#2b9af3
classDef classOcpProject fill:#ffffff00,stroke:#f00,stroke-width:2px
classDef classOcpResource fill:#ffffff00,stroke:#06c,stroke-width:2px
classDef classOpenShift fill:#ffffff00,stroke:#f00,stroke-width:4px
classDef classRoute fill:#2b9af322,stroke:#2b9af3
classDef classService fill:#6ca10022,stroke:#6ca100

class BitBucket classBitBucket
class bitbucket-PROJECTID,bitbucket-PROJECTID-COMPONENTID classBitBucketProject
class dev-HR-PROJECTID-COMPONENTID-feature-next classHelmRelease
class cd-IS-PROJECTID-COMPONENTID-feature-next classImageStream
class ods,PROJECTID-cd,PROJECTID-dev classOcpProject
class Jenkins,Jenkinsfile,sonarqube,webhook-proxy classOcpResource
class openshift-dev classOpenShift

Release Manager

Release to dev environment

%% If the Mermaid Diagram is not rendered (as is the case on BitBucket), it can be viewed at https://mermaid.live/
flowchart TB
    subgraph openshift-dev["OpenShift (DEV)"]

        subgraph PROJECTID-cd
            subgraph jenkins["Jenkins"]
                subgraph jenkinsfile-PROJECTID-COMPONENTID["Jenkinsfile (PROJECTID-COMPONENTID)"]
                    stageInitialize-->stageInstallDependency-->stageVersioning-->stageWorkaroundFindOpenShiftImageOrElse --> stageAnalyzeCode-->odsComponentStageScanWithSonar-->stageBuild-->stageDeploy-->odsComponentStageBuildOpenShiftImage-->stageWorkaroundUnitTest-->stageWorkaroundRolloutDeployment-->stageRelease
                end
                build-with-parameters("<strong>Build with Parameters</strong>\nenvironment: dev\nversion: 20220518.001"):::classManualTask
                subgraph jenkinsfile-releasemanager["Jenkinsfile (Release Manager)"]
                    InitStage --> BuildStage --> DeployStage --> TestStage --> ReleaseStage --> FinalizeStage
                end
            end
            subgraph cd-IS-COMPONENTID["COMPONENTID (Image Stream)"]
                cd-IST-COMPONENTID["COMPONENTID:20220518.001"]:::classImageStreamTag
            end
        end
        subgraph ods
            subgraph sonarqube["SonarQube"]
                direction TB
                ods-DC-sonarqube["sonarqube (DeploymentConfig)"]:::classDeploymentConfig <-. Port 9000 .-> ods-S-sonarqube["sonarqube (Service)"]:::classService <-. Port 9000 .-> ods-RT-sonarqube["sonarqube (Route)\nhttps://sonarqube-ods.apps.OPENSHIFT_DOMAIN_DEV"]:::classRoute
            end
        end
        subgraph aqua
            aqua-aqua["Aqua Container Security"]
        end
        subgraph PROJECTID-dev
            subgraph dev-HR-COMPONENTID["COMPONENTID (Helm Release)"]
                direction TB
                dev-D-COMPONENTID["COMPONENTID (Deployment)"]:::classDeployment <-. Port 8080 .-> dev-S-COMPONENTID["COMPONENTID (Service)"]:::classService <-. Port 8080 .-> dev-RT-COMPONENTID["COMPONENTID (Route)\nhttps://PROJECTID-dev.apps.OPENSHIFT_DOMAIN_DEV"]:::classRoute
            end
        end
    end
    subgraph BitBucket
        subgraph bitbucket-PROJECTID["PROJECTID (Project)"]
            subgraph bitbucket-PROJECTID-COMPONENTID["PROJECTID-COMPONENTID (Repo)"]
                bitbucket-PROJECTID-COMPONENTID-branch-master["master (Branch)"]
                bitbucket-PROJECTID-COMPONENTID-branch-release["release/20220518.001 (Branch)"]
            end
            subgraph bitbucket-PROJECTID-releasemanager["PROJECTID-releasemanager (Repo)"]
                bitbucket-PROJECTID-releasemanager-branch-master["master (Branch)"]
            end
        end
    end

aqua-aqua -- scan --> cd-IST-COMPONENTID
cd-IST-COMPONENTID --> dev-D-COMPONENTID
bitbucket-PROJECTID-COMPONENTID-branch-master -- pull --> jenkinsfile-PROJECTID-COMPONENTID
bitbucket-PROJECTID-releasemanager-branch-master -- pull --> jenkinsfile-releasemanager
BuildStage -- trigger --> jenkinsfile-PROJECTID-COMPONENTID
build-with-parameters -. trigger .-> InitStage
FinalizeStage -- push --> bitbucket-PROJECTID-COMPONENTID-branch-release
FinalizeStage -- push --> bitbucket-PROJECTID-releasemanager-branch-master
odsComponentStageBuildOpenShiftImage -- push --> cd-IST-COMPONENTID
odsComponentStageBuildOpenShiftImage -. trigger .-> aqua-aqua -. result .-> odsComponentStageBuildOpenShiftImage
odsComponentStageScanWithSonar -. trigger .-> sonarqube -. result .-> odsComponentStageScanWithSonar
stageWorkaroundRolloutDeployment -- "Rollout with Helm" --> dev-HR-COMPONENTID

%% stlyes
classDef classBitBucket fill:#2684FF22,stroke:#2684FF,stroke-width:4px
classDef classBitBucketProject fill:#2684FF22,stroke:#2684FF
classDef classBuildConfig fill:#00408022,stroke:#004080
classDef classDeployment fill:#00408022,stroke:#004080
classDef classDeploymentConfig fill:#00408022,stroke:#004080
classDef classHelmRelease fill:#2b9af322,stroke:#2b9af3
classDef classImageStream fill:#2b9af322,stroke:#2b9af3
classDef classImageStreamTag fill:#2b9af322,stroke:#2b9af3
classDef classOcpProject fill:#ffffff00,stroke:#f00,stroke-width:2px
classDef classOcpResource fill:#ffffff00,stroke:#06c,stroke-width:2px
classDef classOpenShift fill:#ffffff00,stroke:#f00,stroke-width:4px
classDef classRoute fill:#2b9af322,stroke:#2b9af3
classDef classService fill:#6ca10022,stroke:#6ca100
classDef classManualTask fill:#65bd1022,stroke:#65bd10,stroke-width:4px

class BitBucket classBitBucket
class bitbucket-PROJECTID,bitbucket-PROJECTID-COMPONENTID,bitbucket-PROJECTID-releasemanager classBitBucketProject
class dev-HR-COMPONENTID classHelmRelease
class cd-IS-COMPONENTID classImageStream
class aqua,ods,PROJECTID-cd,PROJECTID-dev classOcpProject
class aqua-aqua,jenkins,jenkinsfile-PROJECTID-COMPONENTID,jenkinsfile-releasemanager,sonarqube,webhook-proxy classOcpResource
class openshift-dev classOpenShift

Release to test environment

%% If the Mermaid Diagram is not rendered (as is the case on BitBucket), it can be viewed at https://mermaid.live/
flowchart TB
    subgraph openshift-dev["OpenShift (DEV)"]
        subgraph PROJECTID-cd
            subgraph jenkins["Jenkins"]
                build-with-parameters{{"<strong>Build with Parameters</strong>\nenvironment: qa\nversion: 20220518.001"}}:::classManualTask
                subgraph jenkinsfile-releasemanager["Jenkinsfile (Release Manager)"]
                    InitStage --> BuildStage --> DeployStage --> TestStage --> ReleaseStage --> FinalizeStage
                end
                subgraph jenkinsfile-PROJECTID-COMPONENTID["Jenkinsfile (PROJECTID-COMPONENTID)"]
                    stageInitialize --> stageInstallDependency --> stageVersioning --> stageWorkaroundFindOpenShiftImageOrElse --> stageWorkaroundUnitTest --> stageWorkaroundRolloutDeployment --> stageRelease
                end
            end
            subgraph cd-IS-COMPONENTID["COMPONENTID (Image Stream)"]
                cd-IST-COMPONENTID["COMPONENTID:20220518.001"]:::classImageStreamTag
            end
        end
        subgraph PROJECTID-test
            subgraph test-HR-COMPONENTID["COMPONENTID (Helm Release)"]
                test-D-COMPONENTID["COMPONENTID (Deployment)"]:::classDeployment <-. Port 8080 .-> test-S-COMPONENTID["COMPONENTID (Service)"]:::classService <-. Port 8080 .-> test-RT-COMPONENTID["COMPONENTID (Route)\nhttps://PROJECTID-test.apps.OPENSHIFT_DOMAIN_DEV"]:::classRoute
            end
        end
    end
    subgraph BitBucket
        subgraph bitbucket-PROJECTID["PROJECTID (Project)"]
            subgraph bitbucket-PROJECTID-COMPONENTID["PROJECTID-COMPONENTID (Repo)"]
                bitbucket-PROJECTID-COMPONENTID-branch-master["master (Branch)"]
                merge{{"<strong>Merge into master</strong>\nrelease/20220518.001 (Branch)"}}:::classManualTask
            end
            subgraph bitbucket-PROJECTID-releasemanager["PROJECTID-releasemanager (Repo)"]
                bitbucket-PROJECTID-releasemanager-branch-master["master (Branch)"]
            end
        end
    end

cd-IST-COMPONENTID <-.-> stageWorkaroundFindOpenShiftImageOrElse
cd-IST-COMPONENTID --> test-D-COMPONENTID
bitbucket-PROJECTID-COMPONENTID-branch-master -- pull --> jenkinsfile-PROJECTID-COMPONENTID
bitbucket-PROJECTID-releasemanager-branch-master -- pull --> jenkinsfile-releasemanager
merge --> bitbucket-PROJECTID-COMPONENTID-branch-master["master (Branch)"]
BuildStage -- trigger --> jenkinsfile-PROJECTID-COMPONENTID
build-with-parameters -. trigger .-> InitStage
FinalizeStage -- push --> bitbucket-PROJECTID-releasemanager-branch-master
stageWorkaroundRolloutDeployment -- "Rollout with Helm" --> test-HR-COMPONENTID

%% stlyes
classDef classBitBucket fill:#2684FF22,stroke:#2684FF,stroke-width:4px
classDef classBitBucketProject fill:#2684FF22,stroke:#2684FF
classDef classBuildConfig fill:#00408022,stroke:#004080
classDef classDeployment fill:#00408022,stroke:#004080
classDef classDeploymentConfig fill:#00408022,stroke:#004080
classDef classHelmRelease fill:#2b9af322,stroke:#2b9af3
classDef classImageStream fill:#2b9af322,stroke:#2b9af3
classDef classImageStreamTag fill:#2b9af322,stroke:#2b9af3
classDef classOcpProject fill:#ffffff00,stroke:#f00,stroke-width:2px
classDef classOcpResource fill:#ffffff00,stroke:#06c,stroke-width:2px
classDef classOpenShift fill:#ffffff00,stroke:#f00,stroke-width:4px
classDef classRoute fill:#2b9af322,stroke:#2b9af3
classDef classService fill:#6ca10022,stroke:#6ca100
classDef classManualTask fill:#65bd1022,stroke:#65bd10,stroke-width:4px

class BitBucket classBitBucket
class bitbucket-PROJECTID,bitbucket-PROJECTID-COMPONENTID,bitbucket-PROJECTID-releasemanager classBitBucketProject
class test-HR-COMPONENTID classHelmRelease
class cd-IS-COMPONENTID classImageStream
class aqua,ods,PROJECTID-cd,PROJECTID-test classOcpProject
class aqua-aqua,jenkins,jenkinsfile-PROJECTID-COMPONENTID,jenkinsfile-releasemanager,sonarqube,webhook-proxy classOcpResource
class openshift-dev classOpenShift

Release to prod environment

%% If the Mermaid Diagram is not rendered (as is the case on BitBucket), it can be viewed at https://mermaid.live/
flowchart TB
    subgraph openshift-dev["OpenShift (DEV)"]
        subgraph PROJECTID-cd
            subgraph jenkins["Jenkins"]
                build-with-parameters{{"<strong>Build with Parameters</strong>\nenvironment: prod\nversion: 20220518.001"}}:::classManualTask
                subgraph jenkinsfile-releasemanager["Jenkinsfile (Release Manager)"]
                    InitStage --> BuildStage --> DeployStage --> TestStage --> ReleaseStage --> FinalizeStage
                end
                subgraph jenkinsfile-PROJECTID-COMPONENTID["Jenkinsfile (PROJECTID-COMPONENTID)"]
                    stageInitialize --> stageInstallDependency --> stageVersioning --> stageWorkaroundFindOpenShiftImageOrElse --> stageWorkaroundUnitTest --> stageWorkaroundRolloutDeployment --> stageRelease
                end
            end
            subgraph cd-IS-COMPONENTID["COMPONENTID (Image Stream)"]
                cd-IST-COMPONENTID["COMPONENTID:20220518.001"]:::classImageStreamTag
            end
        end
    end
    subgraph openshift-prod["OpenShift (PROD)"]
        subgraph PROJECTID-prod
            subgraph prod-HR-COMPONENTID["COMPONENTID (Helm Release)"]
                prod-D-COMPONENTID["COMPONENTID (Deployment)"]:::classDeployment <-. Port 8080 .-> prod-S-COMPONENTID["COMPONENTID (Service)"]:::classService <-. Port 8080 .-> prod-RT-COMPONENTID["COMPONENTID (Route)\nhttps://PROJECTID.apps.OPENSHIFT_DOMAIN_PROD"]:::classRoute
            end
        end
    end
    subgraph BitBucket
        subgraph bitbucket-PROJECTID["PROJECTID (Project)"]
            subgraph bitbucket-PROJECTID-COMPONENTID["PROJECTID-COMPONENTID (Repo)"]
                bitbucket-PROJECTID-COMPONENTID-branch-master["master (Branch)"]
            end
            subgraph bitbucket-PROJECTID-releasemanager["PROJECTID-releasemanager (Repo)"]
                bitbucket-PROJECTID-releasemanager-branch-master["master (Branch)"]
            end
        end
    end

cd-IST-COMPONENTID --> prod-D-COMPONENTID
cd-IST-COMPONENTID <-.-> stageWorkaroundFindOpenShiftImageOrElse
bitbucket-PROJECTID-COMPONENTID-branch-master -- pull --> jenkinsfile-PROJECTID-COMPONENTID
bitbucket-PROJECTID-releasemanager-branch-master -- pull --> jenkinsfile-releasemanager
BuildStage -- trigger --> jenkinsfile-PROJECTID-COMPONENTID
build-with-parameters -. trigger .-> InitStage
FinalizeStage -- push --> bitbucket-PROJECTID-releasemanager-branch-master
stageWorkaroundRolloutDeployment -- "Rollout with Helm" --> prod-HR-COMPONENTID

%% stlyes
classDef classBitBucket fill:#2684FF22,stroke:#2684FF,stroke-width:4px
classDef classBitBucketProject fill:#2684FF22,stroke:#2684FF
classDef classBuildConfig fill:#00408022,stroke:#004080
classDef classDeployment fill:#00408022,stroke:#004080
classDef classDeploymentConfig fill:#00408022,stroke:#004080
classDef classHelmRelease fill:#2b9af322,stroke:#2b9af3
classDef classImageStream fill:#2b9af322,stroke:#2b9af3
classDef classImageStreamTag fill:#2b9af322,stroke:#2b9af3
classDef classOcpProject fill:#ffffff00,stroke:#f00,stroke-width:2px
classDef classOcpResource fill:#ffffff00,stroke:#06c,stroke-width:2px
classDef classOpenShift fill:#ffffff00,stroke:#f00,stroke-width:4px
classDef classRoute fill:#2b9af322,stroke:#2b9af3
classDef classService fill:#6ca10022,stroke:#6ca100
classDef classManualTask fill:#65bd1022,stroke:#65bd10,stroke-width:4px

class BitBucket classBitBucket
class bitbucket-PROJECTID,bitbucket-PROJECTID-COMPONENTID,bitbucket-PROJECTID-releasemanager classBitBucketProject
class prod-HR-COMPONENTID classHelmRelease
class cd-IS-COMPONENTID classImageStream
class aqua,ods,PROJECTID-cd,PROJECTID-prod classOcpProject
class aqua-aqua,jenkins,jenkinsfile-PROJECTID-COMPONENTID,jenkinsfile-releasemanager,sonarqube,webhook-proxy classOcpResource
class openshift-dev,openshift-prod classOpenShift

Housekeeping 🧹

πŸ’‘ From time to time, obsolete resources should be cleaned up. It would be best to have this automated at a later time. However, at the moment, this is not yet possible, because the webhook-proxy captures the deleted event and cannot be further customized, see: https://github.com/opendevstack/ods-core/blob/99d26527df60fbb4d72ba15a8c233e325ff37fe1/jenkins/webhook-proxy/main.go#L541-L556

Git Branches

git checkout master

# Cleaning outdated branches
git fetch --prune

# Delete all local branches except current branch (e.g. master)
git branch | grep --invert-match '^*' | xargs git branch -D

# Delete all remote branches except master (may take some time)
# Skip git hooks with '--no-verify'
git branch -r | grep 'origin' | grep --invert-match 'master$' | grep --invert-match HEAD | cut -d/ -f2- | while read line; do git push --no-verify origin :heads/$line; done;

Git Tags

# Delete all local tags that do NOT match a pattern of a semantic version (MAJOR.MINOR.PATCH), e.g. ods-generated-v20220518.001, v1.0.0-next.5
git tag -l | grep --invert-match '^v[[:digit:]]*.[[:digit:]]*.[[:digit:]]*$' | xargs git tag -d

# Delete all remote tags that do NOT match a pattern of a semantic version (MAJOR.MINOR.PATCH), e.g. ods-generated-v20220518.001, v1.0.0-next.5
# Skip git hooks with '--no-verify'
git ls-remote --tags origin | cut -d/ -f3- | grep --invert-match '^v[[:digit:]]*.[[:digit:]]*.[[:digit:]]*$' | grep -v '}$' | xargs git push --delete --no-verify origin

OpenShift

Feature Environments

With the approach of making each feature available as a new deployed environment for testing before it is merged into the master branch, a number of environments are created in OpenShift over time. The easiest way to delete these is to use the following command:

# Login
oc login --server=https://api.OPENSHIFT_DOMAIN_DEV:6443 --token=123...456

# Switch to Project
oc project PROJECTID-dev

# Delete/Uninstall all feature charts
helm list | grep -e 'COMPONENTID' | cut -f1 | xargs helm uninstall

# Delete all other feature resources
oc get all --output jsonpath='{range .items[*]}{"oc delete "}{.kind}{" "}{.metadata.name}{" "}{"\n"}{end}' | grep -- "COMPONENTID-feature-" | while read -r line; do eval $line; done

Jenkins Pipelines

Feature Pipelines: Since OpenShift 4, Jenkins pipelines are treated as BuildConfig. Unfortunately, with ODS@4.x in the Jenkins stage odsComponentStageBuildOpenShiftImage, all builds are also created as a BuildConfig in the cd project without any further information filled labels. A distinction is not obvious at first view, but can be figured out via the configuration parameter .spec.strategy.type (JenkinsPipeline vs Docker).

Release Pipelines: Can be deleted without any problems, since they do not create any further resources, instead they are directly cancelled due to [skip ci] in the commit message.

ODS Quickstarter: Can be deleted after successful creation without any problems, as there is no further need for them and they only take up resources unnecessarily.

# Login
oc login --server=https://api.OPENSHIFT_DOMAIN_DEV:6443 --token=123...456

# Switch Project
oc project PROJECTID-cd

# Delete all feature pipelines (may take some time)
oc get bc --output jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.strategy.type}{"\n"}{end}' | grep -e "JenkinsPipeline" | cut -f1 | grep -e "COMPONENTID-feature-" | while read -r line; do oc delete bc $line && sleep 10s; done

# Delete all release pipelines (may take some time)
oc get bc --output custom-columns=NAME:.metadata.name | grep -e "COMPONENTID-release-" | while read -r line; do oc delete bc $line && sleep 10s; done

# Delete all ods quickstarter pipelines (may take some time)
oc get bc --output custom-columns=NAME:.metadata.name | grep -e "ods-qs-" | while read -r line; do oc delete bc $line && sleep 10s; done

Roadmap πŸ›£οΈ

  • Improve Documentation
  • Implement Android
  • Implement iOS
  • Implement Ionic Appflow
  • Improve Testing

FAQ ❓❗

Jenkins

How do I find out which a Jenkins Agent with Node.js are available in my ODS@4.x setup?

Go to https://oauth-openshift.apps.OPENSHIFT_DOMAIN_DEV/k8s/ns/ods/build.openshift.io~v1~BuildConfig?name=jenkins-agent-nodejs

Openshift

How to find the oc login token
  1. Go to https://oauth-openshift.apps.OPENSHIFT_DOMAIN_DEV/oauth/token/display
  2. Click on Display token or Request another token

Known Issues 🚧

Bitbucket

A Pull Request shows a merge conflict on chart/Chart.yaml, chart/values.yaml, CHANGELOG.md, metadata.yml, package-lock.json, package.json, README.md

This happens mainly when e.g. a new feature branch has already been created from master branch before the Jenkins job has been successfully completed with a release commit.

To avoid resolving all merge conflicts manually, this can already be specified in the merge command by the --strategy-option=theirs option to automatically accept all incoming changes.

Solution:

# Merge the remote master branch into the current one without opening a text editor (accept the auto-generated message) and accept all incoming changes on merge conflicts
git merge origin/master --no-edit --strategy-option=theirs

# (Optional) Add `skip ci` command to the previous merge commit
git commit --amend -m "$(git log --format=%s --max-count=1) [skip ci]"

# Push the changes to the remote repository
git push

Jenkins

The Jenkins pipeline does not start and shows the following error message:[Failed] Failed to pull image "image-registry.openshift-image-registry.svc:5000/ods/jenkins-agent-nodejs16:4.x" ... [Failed] Error: ImagePullBackOff

It might happen that your ODS@4.x setup only provides a Jenkins agent with Node.js 12.x. However, in order to be able to work with the latest version and to have potential security holes closed, a Jenkins agent with the latest Node.js version is required for the build process in the CI/CD process.

FAQ: How do I find out which a Jenkins Agent with Node.js are available in my ODS@4.x setup?

In case it does not exist yet, it can be easily created with the following commands

FAQ: How to find the oc login token

Solution:

# Login to OpenShift dev instance
oc login --server=https://api.OPENSHIFT_DOMAIN_DEV:6443 --token=123...456

# Switch project
oc project PROJECTID-cd

# Provision jenkins-agent-nodejs-16
oc process -f https://raw.githubusercontent.com/SimonGolms/ods-jenkins-agent-nodejs/main/jenkins-agent-nodejs-16-template.yaml | oc create -f -

For more information about the Jenkins agent, see: https://github.com/SimonGolms/ods-jenkins-agent-nodejs

The Release Manager finishes the release to the qa/test environment with the following yellow message: Finished: UNSTABLE

This state is already set at the beginning by the following message in the Jenkins log: WARN: app@<GIT-HASH-1> is NOT a descendant of <GIT-HASH-2>, which has previously been promoted to 'Q'. If <GIT-HASH-2> has been promoted to 'P' as well, promotion to 'P' will fail. Proceed with caution.

Before you can deploy a release into qa/test environment, you need to merge the release branch into your master branch to pass the checks in the Jenkins shared library stage odsOrchestrationPipeline, see comment in metadata.yml for more details:

Solution:

  1. Merge release branch into master

    # Switch to master branch
    git checkout master
    
    # Merge the remote release branch into master without opening a text editor and accept the auto-generated message
    git merge origin/release/<VERSION> --no-edit
    
    # Push the changes to the remote repository
    git push
  2. Repeat step 1 for all other relevant code repositories which are also specified in the metadata.yml of the Release Manager code repository and are rolled out with helm, like a backend.

  3. In the Release Manager code repository fix the inconsistent ods state by deleting the ./ods-state folder

    # Switch to master branch
    git checkout master
    
    # Fetch latest state to match the remote branch
    git pull
    
    # Remove inconsistent ods state
    rm -rf ods-state
    
    # Commit all changes
    git commit --all --message="chore(ods): remove inconsistent state"
    
    # Push the changes to the remote repository
    git push
  4. Re-run the Release Manager pipeline with a new version. This time, be sure to merge the release branch into master before the further rollout towards qa/test environment!

WSL

When committing via the VS Code interface, the following error message appears .husky/commit-msg: 4: npx: not found

Since we are using nvm as our versions manager for Node.js, we first need to tell husky where to find the appropriate binaries. This is done by creating and configuring the file ~/.huskyrc. Further Information: https://typicode.github.io/husky/#/?id=command-not-found

Solution:

  1. Create ~/.huskyrc file with nvm configuration

    cat > ~/.huskyrc << EOF
    # This loads nvm.sh and sets the correct PATH before running hook
    export NVM_DIR="$HOME/.nvm"
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
    EOF
  2. Restart VS Code

Author πŸ–Š

Simon Golms:

Contributing 🀝

Contributions, issues and feature requests are welcome!

Show your support πŸ‘

Give a ⭐️ if this project helped you!

License πŸ“œ

Copyright Β© 2022 Simon Golms.
This project is Apache-2.0 licensed.

Further Resources πŸ“–