Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions .github/workflows/examples-fresh-clone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: Examples from a fresh clone

# Builds each product's console examples as AGENTS.md says, from a clone
# with its submodules, against the packages published on Maven Central, with
# the JDK and Maven the runner has. Then runs the getting started example
# from the repository root with no settings. A fresh clone holds only a link
# for each free data file. On Ubuntu the example downloads its file, which
# tests the download, and the job keeps the file in the cache. The other
# systems take it from there, so each file is downloaded once a run.

on:
pull_request:
paths:
- 'examples/**'
- 'cxx'
- '.github/workflows/examples-fresh-clone.yml'
- 'ci/run-fresh-clone-example.ps1'
push:
branches:
- main
- rc
schedule:
- cron: '30 4 * * *'
workflow_dispatch:

permissions:
contents: read

jobs:
download:
name: ${{ matrix.product }} on ubuntu-latest, downloading its data file
strategy:
fail-fast: false
matrix:
include:
- product: device-detection
example: fiftyone.devicedetection.examples.console.GettingStartedOnPrem
file: cxx/data/device-detection/51Degrees-LiteV4.1.hash
- product: ip-intelligence
example: fiftyone.ipintelligence.examples.console.GettingStartedOnPrem
file: cxx/data/ip-intelligence/51Degrees-LiteV41.ipi
runs-on: ubuntu-latest
steps:
- name: Clone the repository with its submodules
uses: actions/checkout@v4
with:
submodules: recursive
persist-credentials: false

- name: The runner's Java and Maven
shell: pwsh
run: |
java -version
mvn -v

- name: Build the console examples against the published packages
working-directory: examples/${{ matrix.product }}
shell: pwsh
run: mvn -B --no-transfer-progress -pl console -am package -DskipTests

- name: Run the getting started example from the repository root
shell: pwsh
run: >-
./ci/run-fresh-clone-example.ps1 -Product '${{ matrix.product }}'
-Example '${{ matrix.example }}' -ExpectDownload $true

# The key follows the link, so a new free file gets a new entry, and
# the same file is kept once rather than once a run.
- name: Keep the data file for the other systems
uses: actions/cache/save@v4
with:
path: ${{ matrix.file }}
key: fresh-clone-${{ matrix.product }}-${{ hashFiles(format('{0}.link', matrix.file)) }}
enableCrossOsArchive: true

other-systems:
name: ${{ matrix.product }} on ${{ matrix.os }}
needs: download
strategy:
fail-fast: false
matrix:
# macOS runners are shared by the whole organisation, so pull
# requests leave them out and the pushes and the daily run use them.
os: ${{ fromJSON(github.event_name == 'pull_request' && '["windows-latest"]' || '["windows-latest", "macos-latest"]') }}
product: [device-detection, ip-intelligence]
include:
- product: device-detection
example: fiftyone.devicedetection.examples.console.GettingStartedOnPrem
file: cxx/data/device-detection/51Degrees-LiteV4.1.hash
- product: ip-intelligence
example: fiftyone.ipintelligence.examples.console.GettingStartedOnPrem
file: cxx/data/ip-intelligence/51Degrees-LiteV41.ipi
runs-on: ${{ matrix.os }}
steps:
- name: Clone the repository with its submodules
uses: actions/checkout@v4
with:
submodules: recursive
persist-credentials: false

- name: Take the data file the Ubuntu job downloaded
uses: actions/cache/restore@v4
with:
path: ${{ matrix.file }}
key: fresh-clone-${{ matrix.product }}-${{ hashFiles(format('{0}.link', matrix.file)) }}
enableCrossOsArchive: true
fail-on-cache-miss: true

- name: The runner's Java and Maven
shell: pwsh
run: |
java -version
mvn -v

- name: Build the console examples against the published packages
working-directory: examples/${{ matrix.product }}
shell: pwsh
run: mvn -B --no-transfer-progress -pl console -am package -DskipTests

- name: Run the getting started example from the repository root
shell: pwsh
run: >-
./ci/run-fresh-clone-example.ps1 -Product '${{ matrix.product }}'
-Example '${{ matrix.example }}' -ExpectDownload $false
24 changes: 17 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ the native engines from `cxx` and does need them, as the README says.
### Prerequisites

