-
Notifications
You must be signed in to change notification settings - Fork 44
[minor] Add support For Installation and FVT setup for Aiservice 9.1.x #1620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
Show all changes
136 commits
Select commit
Hold shift + click to select a range
2d75191
[patch] Create setup for aiservice install
f2a82a2
[patch] Create InstallAiService Class for stand alone aiservice
67eeca3
[patch] Add support for aiservice-install through tekton pipeline
03e9674
[patch] Change the function name of LaunchPipeLine
2de93a3
[patch] Import launchInstallPipelineForAiservice from python package
8f43e45
[patch] remove CP4D from aiservice-install pipeline
9a814fe
[patch] create areBuild for ai service
5a598c6
[patch] remove typo
bb96c50
[patch] Add config-pvc-aiservice claim
8f1341e
[patch] change ansible collection
e93eb03
[patch] change ansible collection
bf8c742
[patch] change pythond-devops package
2898417
[patch] change latest ansible collection
b058cc4
[patch] Add support for AIBroker FVT
6285388
[patch] Add new vars to aibroker task
77cc7e2
[patch] change ansible collection
9eff4a8
[patch] change ansible collection
55df392
[patch] Add dummy value for s3_region
602b6f7
[patch] add new pipeline for launching fvt for aiservice and add appr…
35b54b4
[patch] add new line in fvt-launcher-for-aiservice pipeline
7574f2e
[patch] add key for approval-aibroker
73ba20d
[patch] add params to fvt-run-suite
7a6f4bb
[patch] remove app-config for aibroker
9590079
[patch] Add support for AIBroker FVT
4bd2127
[patch] modify argbuilder
80d62df
[patch] Add aibroker-post-verification
358e983
[patch] fix aibroker-post-verify
d4f923a
[patch] fix aibroker-post-verify
25e1365
[patch] add fvt-finalizer in fvt-aiservice
4788ed0
[patch] change ansible collection
49ede28
[patch] change channel condition in aibroker-tenant
5dc2dd6
[patch] add rsl params
87f78e6
[patch] change default value of s3_region
d8e929a
[patch] change ansible collection
c502d9f
[patch] change timeout for fvt test
efd8953
[patch] change python-devops package
390d84f
[patch] change ansible collection
7e8f27b
[patch] change idenation errro
3e0d4e5
[patch] remove pre-commit error
f778190
Merge master into aiservice
ab24a5a
[patch] Add aibroker as knownProductIds in finalizer.py
ef81b1d
[patch] add mariadb params to aibroker
222780f
[patch] change ansible collection
e373cc6
[patch] Add mariadb params to aibroker
0a77bf0
[patch] add extra line in fvt_launcher
94777f2
[patch] Add params in fvt-run-suite
53f9a53
[patch] Increase fvt-aibroker pipeline timeout to 4h
c2058a4
[patch] Increse timeout for fvt-aibroker
2685a76
[patch] change ansible collection
0cb9ecb
[patch] remove image scan
d133af3
[patch] add approval-aibroker in InstallApp
218e6f3
[patch] add aiservice-fvt in fvt-launcher
e05d109
[patch] set default value for skip mas install
70b488e
[patch] remove disable approval-configmap from InstallAiservice
9cd3f75
[patch] Add flag for installtion of dependency
091e86c
[patch] Introduce hold aiservice for mas
8c942f9
[patch] change condition for wait-suite-verify
1d08741
[patch] Refactor params of aiservice
0175089
[patch] Refactor arg-builder for aiservice
b5b80dc
[patch] Change FVT-aiservice execution into parallel mode
8f2fa83
[patch] remove test marker from fvt-run-suite
8a2926b
[patch] Merge master into aiservice
fd14585
[patch] refactor code
935515d
[patch] change local python package
2dc6740
[patch] fix issue related to facilities
5c34c0d
[patch] create argParserAiservice
c6b74f0
[patch] fix typos
3d2f969
Create install-aiservice.md
Bhautik-Vala 6d7e1d4
[patch] Change condition in installation of deps
87908d2
[patch] change ansible collection
70ae39d
[patch] Fix pre-commit issue
de6405e
[patch] Change fvt execution in sequence mode
34f262a
[patch] code refactoring - remove extra launcher pipeline
e171b32
[patch] remove fvtaisvc pipeline name from generate pipeline
7c190ca
[patch] change python package
89ecc38
[patch] remove masConfig from aibroker class
4c00df3
Merge branch 'master' into aiservice
unnati-solanki-git 976d428
[patch] change ansible collection
6e7c00e
[patch] change ansible collection
47d1109
[patch] change files name to aiservice and add aibroker_instance_id
42008a2
[patch] Fix aibroker_instance_id related issue
f0fd397
[patch] bug fix
4ca2783
[patch] Merge master into aiservice
375e43f
[patch] bug fix
30be254
[patch] bug fix
b7e2018
[patch] change aiservice model template version
098d4e5
[patch] code refactoring
35e1be7
[patch] Code refactoring
621a1d1
[patch] Merge master into aiservice
3aec18b
[patch] Remove local tar files
610a88b
[patch] Add local tar files
4d7c36c
[patch] Remove unused args from argparser
701e73e
[patch] Inherit InstaApp class in InstallAiservice
bc2292d
[patch] remove mas_workspace_id from fvt files - related to aiservice
b888524
[patch] Fix argparser
ca8005a
[patch] Refactor params and aiservice-fvt execution
23fa3d0
[patch] Add additional-configs params
3dacc25
[patch] Refactor code
63d5c10
[patch] Fix bug by add new line in fvt-aiservice
29033b7
[patch] change fvt-suite execution order
034443b
[patch] remove python-pkg local file
8d8aad0
Merge branch 'master' into aiservice
8b61454
[patch] remove redundant class inheritance in InstallAiservice
714376e
[patch] enable optional installation of deps
5d6074c
[patch] refactor code
98473f1
[patch] Fix bug
8e8a52f
[patch] Fix bug
5996752
[patch] Fix bug
d1cc243
[patch] change ansible collection
aa2f676
[patch] change ansible collection
c11cfec
[patch] change ansible collection
f64ae72
[patch] change condition for entitlement local file in InstallAiservice
7b98458
[patch] test smart prompting
a3d2548
[patch] change ansible collection
1469230
Merge branch 'master' into aiservice
e424fbb
[patch] change ansible collection
181be4d
[patch] change ansible collection
a52f6cd
[patch] change ansinle collection
85f4da4
[patch] change ansible collection
7fe8e2d
[patch] change ansible collection
a29b884
[patch] change ansible collection
cd16a1d
[patch] change ansible collection
d4c57ba
[patch] change ansible collection
d750fc4
[patch] refactor documentation
ecdae99
Merge branch 'master' into aiservice
5124414
Aiservicecleanup (#1645)
durera c72c830
[patch] code cleanup for aiservice
4da1e7c
[patch] Inherit class AdditionalConfigsMixin in AiServiceInstallApp
0fa0d61
[patch] Code cleanup
cb8b93d
[patch] Fix code and change ansible collection
80444fd
[patch] Add mas_aibroker_version in june catalogue
1ec4053
[patch] remove ansible local collection
4b193ca
Merge branch 'master' into aiservice
7eef9f0
[patch] code cleanup
595b0ab
[patch] remove local packages and update doc
3c3d3aa
Merge branch 'master' into aiservice
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| Installation | ||
| =============================================================================== | ||
| Usage | ||
| ------------------------------------------------------------------------------- | ||
| For full usage information run `mas aiservice-install --help` <br> | ||
| `mas aiservice-install` is specifically built for installation of Aiservice 9.1.x or above. <br> | ||
| <br> | ||
| For installation of Aiservice 9.0.x have to use `mas install` command. | ||
|
|
||
| Preparation | ||
| ------------------------------------------------------------------------------- | ||
| ### IBM Entitlement Key | ||
| Access [Container Software Library](https://myibm.ibm.com/products-services/containerlibrary) using your IBMId to obtain your entitlement key. | ||
|
|
||
| ### MAS License File | ||
| Access [IBM License Key Center](https://licensing.flexnetoperations.com/), on the **Get Keys** menu select **IBM AppPoint Suites**. Select `IBM MAXIMO APPLICATION SUITE AppPOINT LIC` and on the next page fill in the information as below: | ||
|
|
||
| | Field | Content | | ||
| | ---------------- | ----------------------------------------------------------------------------- | | ||
| | Number of Keys | How many AppPoints to assign to the license file | | ||
| | Host ID Type | Set to **Ethernet Address** | | ||
| | Host ID | Enter any 12 digit hexadecimal string | | ||
| | Hostname | Set to the hostname of your OCP instance, but this can be any value really. | | ||
| | Port | Set to **27000** | | ||
|
|
||
|
|
||
| The other values can be left at their defaults. Finally, click **Generate** and download the license file to your home directory as `entitlement.lic`. | ||
|
|
||
| !!! note | ||
| For more information about how to access the IBM License Key Center review the [getting started documentation](https://www.ibm.com/support/pages/system/files/inline-files/GettingStartedEnglish_2020.pdf) available from the IBM support website. | ||
|
|
||
| ### OpenShift Cluster | ||
| You should already have a target OpenShift cluster ready to install Maximo Application suite into. If you do not already have one then refer to the [OpenShift Container Platform installation overview](https://docs.openshift.com/container-platform/4.15/installing/index.html). | ||
|
|
||
| The CLI also supports OpenShift provisioning in many hyperscaler providers: | ||
|
|
||
| - [AWS](../commands/provision-rosa.md) | ||
| - [IBM Cloud](../commands/provision-roks.md) | ||
| - [IBM DevIT FYRE (Internal)](../commands/provision-fyre.md) | ||
|
|
||
|
|
||
| ### Operator Catalog Selection | ||
| If you have not already determined the catalog version for your installation, refer to the information in the [Operator Catalog](../catalogs/index.md) topic, or contact IBM Support for guidance. | ||
|
|
||
|
|
||
| Interactive Install | ||
| ------------------------------------------------------------------------------- | ||
| Regardless of whether you are running a connected or disconnected installation, simply run the `mas aiservice-install` command and follow the prompts, the basic structure of the interactive flow is described below. | ||
|
|
||
| We will need the `entitlement.lic` file to perform the installation so we will mount your home directory into the running container. When prompted you will be able to set license file to `/mnt/home/entitlement.lic` - <b> This is a prerequisite step, required only when `sls` has not been installed previously. </b> | ||
|
|
||
| ```bash | ||
| docker run -ti --rm -v ~:/mnt/home quay.io/ibmmas/cli:@@CLI_LATEST_VERSION@@ mas aiservice-install | ||
| ``` | ||
|
|
||
| The interactive install will guide you through a series of questioned designed to help you arrive at the best configuration for your scenario, it can be broken down as below: | ||
|
|
||
| <div> | ||
| <cds-accordion> | ||
| <cds-accordion-item title="Connect to OpenShift and Choose a Catalog"> | ||
| <p>If you are not already connected to an OpenShift cluster you will be prompted to provide the server URL & token to make a new connection. If you are already connected to a cluster you will be given the option to change to another cluster</p> | ||
| <p>You will be presented with a table of available catalogs with information about the different releases of MAS</p> | ||
| <p>Confirm that you accept the IBM Maximo Application Suite license terms</p> | ||
| </cds-accordion-item> | ||
| <cds-accordion-item title="Select Storage Classes"> | ||
| <p>MAS requires both a `ReadWriteMany` and a `ReadWriteOnce` capable storage class to be available in the cluster. The installer has the ability to recognize certain storage class providers and will default to the most appropriate storage class in these cases:</p> | ||
| <ul> | ||
| <li>IBMCloud Storage (ibmc-block-gold & ibmc-file-gold-gid)</li> | ||
| <li>OpenShift Container Storage (ocs-storagecluster-ceph-rbd & ocs-storagecluster-cephfs)</li> | ||
| <li>External OpenShift Container Storage (ocs-external-storagecluster-ceph-rbd & ocs-external-storagecluster-cephfs)</li> | ||
| <li>NFS Client (nfs-client)</li> | ||
| <li>Azure Managed Storage (managed-premium & azurefiles-premium)</li> | ||
| <li>AWS Storage (gp3-cs & efs)</li> | ||
| </ul> | ||
| <p>The names in brackets represent the `ReadWriteOnce` and `ReadWriteMany` class that will be used, in the case of NFS the same storage class will be used for both `ReadWriteOnce` and `ReadWriteMany` volumes. Even when a recognized storage provider is detected you will be provided with the option to select your own storages classes if you wish.</p> | ||
| <p>When selecting your own storage classes you will be presented with a list of those available and must select both a `ReadWriteMany` and a `ReadWriteOnce` storage class. Unfortunately there is no way for the install to verify that the storage class selected actually supports the appropriate access mode, refer to the documentation from the storage class provider to determine whether your storage class supports `ReadWriteOnce` and/or `ReadWriteMany`.</p> | ||
| </cds-accordion-item> | ||
| <cds-accordion-item title="Provide a License File and Entitlement Key"> | ||
| <p>Provide the location of your license file, contact information, and IBM entitlement key (if you have set the <code>IBM_ENTITLEMENT_KEY</code> environment variable then this field will be pre-filled with that value already).</p> | ||
| </cds-accordion-item> | ||
| <cds-accordion-item title="Configure your Aiservice Instance"> | ||
| <p>Provide the basic information about your Aiservice instance:</p> | ||
| <ul> | ||
| <li>Instance ID</li> | ||
| <li>Configure s3 storage, DB, RSL and tenant</li> | ||
| <li>Choose to install SLS, DB2, or DRO as a dependency, or opt out and provide alternative information including connection URL and token.</li> | ||
| <li>Operational Mode (production or non-production)</li> | ||
| </ul> | ||
| </cds-accordion-item> | ||
| <cds-accordion-item title="Review Choices"> | ||
| <p>Before the install actually starts you will be presented with a summary of all your choices and a non-interactive command that will allow you to repeat the same installation without going through all the prompts again.</p> | ||
| </cds-accordion-item> | ||
|
|
||
| </cds-accordion> | ||
| </div> | ||
|
|
||
| Non-Interactive Install | ||
| ------------------------------------------------------------------------------- | ||
| The following command will launch the MAS CLI container image, login to your OpenShift Cluster and start the install of MAS without triggering any prompts. This is how we install MAS in development hundreds of times every single week. | ||
|
|
||
| ```bash | ||
| IBM_ENTITLEMENT_KEY=xxx | ||
|
|
||
| docker run -e IBM_ENTITLEMENT_KEY -e SUPERUSER_PASSWORD -ti --rm -v ~:/mnt/home quay.io/ibmmas/cli:@@CLI_LATEST_VERSION@@ bash -c " | ||
| oc login --token=sha256~xxxx --server=https://xxx && | ||
| mas aiservice-install \ | ||
| --mas-catalog-version @@MAS_LATEST_CATALOG@@ \ | ||
| --aibroker-instance-id aib1 \ | ||
| --aibroker-channel 9.1.x \ | ||
| \ | ||
| --ibm-entitlement-key '${IBM_ENTITLEMENT_KEY}' \ | ||
| --license-file /mnt/home/entitlement.lic \ | ||
| --uds-email myemail@email.com \ | ||
| --uds-firstname John \ | ||
| --uds-lastname Barnes \ | ||
| \ | ||
| --storage-rwo ibmc-block-gold \ | ||
| --storage-rwx ibmc-file-gold-gid \ | ||
| --storage-pipeline ibmc-file-gold-gid \ | ||
| --storage-accessmode ReadWriteMany \ | ||
| \ | ||
| --accept-license --no-confirm | ||
| ``` | ||
|
|
||
| More Information | ||
| ------------------------------------------------------------------------------- | ||
| The install is designed to work on any OCP cluster, but has been specifically tested in these environments: | ||
|
|
||
| - IBMCloud ROKS | ||
| - IBM DevIT FYRE (internal) | ||
|
|
||
| The engine that performs all tasks is written in Ansible, you can directly use the same automation outside of this CLI if you wish. The code is open source and available in [ibm-mas/ansible-devops](https://github.com/ibm-mas/ansible-devops), the collection is also available to install directly from [Ansible Galaxy](https://galaxy.ansible.com/ibm/mas_devops), the install supports the following actions: | ||
|
|
||
| - IBM Maximo Operator Catalog installation | ||
| - Required dependency installation: | ||
| - MongoDb (Community Edition) - only needed when want to install SLS. | ||
| - IBM Suite License Service (installed instance of SLS also can be used). | ||
| - IBM Data Reporter Operator | ||
| - Red Hat Certificate Manager | ||
| - Minio | ||
| - Mariadb | ||
| - db2 | ||
| - Aiservice installation | ||
|
|
||
| <div style="clear: right"></div> | ||
|
|
||
| The installation is performed inside your RedHat OpenShift cluster utilizing [Openshift Pipelines](https://cloud.redhat.com/learn/topics/ci-cd) | ||
|
|
||
| > OpenShift Pipelines is a Kubernetes-native CI/CD solution based on Tekton. It builds on Tekton to provide a CI/CD experience through tight integration with OpenShift and Red Hat developer tools. OpenShift Pipelines is designed to run each step of the CI/CD pipeline in its own container, allowing each step to scale independently to meet the demands of the pipeline. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| --- | ||
| - hosts: localhost | ||
| any_errors_fatal: true | ||
| vars: | ||
| # Image Pull Policy | ||
| image_pull_policy: "{{ lookup('env', 'IMAGE_PULL_POLICY') }}" | ||
| # MAS Details | ||
| mas_app_channel_aibroker: "{{ lookup('env', 'MAS_APP_CHANNEL_AIBROKER') }}" | ||
| mas_workspace_id: "{{ lookup('env', 'MAS_WORKSPACE_ID') }}" | ||
|
|
||
| aibroker_instance_id: "{{ lookup('env', 'AIBROKER_INSTANCE_ID') }}" | ||
| # FVT Configuration | ||
| fvt_image_registry: "{{ lookup('env', 'FVT_IMAGE_REGISTRY') }}" | ||
| fvt_artifactory_username: "{{ lookup('env', 'FVT_ARTIFACTORY_USERNAME') }}" | ||
| fvt_artifactory_token: "{{ lookup('env', 'FVT_ARTIFACTORY_TOKEN') }}" | ||
| fvt_digest_aibroker: "{{ lookup('env', 'FVT_DIGEST_AIBROKER') }}" | ||
| ivt_digest_core: "{{ lookup('env', 'IVT_DIGEST_CORE') }}" | ||
| # Pipeline Run Info | ||
| devops_build_number: "{{ lookup('env', 'DEVOPS_BUILD_NUMBER') | default('0', True) }}" | ||
| pipelinerun_name: "{{ lookup('env', 'PIPELINERUN_NAME') | default('mas-fvt-aibroker', True) }}-{{ devops_build_number }}" | ||
| pipelinerun_namespace: "{{ lookup('env', 'PIPELINERUN_NAMESPACE') | default('mas-' ~ aibroker_instance_id ~ '-pipelines', True) }}" | ||
| tasks: | ||
| - name: "Debug" | ||
| debug: | ||
| msg: | ||
| - "pipelinerun_name .................. {{ pipelinerun_name }}" | ||
| - "pipelinerun_namespace ............. {{ pipelinerun_namespace }}" | ||
| - "" | ||
| - "mas_app_channel_aibroker ........... {{ mas_app_channel_aibroker }}" | ||
| - "aibroker_instance_id ................... {{ aibroker_instance_id }}" | ||
| - "" | ||
| - "fvt_image_registry ................ {{ fvt_image_registry }}" | ||
| - "fvt_artifactory_username .......... {{ fvt_artifactory_username }}" | ||
| - "fvt_artifactory_token ............. {{ fvt_artifactory_token }}" | ||
| - "fvt_digest_aibroker ................ {{ fvt_digest_aibroker }}" | ||
| - "ivt_digest_core ................... {{ ivt_digest_core }}" | ||
|
|
||
| - name: "Start fvt-aiservice pipeline" | ||
| kubernetes.core.k8s: | ||
| apply: true | ||
| template: templates/mas-fvt-aiservice.yml.j2 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| --- | ||
| apiVersion: tekton.dev/v1beta1 | ||
| kind: PipelineRun | ||
| metadata: | ||
| name: "{{ pipelinerun_name }}" | ||
| namespace: "{{ pipelinerun_namespace }}" | ||
| labels: | ||
| tekton.dev/pipeline: mas-fvt-aibroker | ||
| spec: | ||
| pipelineRef: | ||
| name: mas-fvt-aibroker | ||
|
|
||
| serviceAccountName: pipeline | ||
| timeouts: | ||
| pipeline: "8h" | ||
|
|
||
| params: | ||
| # Pull Policy | ||
| - name: image_pull_policy | ||
| value: "{{ image_pull_policy }}" | ||
| # MAS Info | ||
| - name: mas_app_channel_aibroker | ||
| value: "{{ mas_app_channel_aibroker }}" | ||
| - name: mas_instance_id | ||
| value: "{{ aibroker_instance_id }}" | ||
| - name: mas_workspace_id | ||
| value: "{{ mas_workspace_id }}" | ||
| # Registry | ||
| - name: fvt_image_registry | ||
| value: "{{ fvt_image_registry }}" | ||
| - name: fvt_artifactory_username | ||
| value: "{{ fvt_artifactory_username }}" | ||
| - name: fvt_artifactory_token | ||
| value: "{{ fvt_artifactory_token }}" | ||
| # Digests | ||
| - name: fvt_digest_aibroker | ||
| value: "{{ fvt_digest_aibroker }}" | ||
| - name: ivt_digest_core | ||
| value: "{{ ivt_digest_core }}" | ||
|
|
||
| workspaces: | ||
| # The generated configuration files | ||
| - name: shared-configs | ||
| persistentVolumeClaim: | ||
| claimName: config-pvc | ||
| # PodTemplates configurations | ||
| - name: shared-pod-templates | ||
| secret: | ||
| secretName: pipeline-pod-templates |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # ***************************************************************************** | ||
| # Copyright (c) 2024, 2025 IBM Corporation and other Contributors. | ||
| # | ||
| # All rights reserved. This program and the accompanying materials | ||
| # are made available under the terms of the Eclipse Public License v1.0 | ||
| # which accompanies this distribution, and is available at | ||
| # http://www.eclipse.org/legal/epl-v10.html | ||
| # | ||
| # ***************************************************************************** | ||
|
|
||
| from ...cli import BaseApp # noqa: F401 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.