├── .github
├── dependabot.yml
└── workflows
│ └── gradle.yml
├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── jitpack.yml
├── lombok.config
├── settings.gradle
└── src
├── main
└── java
│ └── io
│ └── visual_regression_tracker
│ └── sdk_java
│ ├── IgnoreAreas.java
│ ├── PathProvider.java
│ ├── TestRunException.java
│ ├── TestRunOptions.java
│ ├── TestRunResult.java
│ ├── TestRunStatus.java
│ ├── VisualRegressionTracker.java
│ ├── VisualRegressionTrackerConfig.java
│ ├── request
│ ├── BuildRequest.java
│ └── TestRunRequest.java
│ └── response
│ ├── BuildResponse.java
│ └── TestRunResponse.java
└── test
├── java
└── io
│ └── visual_regression_tracker
│ └── sdk_java
│ ├── MockHttpClient.java
│ ├── PathProviderTest.java
│ ├── VisualRegressionTrackerConfigTest.java
│ └── VisualRegressionTrackerTest.java
└── resources
├── home_page.png
├── logback.xml
└── vrt_config_example.json
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: gradle
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | open-pull-requests-limit: 2
8 | ignore:
9 | - dependency-name: com.squareup.okhttp3:mockwebserver
10 | versions:
11 | - 4.9.0
12 |
--------------------------------------------------------------------------------
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Gradle
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
3 |
4 | name: Java CI with Gradle
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 |
20 | - name: Set up JDK 11
21 | uses: actions/setup-java@v4
22 | with:
23 | distribution: 'temurin'
24 | java-version: 11
25 |
26 | - name: Grant execute permission for gradlew
27 | run: chmod +x gradlew
28 |
29 | - name: Gradle check
30 | run: ./gradlew check
31 |
32 | - name: Codecov
33 | uses: codecov/codecov-action@v1.0.12
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Gradle
2 | # ------
3 | .gradle
4 | /build
5 | /buildSrc/build
6 | /buildSrc/subprojects/*/build
7 | /subprojects/*/build
8 | /subprojects/docs/src/samples/**/build
9 | /subprojects/docs/src/snippets/**/build
10 | /subprojects/internal-android-performance-testing/build-android-libs
11 |
12 | # IDEA
13 | # ----
14 | !/.idea
15 | /.idea/*
16 | !/.idea/codeStyles
17 | !/.idea/inspectionProfiles
18 | !/.idea/icon.png
19 | !/.idea/icon_dark.png
20 | */**/.idea
21 | .shelf
22 | /*.iml
23 | /*.ipr
24 | /*.iws
25 | /buildSrc/.idea
26 | /buildSrc/.shelf
27 | /buildSrc/*.iml
28 | /buildSrc/*.ipr
29 | /buildSrc/*.iws
30 | /buildSrc/out
31 | /buildSrc/subprojects/*/*.iml
32 | /buildSrc/subprojects/*/out
33 | /out
34 | /subprojects/*/*.iml
35 | /subprojects/*/out
36 | /.teamcity/*.iml
37 | /.teamcity/target
38 |
39 | # Eclipse
40 | # -------
41 | *.classpath
42 | *.project
43 | *.settings
44 | /bin
45 | /subprojects/*/bin
46 | atlassian-ide-plugin.xml
47 | .metadata/
48 |
49 | # NetBeans
50 | # --------
51 | .nb-gradle
52 | .nb-gradle-properties
53 |
54 | # Vim
55 | # ---
56 | *.sw[nop]
57 |
58 | # Emacs
59 | # -----
60 | *~
61 | \#*\#
62 | .\#*
63 |
64 | # Textmate
65 | # --------
66 | .textmate
67 |
68 | # Sublime Text
69 | # ------------
70 | *.sublime-*
71 |
72 | # jEnv
73 | # ----
74 | .java-version
75 |
76 | # macOS
77 | # ----
78 | .DS_Store
79 |
80 | # HPROF
81 | # -----
82 | *.hprof
83 |
84 | # Work dirs
85 | # ---------
86 | /incoming-distributions
87 | /intTestHomeDir
88 |
89 | # Logs
90 | # ----
91 | /*.log
92 |
93 | # oh-my-zsh gradle plugin
94 | .gradletasknamecache
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Java SDK for [Visual Regression Tracker](https://github.com/Visual-Regression-Tracker/Visual-Regression-Tracker)
2 | [](https://www.codacy.com/gh/Visual-Regression-Tracker/sdk-java?utm_source=github.com&utm_medium=referral&utm_content=Visual-Regression-Tracker/sdk-java&utm_campaign=Badge_Grade)
3 |
4 | ## Gradle
5 |
6 | ```yml
7 | repositories {
8 | maven { url 'https://jitpack.io' }
9 | }
10 | ```
11 |
12 | ```yml
13 | dependencies {
14 | implementation group: 'com.github.visual-regression-tracker', name: 'sdk-java', version: '${REPLACE_THIS_VALUE}'
15 | }
16 | ```
17 |
18 | ## Maven
19 |
20 | ```xml
21 |
22 |
23 | jitpack.io
24 | https://jitpack.io
25 |
26 |
27 | ```
28 |
29 | ```xml
30 |
31 | com.github.Visual-Regression-Tracker
32 | sdk-java
33 | ${REPLACE_THIS_VALUE}
34 |
35 | ```
36 | [Available versions](https://github.com/Visual-Regression-Tracker/sdk-java/releases)
37 |
38 | More info about https://jitpack.io/
39 |
40 | ## Usage
41 |
42 | ### Configuration
43 | In order to initialize VisualRegressionTracker, following options should be defined:
44 |
45 | * `apiUrl` (**Required**) - URL where backend is running. _Example_: "http://localhost:4200"
46 | * `project` (**Required**) - Project name or ID. _Example_: "003f5fcf-6c5f-4f1f-a99f-82a697711382"
47 | * `apiKey` (**Required**) - User apiKey. _Example_: "F5Z2H0H2SNMXZVHX0EA4YQM1MGDD"
48 | * `branch` (Optional) - Current git branch. _Example_: "develop"
49 | * `enableSoftAssert` (Optional) - Log errors instead of exceptions. Default value is false
50 | * `ciBuildId` (Optional) - id of the build in CI system
51 | * `httpTimeoutInSeconds` (Optional) - define http socket timeout in seconds. Default value is 10 seconds
52 |
53 | There are a few ways to provide those options
54 |
55 |
56 |
57 | Create config with builder
58 |
59 | ```java
60 | VisualRegressionTrackerConfig config = VisualRegressionTrackerConfig.builder()
61 | .apiUrl("http://localhost:4200")
62 | .apiKey("F5Z2H0H2SNMXZVHX0EA4YQM1MGDD")
63 | .project("003f5fcf-6c5f-4f1f-a99f-82a697711382")
64 | .enableSoftAssert(true)
65 | .branchName("develop")
66 | .build();
67 | ```
68 |
69 |
70 |
71 |
72 |
73 | Set environment variables
74 |
75 | ```
76 | export VRT_APIURL=http://localhost:4200
77 | export VRT_APIKEY=F5Z2H0H2SNMXZVHX0EA4YQM1MGDD
78 | export VRT_PROJECT=003f5fcf-6c5f-4f1f-a99f-82a697711382
79 | export VRT_BRANCHNAME=develop
80 | export VRT_ENABLESOFTASSERT=true
81 | export VRT_CIBUILDID=40bdba4
82 | export VRT_HTTPTIMEOUTINSECONDS=15
83 |
84 | ```
85 |
86 |
87 |
88 |
89 |
90 | Create vrt.json file in the root of the project
91 |
92 | ```json
93 | {
94 | "apiUrl": "[http://162.243.161.172:4200](http://localhost:4200)",
95 | "project": "003f5fcf-6c5f-4f1f-a99f-82a697711382",
96 | "apiKey": "F5Z2H0H2SNMXZVHX0EA4YQM1MGDD",
97 | "branchName": "develop",
98 | "enableSoftAssert": false,
99 | "ciBuildId": "40bdba4"
100 | }
101 |
102 | ```
103 |
104 |
105 |
106 | > [!NOTE]
107 | > Final values, that will be used by VisualRegressionTracker, will be resolved as following:
108 | > 1. If explicitly set while creating `VisualRegressionTrackerConfig` - use this value
109 | > 2. Use value from environment variable if it exists
110 | > 3. Try to get it from the configuration file
111 |
112 |
113 |
114 |
115 | ### Create an instance of `VisualRegressionTracker`
116 |
117 | ```java
118 | VisualRegressionTracker visualRegressionTracker = new VisualRegressionTracker(config);
119 | ```
120 |
121 | or
122 |
123 | ```java
124 | VisualRegressionTracker visualRegressionTracker = new VisualRegressionTracker();
125 | ```
126 |
127 | > [!TIP]
128 | > If config is not provided explicitly, it will be created based on the environment variables or configuration file. Please see [Configuration](README.md#configuration) section
129 |
130 |
131 |
132 | ### Start `VisualRegressionTracker`
133 |
134 | ```java
135 | visualRegressionTracker.start();
136 | ```
137 |
138 | At that point VisualRegressionTracker will try to create a new build for provided project. All of the subsequent tracked screenshots are going to be included in that build.
139 |
140 |
141 |
142 | ### Take a screenshot as String in Base64 format
143 |
144 | ```java
145 | // Selenium example
146 | String screenshotBase64 = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BASE64);
147 | ```
148 |
149 |
150 |
151 | ### Track image
152 |
153 | Default options
154 |
155 | ```java
156 | visualRegressionTracker.track(
157 | "Name for test",
158 | screenshotBase64
159 | );
160 | ```
161 |
162 | With specific options
163 |
164 | ```java
165 | visualRegressionTracker.track(
166 | "Name for test",
167 | screenshotBase64,
168 | TestRunOptions.builder()
169 | .browser("Chrome")
170 | .os("Windows")
171 | .viewport("1200x800")
172 | .diffTollerancePercent(3.0f)
173 | .build()
174 | );
175 | ```
176 |
177 |
178 | ### Stop `VisualRegressionTracker`
179 |
180 | ```java
181 | visualRegressionTracker.stop();
182 | ```
183 |
184 | Should be called once current build should be considered as completed.
185 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | group 'io.visual-regression-tracker.sdk-java'
2 | version '4.3.1'
3 |
4 | apply plugin: 'java'
5 | apply plugin: 'jacoco'
6 | apply plugin: "io.freefair.lombok"
7 | apply plugin: "com.github.johnrengelman.shadow"
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | buildscript {
14 | repositories {
15 | maven {
16 | url "https://plugins.gradle.org/m2/"
17 | }
18 |
19 | }
20 | dependencies {
21 | classpath "io.freefair.gradle:lombok-plugin:5.1.1"
22 | classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0"
23 | }
24 | }
25 |
26 | dependencies {
27 | implementation 'com.google.code.gson:gson:2.9.0'
28 | implementation 'org.slf4j:slf4j-api:1.7.25'
29 | testImplementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.5.16'
30 | testImplementation group: 'org.testng', name: 'testng', version: '7.7.0'
31 | testImplementation 'commons-io:commons-io:2.18.0'
32 | testImplementation 'org.mockito:mockito-core:4.4.0'
33 | testImplementation 'com.squareup.okhttp3:mockwebserver:4.11.0'
34 | testImplementation 'uk.org.webcompere:system-stubs-testng:2.1.3'
35 | }
36 |
37 | test {
38 | useTestNG()
39 | }
40 |
41 | // codecov integration https://github.com/codecov/example-gradle
42 | jacocoTestReport {
43 | reports {
44 | xml.enabled true
45 | html.enabled true
46 | }
47 | }
48 |
49 | check.dependsOn jacocoTestReport
50 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Visual-Regression-Tracker/sdk-java/833f16a72ec498b57be63cb2b14e2ef38eba91e0/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat May 09 22:38:23 CEST 2020
2 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1-all.zip
3 | distributionBase=GRADLE_USER_HOME
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 | # Determine the Java command to use to start the JVM.
86 | if [ -n "$JAVA_HOME" ] ; then
87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
88 | # IBM's JDK on AIX uses strange locations for the executables
89 | JAVACMD="$JAVA_HOME/jre/sh/java"
90 | else
91 | JAVACMD="$JAVA_HOME/bin/java"
92 | fi
93 | if [ ! -x "$JAVACMD" ] ; then
94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
95 |
96 | Please set the JAVA_HOME variable in your environment to match the
97 | location of your Java installation."
98 | fi
99 | else
100 | JAVACMD="java"
101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
102 |
103 | Please set the JAVA_HOME variable in your environment to match the
104 | location of your Java installation."
105 | fi
106 |
107 | # Increase the maximum file descriptors if we can.
108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
109 | MAX_FD_LIMIT=`ulimit -H -n`
110 | if [ $? -eq 0 ] ; then
111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
112 | MAX_FD="$MAX_FD_LIMIT"
113 | fi
114 | ulimit -n $MAX_FD
115 | if [ $? -ne 0 ] ; then
116 | warn "Could not set maximum file descriptor limit: $MAX_FD"
117 | fi
118 | else
119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
120 | fi
121 | fi
122 |
123 | # For Darwin, add options to specify how the application appears in the dock
124 | if $darwin; then
125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
126 | fi
127 |
128 | # For Cygwin or MSYS, switch paths to Windows format before running java
129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
132 | JAVACMD=`cygpath --unix "$JAVACMD"`
133 |
134 | # We build the pattern for arguments to be converted via cygpath
135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
136 | SEP=""
137 | for dir in $ROOTDIRSRAW ; do
138 | ROOTDIRS="$ROOTDIRS$SEP$dir"
139 | SEP="|"
140 | done
141 | OURCYGPATTERN="(^($ROOTDIRS))"
142 | # Add a user-defined pattern to the cygpath arguments
143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
145 | fi
146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
147 | i=0
148 | for arg in "$@" ; do
149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
151 |
152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
154 | else
155 | eval `echo args$i`="\"$arg\""
156 | fi
157 | i=`expr $i + 1`
158 | done
159 | case $i in
160 | 0) set -- ;;
161 | 1) set -- "$args0" ;;
162 | 2) set -- "$args0" "$args1" ;;
163 | 3) set -- "$args0" "$args1" "$args2" ;;
164 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
165 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
166 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
167 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
168 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
169 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
170 | esac
171 | fi
172 |
173 | # Escape application args
174 | save () {
175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
176 | echo " "
177 | }
178 | APP_ARGS=`save "$@"`
179 |
180 | # Collect all arguments for the java command, following the shell quoting and substitution rules
181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
182 |
183 | exec "$JAVACMD" "$@"
184 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
34 |
35 | @rem Find java.exe
36 | if defined JAVA_HOME goto findJavaFromJavaHome
37 |
38 | set JAVA_EXE=java.exe
39 | %JAVA_EXE% -version >NUL 2>&1
40 | if "%ERRORLEVEL%" == "0" goto init
41 |
42 | echo.
43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
44 | echo.
45 | echo Please set the JAVA_HOME variable in your environment to match the
46 | echo location of your Java installation.
47 |
48 | goto fail
49 |
50 | :findJavaFromJavaHome
51 | set JAVA_HOME=%JAVA_HOME:"=%
52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
53 |
54 | if exist "%JAVA_EXE%" goto init
55 |
56 | echo.
57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
58 | echo.
59 | echo Please set the JAVA_HOME variable in your environment to match the
60 | echo location of your Java installation.
61 |
62 | goto fail
63 |
64 | :init
65 | @rem Get command-line arguments, handling Windows variants
66 |
67 | if not "%OS%" == "Windows_NT" goto win9xME_args
68 |
69 | :win9xME_args
70 | @rem Slurp the command line arguments.
71 | set CMD_LINE_ARGS=
72 | set _SKIP=2
73 |
74 | :win9xME_args_slurp
75 | if "x%~1" == "x" goto execute
76 |
77 | set CMD_LINE_ARGS=%*
78 |
79 | :execute
80 | @rem Setup the command line
81 |
82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
83 |
84 | @rem Execute Gradle
85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
86 |
87 | :end
88 | @rem End local scope for the variables with windows NT shell
89 | if "%ERRORLEVEL%"=="0" goto mainEnd
90 |
91 | :fail
92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
93 | rem the _cmd.exe /c_ return code!
94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
95 | exit /b 1
96 |
97 | :mainEnd
98 | if "%OS%"=="Windows_NT" endlocal
99 |
100 | :omega
101 |
--------------------------------------------------------------------------------
/jitpack.yml:
--------------------------------------------------------------------------------
1 | jdk:
2 | - openjdk11
--------------------------------------------------------------------------------
/lombok.config:
--------------------------------------------------------------------------------
1 | # This file is generated by the 'io.freefair.lombok' Gradle plugin
2 | config.stopBubbling = true
3 | lombok.addLombokGeneratedAnnotation = true
4 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'visual-regression-tracker-sdk-java'
2 |
3 |
--------------------------------------------------------------------------------
/src/main/java/io/visual_regression_tracker/sdk_java/IgnoreAreas.java:
--------------------------------------------------------------------------------
1 | package io.visual_regression_tracker.sdk_java;
2 |
3 | import lombok.Builder;
4 | import lombok.Data;
5 |
6 | @Builder
7 | @Data
8 | public class IgnoreAreas {
9 |
10 | private final Long x;
11 | private final Long y;
12 | private final Long width;
13 | private final Long height;
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/io/visual_regression_tracker/sdk_java/PathProvider.java:
--------------------------------------------------------------------------------
1 | package io.visual_regression_tracker.sdk_java;
2 |
3 | import lombok.AllArgsConstructor;
4 |
5 | @AllArgsConstructor
6 | public class PathProvider {
7 |
8 | private static final String BUILD_PATH = "/builds";
9 | private static final String TEST_RUNS_PATH = "/test-runs";
10 |
11 | private final String baseApiUrl;
12 |
13 | public String getBuildPath() {
14 | return baseApiUrl.concat(BUILD_PATH);
15 | }
16 |
17 | public String getBuildPathForBuild(String buildId) {
18 | return getBuildPath().concat("/").concat(buildId);
19 | }
20 |
21 | public String getTestRunPath() {
22 | return baseApiUrl.concat(TEST_RUNS_PATH);
23 | }
24 |
25 | public String getImageUrl(String name) {
26 | if(name == null || name.isEmpty()){
27 | return null;
28 | }
29 | return baseApiUrl.concat("/").concat(name);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/io/visual_regression_tracker/sdk_java/TestRunException.java:
--------------------------------------------------------------------------------
1 | package io.visual_regression_tracker.sdk_java;
2 |
3 | public class TestRunException extends RuntimeException {
4 | public TestRunException(String errorMessage) {
5 | super(errorMessage);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/io/visual_regression_tracker/sdk_java/TestRunOptions.java:
--------------------------------------------------------------------------------
1 | package io.visual_regression_tracker.sdk_java;
2 |
3 | import java.util.List;
4 |
5 | import lombok.Builder;
6 | import lombok.Getter;
7 |
8 | @Builder
9 | @Getter
10 | public class TestRunOptions {
11 | private final String os;
12 | private final String browser;
13 | private final String viewport;
14 | private final String device;
15 | private final String customTags;
16 | private final Float diffTollerancePercent;
17 | private final List ignoreAreas;
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/io/visual_regression_tracker/sdk_java/TestRunResult.java:
--------------------------------------------------------------------------------
1 | package io.visual_regression_tracker.sdk_java;
2 |
3 | import io.visual_regression_tracker.sdk_java.response.TestRunResponse;
4 | import lombok.Getter;
5 |
6 | @Getter
7 | public class TestRunResult {
8 | private final TestRunResponse testRunResponse;
9 | private final String imageUrl;
10 | private final String diffUrl;
11 | private final String baselineUrl;
12 |
13 | public TestRunResult(TestRunResponse testRunResponse, PathProvider pathProvider) {
14 | this.testRunResponse = testRunResponse;
15 | this.imageUrl = pathProvider.getImageUrl(testRunResponse.getImageName());
16 | this.diffUrl = pathProvider.getImageUrl(testRunResponse.getDiffName());
17 | this.baselineUrl = pathProvider.getImageUrl(testRunResponse.getBaselineName());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/io/visual_regression_tracker/sdk_java/TestRunStatus.java:
--------------------------------------------------------------------------------
1 | package io.visual_regression_tracker.sdk_java;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Getter;
6 |
7 | @Getter
8 | @AllArgsConstructor
9 | public enum TestRunStatus {
10 | @SerializedName("ok")
11 | OK,
12 | @SerializedName("approved")
13 | APPROVED,
14 | @SerializedName("autoApproved")
15 | AUTO_APPROVED,
16 | @SerializedName("failed")
17 | FAILED,
18 | @SerializedName("new")
19 | NEW,
20 | @SerializedName("unresolved")
21 | UNRESOLVED
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/io/visual_regression_tracker/sdk_java/VisualRegressionTracker.java:
--------------------------------------------------------------------------------
1 | package io.visual_regression_tracker.sdk_java;
2 |
3 | import com.google.gson.Gson;
4 | import io.visual_regression_tracker.sdk_java.request.BuildRequest;
5 | import io.visual_regression_tracker.sdk_java.request.TestRunRequest;
6 | import io.visual_regression_tracker.sdk_java.response.BuildResponse;
7 | import io.visual_regression_tracker.sdk_java.response.TestRunResponse;
8 | import lombok.extern.slf4j.Slf4j;
9 |
10 | import java.io.File;
11 | import java.io.IOException;
12 | import java.net.URI;
13 | import java.net.http.HttpClient;
14 | import java.net.http.HttpRequest;
15 | import java.net.http.HttpResponse;
16 | import java.time.Duration;
17 |
18 | enum METHOD {
19 | GET,
20 | POST,
21 | PATCH
22 | }
23 |
24 | @Slf4j
25 | public class VisualRegressionTracker {
26 |
27 | private static final String TRACKER_NOT_STARTED = "Visual Regression Tracker has not been started";
28 | private static final String CONFIG_FILE_NAME = "vrt.json";
29 | protected static final String API_KEY_HEADER = "apiKey";
30 | protected static final String PROJECT_HEADER = "project";
31 | protected Gson gson;
32 | protected VisualRegressionTrackerConfig configuration;
33 | protected PathProvider paths;
34 | protected String buildId;
35 | protected String projectId;
36 |
37 | public VisualRegressionTracker() {
38 | VisualRegressionTrackerConfig.VisualRegressionTrackerConfigBuilder configBuilder = VisualRegressionTrackerConfig.builder();
39 | File configFile = new File(CONFIG_FILE_NAME);
40 | if (configFile.exists()) {
41 | configBuilder.configFile(configFile);
42 | }
43 | configuration = configBuilder.build();
44 | paths = new PathProvider(configuration.getApiUrl());
45 | gson = new Gson();
46 | }
47 |
48 | public VisualRegressionTracker(VisualRegressionTrackerConfig trackerConfig) {
49 | configuration = trackerConfig;
50 | paths = new PathProvider(trackerConfig.getApiUrl());
51 | gson = new Gson();
52 | }
53 |
54 | public BuildResponse start() throws IOException, InterruptedException {
55 | String projectName = configuration.getProject();
56 | String branch = configuration.getBranchName();
57 | String ciBuildId = configuration.getCiBuildId();
58 |
59 | BuildRequest newBuild = BuildRequest.builder()
60 | .branchName(branch)
61 | .project(projectName)
62 | .ciBuildId(ciBuildId)
63 | .build();
64 | log.info("Starting Visual Regression Tracker for project <{}> and branch <{}>", projectName, branch);
65 | HttpRequest.BodyPublisher body = HttpRequest.BodyPublishers.ofString(gson.toJson(newBuild));
66 | HttpResponse response = getResponse(METHOD.POST, paths.getBuildPath(), body);
67 | BuildResponse buildResponse = handleResponse(response, BuildResponse.class);
68 |
69 | buildId = buildResponse.getId();
70 | projectId = buildResponse.getProjectId();
71 |
72 | log.info("Visual Regression Tracker is started for project <{}>: projectId: <{}>, buildId: <{}>, ciBuildId: <{}>",
73 | projectName, projectId, buildId, buildResponse.getCiBuildId());
74 | return buildResponse;
75 | }
76 |
77 | public BuildResponse stop() throws IOException, InterruptedException {
78 | if (!isStarted()) {
79 | throw new TestRunException(TRACKER_NOT_STARTED);
80 | }
81 |
82 | log.info("Stopping Visual Regression Tracker for buildId <{}>", buildId);
83 |
84 | HttpRequest.BodyPublisher body = HttpRequest.BodyPublishers.ofString("");
85 | HttpResponse response = getResponse(METHOD.PATCH, paths.getBuildPathForBuild(buildId), body);
86 | BuildResponse vrtStopResponse = handleResponse(response, BuildResponse.class);
87 |
88 | log.info("Visual Regression Tracker is stopped for buildId <{}>", buildId);
89 | return vrtStopResponse;
90 | }
91 |
92 | public TestRunResult track(String name, String imageBase64, TestRunOptions testRunOptions)
93 | throws IOException, InterruptedException {
94 | log.info("Tracking test run <{}> with options <{}> for buildId <{}>", name, testRunOptions, buildId);
95 | TestRunResponse testResultDTO = submitTestRun(name, imageBase64, testRunOptions);
96 |
97 | String errorMessage;
98 | switch (testResultDTO.getStatus()) {
99 | case NEW:
100 | errorMessage = "No baseline: ".concat(testResultDTO.getUrl());
101 | break;
102 | case UNRESOLVED:
103 | errorMessage = "Difference found: ".concat(testResultDTO.getUrl());
104 | break;
105 | default:
106 | errorMessage = "";
107 | break;
108 | }
109 |
110 | if (!errorMessage.isEmpty()) {
111 | if (configuration.getEnableSoftAssert()) {
112 | log.error(errorMessage);
113 | } else {
114 | throw new TestRunException(errorMessage);
115 | }
116 | }
117 |
118 | return new TestRunResult(testResultDTO, this.paths);
119 | }
120 |
121 | public TestRunResult track(String name, String imageBase64) throws IOException, InterruptedException {
122 | return track(name, imageBase64, TestRunOptions.builder().build());
123 | }
124 |
125 | protected boolean isStarted() {
126 | return buildId != null && projectId != null;
127 | }
128 |
129 | protected TestRunResponse submitTestRun(String name, String imageBase64,
130 | TestRunOptions testRunOptions) throws IOException, InterruptedException {
131 | if (!isStarted()) {
132 | throw new TestRunException(TRACKER_NOT_STARTED);
133 | }
134 |
135 | TestRunRequest newTestRun = TestRunRequest.builder()
136 | .projectId(projectId)
137 | .buildId(buildId)
138 | .branchName(configuration.getBranchName())
139 | .name(name)
140 | .imageBase64(imageBase64)
141 | .os(testRunOptions.getOs())
142 | .browser(testRunOptions.getBrowser())
143 | .viewport(testRunOptions.getViewport())
144 | .device(testRunOptions.getDevice())
145 | .customTags(testRunOptions.getCustomTags())
146 | .diffTollerancePercent(testRunOptions.getDiffTollerancePercent())
147 | .ignoreAreas(testRunOptions.getIgnoreAreas())
148 | .build();
149 |
150 | HttpRequest.BodyPublisher body = HttpRequest.BodyPublishers.ofString(gson.toJson(newTestRun));
151 | HttpResponse response = getResponse(METHOD.POST, paths.getTestRunPath(), body);
152 | return handleResponse(response, TestRunResponse.class);
153 | }
154 |
155 | private HttpResponse getResponse(METHOD method, String url, HttpRequest.BodyPublisher body) throws IOException, InterruptedException {
156 | HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
157 | .timeout(Duration.ofSeconds(configuration.getHttpTimeoutInSeconds()))
158 | .header(API_KEY_HEADER, configuration.getApiKey())
159 | .header(PROJECT_HEADER, configuration.getProject())
160 | .header("Content-Type", "application/json;charset=UTF-8")
161 | .uri(URI.create(url));
162 | HttpRequest request = getRequest(method, body, requestBuilder);
163 | HttpResponse response = HttpClient.newBuilder()
164 | .version(HttpClient.Version.HTTP_1_1)
165 | .connectTimeout(Duration.ofSeconds(configuration.getHttpTimeoutInSeconds()))
166 | .build()
167 | .send(request, HttpResponse.BodyHandlers.ofString());
168 | return response;
169 | }
170 |
171 | protected HttpRequest getRequest(METHOD method, HttpRequest.BodyPublisher body, HttpRequest.Builder requestBuilder) {
172 | switch (method) {
173 | case PATCH:
174 | return requestBuilder.method("PATCH", body).build();
175 | case POST:
176 | return requestBuilder.POST(body).build();
177 | default:
178 | throw new UnsupportedOperationException("This method is not yet supported.");
179 | }
180 | }
181 |
182 | protected T handleResponse(HttpResponse response, Class classOfT) {
183 | String responseBody = response.body();
184 | if (!String.valueOf(response.statusCode()).startsWith("2")) {
185 | throw new TestRunException(responseBody);
186 | }
187 | return gson.fromJson(responseBody, classOfT);
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/src/main/java/io/visual_regression_tracker/sdk_java/VisualRegressionTrackerConfig.java:
--------------------------------------------------------------------------------
1 | package io.visual_regression_tracker.sdk_java;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.reflect.TypeToken;
5 | import lombok.*;
6 | import lombok.experimental.Accessors;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | import java.io.File;
10 | import java.io.IOException;
11 | import java.lang.reflect.Field;
12 | import java.lang.reflect.Type;
13 | import java.nio.charset.StandardCharsets;
14 | import java.nio.file.Files;
15 | import java.util.Collections;
16 | import java.util.Map;
17 | import java.util.function.Function;
18 |
19 | @Data()
20 | @RequiredArgsConstructor
21 | @AllArgsConstructor
22 | @Accessors(chain = true)
23 | @Slf4j
24 | public class VisualRegressionTrackerConfig {
25 |
26 | @NonNull
27 | private final String apiUrl;
28 | @NonNull
29 | private final String apiKey;
30 | @NonNull
31 | private final String project;
32 |
33 | private String branchName;
34 | private String ciBuildId;
35 | private Boolean enableSoftAssert;
36 | private int httpTimeoutInSeconds;
37 |
38 | public static VisualRegressionTrackerConfigBuilder builder() {
39 | return new VisualRegressionTrackerConfigBuilder();
40 | }
41 |
42 | public static class VisualRegressionTrackerConfigBuilder {
43 | private String apiUrl;
44 | private String apiKey;
45 | private String project;
46 |
47 | private String branchName;
48 | private String ciBuildId;
49 | private Boolean enableSoftAssert;
50 | private Integer httpTimeoutInSeconds;
51 |
52 | private File configFile;
53 |
54 | private static final String VRT_ENV_VARIABLE_PREFIX = "VRT_";
55 | private static final boolean DEFAULT_SOFT_ASSERTION_STATE = false;
56 | private static final int DEFAULT_HTTP_TIMEOUT_SECONDS = 10;
57 |
58 | public VisualRegressionTrackerConfigBuilder apiUrl(String apiUrl) {
59 | this.apiUrl = apiUrl;
60 | return this;
61 | }
62 |
63 | public VisualRegressionTrackerConfigBuilder apiKey(String apiKey) {
64 | this.apiKey = apiKey;
65 | return this;
66 | }
67 |
68 | public VisualRegressionTrackerConfigBuilder project(String project) {
69 | this.project = project;
70 | return this;
71 | }
72 |
73 | public VisualRegressionTrackerConfigBuilder branchName(String branchName) {
74 | this.branchName = branchName;
75 | return this;
76 | }
77 |
78 | public VisualRegressionTrackerConfigBuilder ciBuildId(String ciBuildId) {
79 | this.ciBuildId = ciBuildId;
80 | return this;
81 | }
82 |
83 | public VisualRegressionTrackerConfigBuilder enableSoftAssert(Boolean enableSoftAssert) {
84 | this.enableSoftAssert = enableSoftAssert;
85 | return this;
86 | }
87 |
88 | public VisualRegressionTrackerConfigBuilder httpTimeoutInSeconds(int httpTimeoutInSeconds) {
89 | this.httpTimeoutInSeconds = httpTimeoutInSeconds;
90 | return this;
91 | }
92 |
93 | public VisualRegressionTrackerConfigBuilder configFile(File configFile) {
94 | this.configFile = configFile;
95 | return this;
96 | }
97 |
98 | public VisualRegressionTrackerConfig build() {
99 | Map configFromFile = Collections.emptyMap();
100 | if (configFile != null) {
101 | configFromFile = readConfigFromFile(configFile);
102 | }
103 |
104 | String actualApiUrl = resolve("apiUrl", configFromFile);
105 | String actualApiKey = resolve("apiKey", configFromFile);
106 | String actualProject = resolve("project", configFromFile);
107 |
108 | VisualRegressionTrackerConfig config = new VisualRegressionTrackerConfig(actualApiUrl, actualApiKey, actualProject);
109 | config.setCiBuildId(resolve("ciBuildId", configFromFile));
110 | config.setBranchName(resolve("branchName", configFromFile));
111 |
112 | Boolean actualEnableSoftAssert = resolve("enableSoftAssert", configFromFile);
113 | config.setEnableSoftAssert(actualEnableSoftAssert == null ? DEFAULT_SOFT_ASSERTION_STATE : actualEnableSoftAssert);
114 |
115 | Integer actualHttpTimeoutInSeconds = resolve("httpTimeoutInSeconds", configFromFile);
116 | config.setHttpTimeoutInSeconds(actualHttpTimeoutInSeconds == null ? DEFAULT_HTTP_TIMEOUT_SECONDS : actualHttpTimeoutInSeconds);
117 |
118 | return config;
119 | }
120 |
121 | private Map readConfigFromFile(File configFile) {
122 | if (!configFile.exists()) {
123 | throw new IllegalArgumentException("File " + configFile + " doesn't exist");
124 | }
125 |
126 | String fileContent;
127 | try {
128 | fileContent = Files.readString(configFile.toPath(), StandardCharsets.UTF_8);
129 | } catch (IOException e) {
130 | throw new IllegalArgumentException("Can't read content of provided config file", e);
131 | }
132 | Type mapType = new TypeToken