- Git.
- A JDK, 8 or later. CI tests 8, 11, 17 and 21 (`ci/options.json`).
- A JDK, 8 or later. CI tests 8, 11, 17 and 21 (`ci/options.json`), and
builds and runs the examples on the JDK each runner has (see
[What CI tests](#pitfalls)).
- Maven 3.8 or later, or the `mvnw` wrapper at the root.
- Network access to GitHub, to Maven Central for the packages the examples
use, and to `distributor.51degrees.com` for the data files.
Expand Down Expand Up @@ -215,12 +217,20 @@ example. The IP Intelligence cloud examples read their key from
for Windows x64 and x86, Linux x64 and aarch64, and macOS x64 and aarch64.
The `ip-intelligence.engine.on-premise` 4.5.128 jar has the same, without
Windows x86. On a platform a jar lacks, the example cannot load the engine.
- **What CI does not test.** On a pull request CI builds and tests the
examples with the `dev` profile (`ci/build-project.ps1` and
`ci/run-unit-tests.ps1`), and against the published packages only when it
publishes (`ci/run-integration-tests.ps1`). It never runs the console
example jars as above, and the example tests use the paid data files when
CI has them.
- **What CI tests.** On a pull request CI builds and tests the examples
with the `dev` profile (`ci/build-project.ps1` and
`ci/run-unit-tests.ps1`), and the example tests use the paid data files
when CI has them. Publish tests them against the packages it has just
built (`ci/run-integration-tests.ps1`).
[examples-fresh-clone.yml](.github/workflows/examples-fresh-clone.yml)
does what [Run the examples](#run-the-examples) says, with the JDK and
Maven each runner has. It
builds the console examples against the published packages and runs each
product's `GettingStartedOnPrem` jar from the repository root with no
settings. On Ubuntu the free data file is downloaded, as from a fresh
clone, and the Windows and macOS jobs take that file from the run's cache,
so each file is downloaded once a run. It runs on each push to `main` and
`rc`, daily, and on a pull request that changes the examples.

## Environment variable names

Expand Down
8 changes: 8 additions & 0 deletions ci/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ repositories used to do for one package tree each.
of cxx. No test job downloads a data file, so a file added to the data
repository needs an entry in common-ci's `steps/fetch-assets.ps1` before CI
can use it.
- [run-fresh-clone-example.ps1](run-fresh-clone-example.ps1) runs a
product's console example jar from the repository root for
[examples-fresh-clone.yml](../.github/workflows/examples-fresh-clone.yml).
It fails unless the example exits with 0 and prints results, and unless it
downloads its free data file exactly when the job expects it to. That
workflow's Ubuntu job downloads each product's free data file once a run,
as a test of the download, and its other jobs take the file from the cache
the Ubuntu job saves.
- [run-performance-tests.ps1](run-performance-tests.ps1) measures the Pipeline
API, Device Detection and IP Intelligence and writes one results file per
configuration. The Device Detection and IP Intelligence metrics are prefixed
Expand Down
44 changes: 44 additions & 0 deletions ci/run-fresh-clone-example.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
param (
[Parameter(Mandatory)][string]$Product,
[Parameter(Mandatory)][string]$Example,
# True where the clone holds only the data file's link, so the example
# has to download the file. False where the file is already in place.
[Parameter(Mandatory)][bool]$ExpectDownload
)

# Runs a product's console example jar from the repository root with no
# settings, as AGENTS.md's "Run the examples" does, and fails unless it ends
# with exit code 0, prints results, and downloads its data file exactly when
# expected.

$jar = Get-ChildItem "examples/$Product/console/target" `
-Filter '*-jar-with-dependencies.jar' | Select-Object -First 1
if ($null -eq $jar) {
Write-Output '::error::The build made no jar with dependencies.'
exit 1
}
$output = & java -cp $jar.FullName $Example 2>&1 | ForEach-Object { "$_" }
$code = $LASTEXITCODE
$output
$text = $output -join "`n"
$failed = $false
if ($code -ne 0) {
Write-Output "::error::The example exited with $code."
$failed = $true
}
$downloaded = $text -match 'is missing, so it is being downloaded'
if ($ExpectDownload -and -not $downloaded) {
Write-Output '::error::The example did not download its free data file.'
$failed = $true
}
if (-not $ExpectDownload -and $downloaded) {
Write-Output '::error::The example downloaded its data file, which should have come from the cache.'
$failed = $true
}
if ($text -notmatch 'Results:') {
Write-Output '::error::The example printed no results.'
$failed = $true
}
if ($failed) {
exit 1
}
2 changes: 1 addition & 1 deletion examples/device-detection/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@

<slf4j-api.version>2.0.20</slf4j-api.version>
<logback-classic.version>1.3.16</logback-classic.version>
<maven-pmd-plugin.version>3.26.0</maven-pmd-plugin.version>
<maven-pmd-plugin.version>3.28.0</maven-pmd-plugin.version>
</properties>

<profiles>
Expand Down
2 changes: 1 addition & 1 deletion examples/ip-intelligence/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@

<slf4j-api.version>2.0.20</slf4j-api.version>
<logback-classic.version>1.3.16</logback-classic.version>
<maven-pmd-plugin.version>3.26.0</maven-pmd-plugin.version>
<maven-pmd-plugin.version>3.28.0</maven-pmd-plugin.version>
</properties>

<profiles>
Expand Down
Loading