From 7004a8ef0535f87da31a7cfaef1d65148f832cca Mon Sep 17 00:00:00 2001 From: Reneta Popova Date: Wed, 5 Feb 2025 13:43:05 +0000 Subject: [PATCH 01/48] bump version to 2025.02 (#248) --- antora.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/antora.yml b/antora.yml index f421dcb..3dd9b86 100644 --- a/antora.yml +++ b/antora.yml @@ -6,9 +6,9 @@ nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2025.01' - neo4j-version-exact: '2025.01.0' - neo4j-buildnumber: '2025.01' + neo4j-version: '2025.02' + neo4j-version-exact: '2025.02.0' + neo4j-buildnumber: '2025.02' java-driver-version: '5.27' neo4j-documentation-branch: 'dev' page-origin-private: false From 42a163bce24d140ccb40f9e7ff1fedc8efe4cab4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 17:31:36 +0000 Subject: [PATCH 02/48] Bump @neo4j-antora/antora-modify-sitemaps in the prod-dependencies group (#249) Bumps the prod-dependencies group with 1 update: @neo4j-antora/antora-modify-sitemaps. Updates `@neo4j-antora/antora-modify-sitemaps` from 0.6.1 to 0.7.0 --- updated-dependencies: - dependency-name: "@neo4j-antora/antora-modify-sitemaps" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f0bb961..1a4bf63 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "antora": "^3.1.10", "@neo4j-antora/antora-add-notes": "^0.3.1", "@neo4j-antora/antora-listing-roles": "^0.1.0", - "@neo4j-antora/antora-modify-sitemaps": "^0.6.0", + "@neo4j-antora/antora-modify-sitemaps": "^0.7.0", "@neo4j-antora/antora-table-footnotes": "^0.3.2", "@neo4j-antora/selector-labels": "^0.1.1", "@neo4j-documentation/macros": "^1.0.2", From f9f20001c5eb98ad7069c09123d62b75f883187b Mon Sep 17 00:00:00 2001 From: Reneta Popova Date: Thu, 27 Feb 2025 18:00:34 +0000 Subject: [PATCH 03/48] Update dev version to 2025.03 (#252) --- antora.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/antora.yml b/antora.yml index 3dd9b86..a6cfaeb 100644 --- a/antora.yml +++ b/antora.yml @@ -6,9 +6,9 @@ nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2025.02' - neo4j-version-exact: '2025.02.0' - neo4j-buildnumber: '2025.02' + neo4j-version: '2025.03' + neo4j-version-exact: '2025.03.0' + neo4j-buildnumber: '2025.03' java-driver-version: '5.27' neo4j-documentation-branch: 'dev' page-origin-private: false From 00efb64f61d6bd1f644f952df4a77cfbc79902f5 Mon Sep 17 00:00:00 2001 From: Neil Dewhurst Date: Fri, 28 Feb 2025 09:40:40 +0000 Subject: [PATCH 04/48] Update version in antora.yml to 2025.03 (#254) --- antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/antora.yml b/antora.yml index a6cfaeb..aa229a5 100644 --- a/antora.yml +++ b/antora.yml @@ -1,6 +1,6 @@ name: java-reference title: Java Reference -version: '2025.01' +version: '2025.03' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc From dd72fcf6905b18c6a3c968f08d31c1b06fd124a4 Mon Sep 17 00:00:00 2001 From: NataliaIvakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Wed, 12 Mar 2025 13:27:52 +0100 Subject: [PATCH 05/48] Update Java driver version to 5.28.3 (#258) --- antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/antora.yml b/antora.yml index aa229a5..9b1fca4 100644 --- a/antora.yml +++ b/antora.yml @@ -9,7 +9,7 @@ asciidoc: neo4j-version: '2025.03' neo4j-version-exact: '2025.03.0' neo4j-buildnumber: '2025.03' - java-driver-version: '5.27' + java-driver-version: '5.28.3' neo4j-documentation-branch: 'dev' page-origin-private: false neo4j-javadocs-base-uri: "https://neo4j.com/docs/java-reference/5/javadocs" From 6910e99ed9dd99c8f12deb4511d6922f08dbf32c Mon Sep 17 00:00:00 2001 From: Neil Dewhurst Date: Fri, 14 Mar 2025 13:39:16 +0000 Subject: [PATCH 06/48] Packages workflows refine (#261) * update workflow to 1.2.0 * update packages --- .github/workflows/docs-pr-checks.yml | 6 +++--- package.json | 11 +++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/docs-pr-checks.yml b/.github/workflows/docs-pr-checks.yml index 7c85c7c..a896369 100644 --- a/.github/workflows/docs-pr-checks.yml +++ b/.github/workflows/docs-pr-checks.yml @@ -13,7 +13,7 @@ jobs: # Generate HTML docs-build-pr: - uses: neo4j/docs-tools/.github/workflows/reusable-docs-build.yml@v1.1.2 + uses: neo4j/docs-tools/.github/workflows/reusable-docs-build.yml@v1.2.0 with: deploy-id: ${{ github.event.number }} retain-artifacts: 14 @@ -23,7 +23,7 @@ jobs: # By default, the job fails if there are errors, passes if there are warnings only. docs-verify-pr: needs: docs-build-pr - uses: neo4j/docs-tools/.github/workflows/reusable-docs-verify.yml@v1.1.2 + uses: neo4j/docs-tools/.github/workflows/reusable-docs-verify.yml@v1.2.0 with: failOnWarnings: true @@ -55,7 +55,7 @@ jobs: docs-updates-comment-pr: if: needs.docs-build-pr.outputs.pages-listed == 'success' needs: [docs-build-pr, docs-changes-pr] - uses: neo4j/docs-tools/.github/workflows/reusable-docs-pr-changes.yml@v1.1.2 + uses: neo4j/docs-tools/.github/workflows/reusable-docs-pr-changes.yml@v1.2.0 with: pages-modified: ${{ needs.docs-changes-pr.outputs.pages-modified }} pages-added: ${{ needs.docs-changes-pr.outputs.pages-added }} diff --git a/package.json b/package.json index 1a4bf63..2222a84 100644 --- a/package.json +++ b/package.json @@ -23,14 +23,13 @@ }, "homepage": "https://github.com/neo4j/docs-java-reference#readme", "dependencies": { - "antora": "^3.1.10", - "@neo4j-antora/antora-add-notes": "^0.3.1", + "@neo4j-antora/antora-add-notes": "^0.3.2", "@neo4j-antora/antora-listing-roles": "^0.1.0", - "@neo4j-antora/antora-modify-sitemaps": "^0.7.0", - "@neo4j-antora/antora-table-footnotes": "^0.3.2", + "@neo4j-antora/antora-table-footnotes": "^0.3.3", "@neo4j-antora/selector-labels": "^0.1.1", - "@neo4j-documentation/macros": "^1.0.2", - "@neo4j-documentation/remote-include": "^1.0.0" + "@neo4j-documentation/macros": "^1.0.4", + "@neo4j-documentation/remote-include": "^1.0.0", + "antora": "^3.1.10" }, "devDependencies": { "express": "^5.0.1", From aac58bbfb1cdfec336ce7974eb52c045163b88b6 Mon Sep 17 00:00:00 2001 From: NataliaIvakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Thu, 20 Mar 2025 15:29:22 +0100 Subject: [PATCH 07/48] Replace `page-version` with `current` in links (#260) * Replace `page-version` with `current` in links * Put back `page-version` for the Ops manual and fix links on locks/deadlocks * Update modules/ROOT/pages/java-embedded/unique-nodes.adoc * Update modules/ROOT/pages/extending-neo4j/unmanaged-extensions.adoc --- modules/ROOT/pages/extending-neo4j/customized-code.adoc | 4 ++-- modules/ROOT/pages/extending-neo4j/procedures.adoc | 2 +- modules/ROOT/pages/extending-neo4j/unmanaged-extensions.adoc | 2 +- modules/ROOT/pages/extending-neo4j/values-and-types.adoc | 2 +- modules/ROOT/pages/java-embedded/cypher-java.adoc | 4 ++-- modules/ROOT/pages/java-embedded/indexes.adoc | 4 ++-- modules/ROOT/pages/java-embedded/property-values.adoc | 2 +- modules/ROOT/pages/java-embedded/query-parameters.adoc | 2 +- modules/ROOT/pages/java-embedded/unique-nodes.adoc | 2 +- modules/ROOT/pages/transaction-management.adoc | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/modules/ROOT/pages/extending-neo4j/customized-code.adoc b/modules/ROOT/pages/extending-neo4j/customized-code.adoc index 184dccf..c4b44c5 100644 --- a/modules/ROOT/pages/extending-neo4j/customized-code.adoc +++ b/modules/ROOT/pages/extending-neo4j/customized-code.adoc @@ -53,9 +53,9 @@ In addition, procedures can perform write operations on the database. Neo4j also comes bundled with a number of _built-in_ procedures and functions. -The available built-in procedures vary depending on edition and mode, as described in link:{neo4j-docs-base-uri}/operations-manual/{page-version}/reference/procedures[Operations Manual -> Procedures]. +The available built-in procedures vary depending on edition and mode, as described in link:{neo4j-docs-base-uri}/operations-manual/{page-version}/procedures[Operations Manual -> Procedures]. Running `SHOW PROCEDURES` displays the full list of procedures available in your Neo4j DBMS, including user-defined procedures. -The built-in functions are described in link:{neo4j-docs-base-uri}/cypher-manual/{page-version}/functions[Cypher Manual -> Functions]. +The built-in functions are described in link:{neo4j-docs-base-uri}/cypher-manual/current/functions[Cypher Manual -> Functions]. Running `SHOW FUNCTIONS` displays the full list of all the functions available in your Neo4j DBMS, including user-defined functions. diff --git a/modules/ROOT/pages/extending-neo4j/procedures.adoc b/modules/ROOT/pages/extending-neo4j/procedures.adoc index 22b8a62..2d61214 100644 --- a/modules/ROOT/pages/extending-neo4j/procedures.adoc +++ b/modules/ROOT/pages/extending-neo4j/procedures.adoc @@ -28,7 +28,7 @@ CALL org.neo4j.examples.findDenseNodes(1000) `CALL` may be the only clause within a Cypher statement or may be combined with other clauses. Arguments can be supplied directly within the query or taken from the associated parameter set. -For full details, see the documentation in link:{neo4j-docs-base-uri}/cypher-manual/{page-version}/clauses/call[Cypher Manual -> `CALL` procedure]. +For full details, see the documentation in link:{neo4j-docs-base-uri}/cypher-manual/current/clauses/call[Cypher Manual -> `CALL` procedure]. [[user-defined-procedures]] diff --git a/modules/ROOT/pages/extending-neo4j/unmanaged-extensions.adoc b/modules/ROOT/pages/extending-neo4j/unmanaged-extensions.adoc index fda9117..61a2920 100644 --- a/modules/ROOT/pages/extending-neo4j/unmanaged-extensions.adoc +++ b/modules/ROOT/pages/extending-neo4j/unmanaged-extensions.adoc @@ -102,7 +102,7 @@ When writing unmanaged extensions, you have greater control over the amount of m If you keep too much state around, it can lead to more frequent full Garbage Collection and subsequent unresponsiveness by the Neo4j server. A common way that state can increase, is the creation of JSON objects to represent the result of a query, which is then sent back to your application. -Neo4j's Transactional Cypher HTTP endpoint (see link:{neo4j-docs-base-uri}/http-api/{page-version}/actions[HTTP API Docs -> transactional Cypher endpoint]) streams responses back to the client. +Neo4j's HTTP endpoint (see link:{neo4j-docs-base-uri}/http-api/current/transactions[HTTP API Docs -> Run transactions]) streams responses back to the client. For example, the following unmanaged extension streams an array of a person's colleagues: //https://github.com/neo4j/neo4j-documentation/blob/dev/server-examples/src/main/java/org/neo4j/examples/server/unmanaged/ColleaguesResource.java diff --git a/modules/ROOT/pages/extending-neo4j/values-and-types.adoc b/modules/ROOT/pages/extending-neo4j/values-and-types.adoc index 2a2abea..7a2bf04 100644 --- a/modules/ROOT/pages/extending-neo4j/values-and-types.adoc +++ b/modules/ROOT/pages/extending-neo4j/values-and-types.adoc @@ -6,7 +6,7 @@ [[extending-neo4j-procedures-and-functions-values-and-types]] = Values and types -The _input_ and _output_ to and from a procedure or a function must be one of the supported types, as described in link:{neo4j-docs-base-uri}/cypher-manual/{page-version}/values-and-types/[Cypher Manual -> Values and types]. +The _input_ and _output_ to and from a procedure or a function must be one of the supported types, as described in link:{neo4j-docs-base-uri}/cypher-manual/current/values-and-types/[Cypher Manual -> Values and types]. Composite types are supported via: diff --git a/modules/ROOT/pages/java-embedded/cypher-java.adoc b/modules/ROOT/pages/java-embedded/cypher-java.adoc index 2433c8d..e832ad8 100644 --- a/modules/ROOT/pages/java-embedded/cypher-java.adoc +++ b/modules/ROOT/pages/java-embedded/cypher-java.adoc @@ -4,7 +4,7 @@ [[cypher-java]] = Cypher queries -In Java, you can use the link:{neo4j-docs-base-uri}/cypher-manual/{page-version}/[Cypher query language] as per the example below. +In Java, you can use the link:{neo4j-docs-base-uri}/cypher-manual/current/[Cypher query language] as per the example below. [TIP] ==== @@ -118,5 +118,5 @@ You should instead use only one and if you need the facilities of the other meth For more information on the Java interface to Cypher, see the link:{neo4j-javadocs-base-uri}/index.html[Neo4j Javadocs^]. -For more information and examples for Cypher, see link:{neo4j-docs-base-uri}/cypher-manual/{page-version}/[Neo4j Cypher Manual]. +For more information and examples for Cypher, see link:{neo4j-docs-base-uri}/cypher-manual/current/[Neo4j Cypher Manual]. diff --git a/modules/ROOT/pages/java-embedded/indexes.adoc b/modules/ROOT/pages/java-embedded/indexes.adoc index 8a94fb3..94e204e 100644 --- a/modules/ROOT/pages/java-embedded/indexes.adoc +++ b/modules/ROOT/pages/java-embedded/indexes.adoc @@ -4,10 +4,10 @@ [[java-embedded-new-index]] = Using indexes -It is possible to create and use all the index types described in link:{neo4j-docs-base-uri}/cypher-manual/{page-version}/indexes-for-search-performance[Cypher Manual -> Indexes]. +It is possible to create and use all the index types described in link:{neo4j-docs-base-uri}/cypher-manual/current/indexes-for-search-performance[Cypher Manual -> Indexes]. This section demonstrates how to work with indexes with an example of a user database. -For information about how to create an index on all `User` nodes that have a `username` property, see link:{neo4j-docs-base-uri}/cypher-manual/{page-version}/indexes-for-search-performance#administration-indexes-create-a-single-property-index-for-nodes[Cypher Manual -> Create a single-property index for nodes]. +For information about how to create an index on all `User` nodes that have a `username` property, see link:{neo4j-docs-base-uri}/cypher-manual/current/indexes-for-search-performance#administration-indexes-create-a-single-property-index-for-nodes[Cypher Manual -> Create a single-property index for nodes]. [TIP] ==== diff --git a/modules/ROOT/pages/java-embedded/property-values.adoc b/modules/ROOT/pages/java-embedded/property-values.adoc index 10a27bc..6e58784 100644 --- a/modules/ROOT/pages/java-embedded/property-values.adoc +++ b/modules/ROOT/pages/java-embedded/property-values.adoc @@ -54,6 +54,6 @@ If these objects are returned from procedures, the original types cannot be recr [NOTE] ==== Strings that contain special characters can have inconsistent or non-deterministic ordering in Neo4j. -For details, see link:{neo4j-docs-base-uri}/cypher-manual/{page-version}/syntax/values#property-types-sip-note[Cypher Manual -> Sorting of special characters]. +For details, see link:{neo4j-docs-base-uri}/cypher-manual/current/syntax/values#property-types-sip-note[Cypher Manual -> Sorting of special characters]. ==== diff --git a/modules/ROOT/pages/java-embedded/query-parameters.adoc b/modules/ROOT/pages/java-embedded/query-parameters.adoc index 179495a..4283283 100644 --- a/modules/ROOT/pages/java-embedded/query-parameters.adoc +++ b/modules/ROOT/pages/java-embedded/query-parameters.adoc @@ -6,7 +6,7 @@ The following examples illustrate how to use parameters when executing Cypher queries from Java. -For more information on parameters, see the link:{neo4j-docs-base-uri}/cypher-manual/{page-version}/[Neo4j Cypher Manual]. +For more information on parameters, see the link:{neo4j-docs-base-uri}/cypher-manual/current/[Neo4j Cypher Manual]. //https://github.com/neo4j/neo4j-documentation/blob/dev/cypher/cypher-docs/src/test/java/org/neo4j/cypher/example/JavaExecutionEngineDocTest.java diff --git a/modules/ROOT/pages/java-embedded/unique-nodes.adoc b/modules/ROOT/pages/java-embedded/unique-nodes.adoc index 4ee6c13..a4a0cff 100644 --- a/modules/ROOT/pages/java-embedded/unique-nodes.adoc +++ b/modules/ROOT/pages/java-embedded/unique-nodes.adoc @@ -82,5 +82,5 @@ You might also be tempted to use Java synchronization for pessimistic locking, b By mixing locks in Neo4j and the Java runtime, it is possible to produce deadlocks that are not detectable by Neo4j. As long as all locking is done by Neo4j, all deadlocks will be detected and avoided. -For more information on locks and deadlocks, see link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-internals/locks-deadlocks.adoc#_locks[Operations Manual -> Locks and deadlocks^]. +For more information on locks and deadlocks, see link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-internals/concurrent-data-access/#_locks[Operations Manual -> Locks and deadlocks^]. diff --git a/modules/ROOT/pages/transaction-management.adoc b/modules/ROOT/pages/transaction-management.adoc index b414bc5..3acfb24 100644 --- a/modules/ROOT/pages/transaction-management.adoc +++ b/modules/ROOT/pages/transaction-management.adoc @@ -31,7 +31,7 @@ The interaction cycle of working with transactions follows the steps: [NOTE] ==== It is crucial to finish each transaction because the locks or memory acquired by a transaction are only released upon completion. -For more information on locks and deadlocks, see link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-internals/locks-deadlocks[Operations Manual -> Locks and deadlocks^]. +For more information on locks and deadlocks, see link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-internals/concurrent-data-access/#_locks[Operations Manual -> Locks and deadlocks^]. ==== The idiomatic use of transactions in Neo4j is to use a `try-with-resources` statement and declare `transaction` as one of the resources. From 92d0cc196e9841e3795263c35975e9bd3dcb71df Mon Sep 17 00:00:00 2001 From: Neil Dewhurst Date: Fri, 21 Mar 2025 16:19:29 +0000 Subject: [PATCH 08/48] Update docs-pr-checks.yml (#263) --- .github/workflows/docs-pr-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs-pr-checks.yml b/.github/workflows/docs-pr-checks.yml index a896369..1e0d4b0 100644 --- a/.github/workflows/docs-pr-checks.yml +++ b/.github/workflows/docs-pr-checks.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Get file changes id: get-file-changes - uses: tj-actions/changed-files@cbda684547adc8c052d50711417fa61b428a9f88 # v41.1.2 + uses: tj-actions/changed-files@2f7c5bfce28377bc069a65ba478de0a74aa0ca32 # v46.0.1 with: separator: ',' files_yaml: | From ff9349372a1d3da0bf5f9937d898c0673959c0a2 Mon Sep 17 00:00:00 2001 From: NataliaIvakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Fri, 28 Mar 2025 11:45:35 +0100 Subject: [PATCH 09/48] Update the version to 2025.04 (#268) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index 9b1fca4..6514b83 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2025.03' +version: '2025.04' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2025.03' - neo4j-version-exact: '2025.03.0' - neo4j-buildnumber: '2025.03' + neo4j-version: '2025.04' + neo4j-version-exact: '2025.04.0' + neo4j-buildnumber: '2025.04' java-driver-version: '5.28.3' neo4j-documentation-branch: 'dev' page-origin-private: false From b2fce0f15addac6d17211aaf157245890107cd1a Mon Sep 17 00:00:00 2001 From: Reneta Popova Date: Wed, 30 Apr 2025 16:03:49 +0100 Subject: [PATCH 10/48] Update version to 2025.05 (#271) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index 6514b83..e892d35 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2025.04' +version: '2025.05' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2025.04' - neo4j-version-exact: '2025.04.0' - neo4j-buildnumber: '2025.04' + neo4j-version: '2025.05' + neo4j-version-exact: '2025.05.0' + neo4j-buildnumber: '2025.05' java-driver-version: '5.28.3' neo4j-documentation-branch: 'dev' page-origin-private: false From c55e07154bf802ae2219c92235ed31db5bc12b42 Mon Sep 17 00:00:00 2001 From: Reneta Popova Date: Tue, 3 Jun 2025 17:08:58 +0100 Subject: [PATCH 11/48] Update version to 2025.06 (#277) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index e892d35..27c3121 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2025.05' +version: '2025.06' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2025.05' - neo4j-version-exact: '2025.05.0' - neo4j-buildnumber: '2025.05' + neo4j-version: '2025.06' + neo4j-version-exact: '2025.06.0' + neo4j-buildnumber: '2025.06' java-driver-version: '5.28.3' neo4j-documentation-branch: 'dev' page-origin-private: false From 148a6ca83345a4de1e9131d286e137a025a1d23d Mon Sep 17 00:00:00 2001 From: NataliaIvakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Tue, 10 Jun 2025 13:48:19 +0200 Subject: [PATCH 12/48] Update Java driver version to 5.28.5 (#280) --- antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/antora.yml b/antora.yml index 27c3121..11958e8 100644 --- a/antora.yml +++ b/antora.yml @@ -9,7 +9,7 @@ asciidoc: neo4j-version: '2025.06' neo4j-version-exact: '2025.06.0' neo4j-buildnumber: '2025.06' - java-driver-version: '5.28.3' + java-driver-version: '5.28.5' neo4j-documentation-branch: 'dev' page-origin-private: false neo4j-javadocs-base-uri: "https://neo4j.com/docs/java-reference/5/javadocs" From 7726721011c663af38822be1c92af8d776c5a2fd Mon Sep 17 00:00:00 2001 From: NataliaIvakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:55:17 +0200 Subject: [PATCH 13/48] Update and fix several pages (#279) * Update and fix several pages * Change ClusterSettings to DiscoverySettings --- .../pages/extending-neo4j/project-setup.adoc | 15 ++++++----- .../extending-neo4j/server-debugging.adoc | 2 +- .../extending-neo4j/unmanaged-extensions.adoc | 25 ++++++------------- .../ROOT/pages/java-embedded/entities.adoc | 2 +- .../pages/java-embedded/graph-algorithms.adoc | 2 +- .../ROOT/pages/java-embedded/hello-world.adoc | 2 +- modules/ROOT/pages/java-embedded/setup.adoc | 10 ++++---- .../ROOT/pages/java-embedded/terminate.adoc | 2 +- 8 files changed, 27 insertions(+), 33 deletions(-) diff --git a/modules/ROOT/pages/extending-neo4j/project-setup.adoc b/modules/ROOT/pages/extending-neo4j/project-setup.adoc index 6cf91f4..c9c6cb7 100644 --- a/modules/ROOT/pages/extending-neo4j/project-setup.adoc +++ b/modules/ROOT/pages/extending-neo4j/project-setup.adoc @@ -138,7 +138,7 @@ Once the procedure has been deployed to the _plugins_ directory of each Neo4j in The _Seed from URI_ feature provides the ability to dynamically discover additional seed provider implementations from the class path. -Seed providers should be implemented in Java and this guide provides instructions on how to do this using Maven as the build tool. +Seed providers should be implemented in Java; and this guide provides instructions on how to do this using Maven as the build tool. === Set up a Maven project @@ -203,24 +203,27 @@ To implement the custom database seed provider, you must define three methods on Additionally, you must implement a method on the nested `Dependencies` interface to resolve any dependencies required by your seed provider implementation. Typically, the match method uses the URI scheme (the part specified before the first colon) to determine whether it can support the given URI or not. -For example, `file`, `http`, `https` etc. +For example, `file`, `http`, `https`, etc. The stream method should implement a scheme-specific way to obtain an input stream for the backup or dump. -Implementation-specific seed configuration can be passed through from options specified in the `CREATE DATABASE` command using `seedConfig`. +Implementation-specific seed configuration can be passed through from options specified in the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/standard-databases/create-databases[`CREATE DATABASE` command using `seedConfig`]. + +Keep in mind that the `CREATE DATABASE` command is Enterprise Edition feature. + === Deploy -Build a jar file from Maven and place this onto the Neo4j classpath. +Build a JAR file from Maven and place this onto the Neo4j classpath. -The jar must include a META-INF file to enable discovery of the providers with the path: +The JAR file must include a META-INF file to enable discovery of the providers with the path: [source, none] ---- /META_INF/services/com.neo4j.dbms.seeding.SeedProvider ---- -It should be a plain text file with one line for each provider contained within the jar, the line should contain the fully qualified name of the provider class. +It should be a plain text file with one line for each provider contained within the JAR file, the line should contain the fully qualified name of the provider class. [NOTE] ==== diff --git a/modules/ROOT/pages/extending-neo4j/server-debugging.adoc b/modules/ROOT/pages/extending-neo4j/server-debugging.adoc index a24038d..e1d84e4 100644 --- a/modules/ROOT/pages/extending-neo4j/server-debugging.adoc +++ b/modules/ROOT/pages/extending-neo4j/server-debugging.adoc @@ -14,6 +14,6 @@ To specify the parameters, you must add a line for the additional Java arguments server.jvm.additional=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 ---- -This configuration starts Neo4j, ready for remote debugging attachment, at `localhost`` and port `5005`. +This configuration starts Neo4j, ready for remote debugging attachment, at `localhost` and port `5005`. Use these parameters to attach to the process from Eclipse, IntelliJ, or your remote debugger of choice after starting the server. diff --git a/modules/ROOT/pages/extending-neo4j/unmanaged-extensions.adoc b/modules/ROOT/pages/extending-neo4j/unmanaged-extensions.adoc index 61a2920..f63173a 100644 --- a/modules/ROOT/pages/extending-neo4j/unmanaged-extensions.adoc +++ b/modules/ROOT/pages/extending-neo4j/unmanaged-extensions.adoc @@ -61,7 +61,7 @@ public class HelloWorldResource } ---- -The full source code isfound at: +The full source code is found at: link:https://github.com/neo4j/neo4j-documentation/blob/{neo4j-documentation-branch}/server-examples/src/main/java/org/neo4j/examples/server/unmanaged/HelloWorldResource.java[HelloWorldResource.java^] Having built your code, the resulting JAR file (and any customized dependencies) should be placed in the _$NEO4J_SERVER_HOME/plugins_ directory. @@ -174,7 +174,7 @@ public class ColleaguesResource } ---- -The full source code isfound at: +The full source code is found at: link:https://github.com/neo4j/neo4j-documentation/blob/{neo4j-documentation-branch}/server-examples/src/main/java/org/neo4j/examples/server/unmanaged/ColleaguesResource.java[ColleaguesResource.java^] As well as depending on JAX-RS API, this example also uses Jackson -- a Java JSON library. @@ -191,18 +191,9 @@ You need to add the following dependency to your Maven POM file (or equivalent): [CAUTION] ==== -From Neo4j 3.5.15, a breaking change was introduced following an update to the Jackson dependency. +Neo4j supports Jackson v2. -Jackson v1 is out of support and has accumulated security issues such as: - -* link:https://www.cvedetails.com/cve/CVE-2017-7525/[`CVE-2017-7525`] -* link:https://www.cvedetails.com/cve/CVE-2017-17485/[`CVE-2017-17485`] -* link:https://www.cvedetails.com/cve/CVE-2017-15095/[`CVE-2017-15095`] -* link:https://www.cvedetails.com/cve/CVE-2018-11307/[`CVE-2018-11307`] -* link:https://www.cvedetails.com/cve/CVE-2018-7489/[`CVE-2018-7489`] -* link:https://www.cvedetails.com/cve/CVE-2018-5968/[`CVE-2018-5968`] - -For further information about Jackson v2, please see the link:https://github.com/FasterXML/jackson[Jackson Project on GitHub]. +For more information about Jackson v2, see the link:https://github.com/FasterXML/jackson[Jackson Project on GitHub]. ==== Your `findColleagues` method now responds to `GET` requests at the URI: @@ -295,7 +286,7 @@ public class ColleaguesCypherExecutionResource } ---- -The full source code isfound at: +The full source code is found at: link:https://github.com/neo4j/neo4j-documentation/blob/{neo4j-documentation-branch}/server-examples/src/main/java/org/neo4j/examples/server/unmanaged/ColleaguesCypherExecutionResource.java[ColleaguesCypherExecutionResource.java^] Your `findColleagues` method now responds to `GET` requests at the URI: @@ -336,7 +327,7 @@ You can access this toolkit by adding the following test dependency to your proj -------- -The test toolkit provides a mechanism to start a Neo4j instance with a customized configuration and with extensions of your choice. +The test toolkit provides a mechanism to start a Neo4j instance with a customized configuration and extensions of your choice. It also provides mechanisms to specify data fixtures to include when starting Neo4j, as you can see in the following example: //https://github.com/neo4j/neo4j-documentation/blob/dev/neo4j-harness-enterprise-test/src/test/java/org/neo4j/harness/enterprise/doc/ExtensionTestingDocIT.java @@ -380,7 +371,7 @@ public void testMyExtensionWithFunctionFixture() } ---- -The full source code of the example isfound at: +The full source code of the example is found at: link:https://github.com/neo4j/neo4j-documentation/blob/{neo4j-documentation-branch}/neo4j-harness-test/src/test/java/org/neo4j/harness/doc/ExtensionTestingDocIT.java[ExtensionTestingDocIT.java^] @@ -426,6 +417,6 @@ public void shouldWorkWithServer() } ---- -The full source code of the example isfound at: +The full source code of the example is found at: link:https://github.com/neo4j/neo4j-documentation/blob/{neo4j-documentation-branch}/neo4j-harness-test/src/test/java/org/neo4j/harness/doc/JUnitDocIT.java[JUnitDocIT.java^] diff --git a/modules/ROOT/pages/java-embedded/entities.adoc b/modules/ROOT/pages/java-embedded/entities.adoc index f9c549f..475f802 100644 --- a/modules/ROOT/pages/java-embedded/entities.adoc +++ b/modules/ROOT/pages/java-embedded/entities.adoc @@ -9,7 +9,7 @@ The same approach can be used with relationships. [TIP] ==== -The source code of the examples isfound at: +The source code of the examples is found at: link:https://github.com/neo4j/neo4j-documentation/blob/{neo4j-documentation-branch}/embedded-examples/src/main/java/org/neo4j/examples/socnet/Person.java[Person.java] ==== diff --git a/modules/ROOT/pages/java-embedded/graph-algorithms.adoc b/modules/ROOT/pages/java-embedded/graph-algorithms.adoc index 3ca5cf8..d6e95da 100644 --- a/modules/ROOT/pages/java-embedded/graph-algorithms.adoc +++ b/modules/ROOT/pages/java-embedded/graph-algorithms.adoc @@ -11,7 +11,7 @@ For details on the graph algorithm usage, see the link:{org-neo4j-graphalgo-grap [TIP] ==== -The source code used in the example isfound at: +The source code used in the example is found at: link:https://github.com/neo4j/neo4j-documentation/blob/{neo4j-documentation-branch}/embedded-examples/src/test/java/org/neo4j/examples/PathFindingDocTest.java[PathFindingDocTest.java^] ==== diff --git a/modules/ROOT/pages/java-embedded/hello-world.adoc b/modules/ROOT/pages/java-embedded/hello-world.adoc index d663ce2..86e0003 100644 --- a/modules/ROOT/pages/java-embedded/hello-world.adoc +++ b/modules/ROOT/pages/java-embedded/hello-world.adoc @@ -22,7 +22,7 @@ For information on project setup, see xref:java-embedded/setup.adoc[]. [TIP] ==== -The source code of this example isfound at: +The source code of this example is found at: link:https://github.com/neo4j/neo4j-documentation/blob/{neo4j-documentation-branch}/embedded-examples/src/main/java/org/neo4j/examples/EmbeddedNeo4j.java[EmbeddedNeo4j.java] ==== diff --git a/modules/ROOT/pages/java-embedded/setup.adoc b/modules/ROOT/pages/java-embedded/setup.adoc index 6c586fa..3c4b6d0 100644 --- a/modules/ROOT/pages/java-embedded/setup.adoc +++ b/modules/ROOT/pages/java-embedded/setup.adoc @@ -126,7 +126,7 @@ registerShutdownHook( managementService ); If you are using the Enterprise Edition of Neo4j in embedded mode, you have to create your database with the link:{com-neo4j-dbms-api-EnterpriseDatabaseManagementServiceBuilder}[`com.neo4j.dbms.api.EnterpriseDatabaseManagementServiceBuilder`^] to enable the Enterprise Edition features. -If you intend to operate embedded clusters, you need to provide the appropriate configuration to the instances you create (for example ports and discovery endpoints). +If you intend to operate embedded clusters, you need to provide the appropriate configuration to the instances you create (for example, ports and discovery endpoints). For maintainability purposes, you can define your embedded DBMS configuration in the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/configuration/neo4j-conf[_neo4j.conf_] file as follows: //https://github.com/neo4j/neo4j-documentation/blob/dev/embedded-examples/src/main/java/org/neo4j/examples/EmbeddedNeo4jClusterUsingBuilder.java @@ -136,8 +136,8 @@ For maintainability purposes, you can define your embedded DBMS configuration in ---- server.default_advertised_address=core01.example.com server.default_listen_address=0.0.0.0 -dbms.cluster.discovery.type=LIST -dbms.cluster.discovery.endpoints=core01.example.com,core02.example.com,core03.example.com +dbms.cluster.discovery.resolver_type=LIST +dbms.cluster.endpoints=core01.example.com,core02.example.com,core03.example.com server.bolt.enabled=true server.http.enabled=true ---- @@ -171,8 +171,8 @@ var initialMembers = List.of( var managementService = new EnterpriseDatabaseManagementServiceBuilder( homeDirectory ) .setConfig( GraphDatabaseSettings.default_advertised_address, defaultAdvertised ) .setConfig( GraphDatabaseSettings.default_listen_address, defaultListen ) - .setConfig( ClusterSettings.discovery_type, DiscoveryType.LIST ) - .setConfig( ClusterSettings.discovery_endpoints, initialMembers ) + .setConfig( DiscoverySettings.discovery.resolver_type, DiscoveryType.LIST ) + .setConfig( DiscoverySettings.cluster_endpoints, initialMembers ) .setConfig( EnterpriseEditionSettings.initial_default_primaries_count, 3 ) .setConfig( BoltConnector.enabled, true ) .setConfig( HttpConnector.enabled, true ) diff --git a/modules/ROOT/pages/java-embedded/terminate.adoc b/modules/ROOT/pages/java-embedded/terminate.adoc index 28cee13..d88176a 100644 --- a/modules/ROOT/pages/java-embedded/terminate.adoc +++ b/modules/ROOT/pages/java-embedded/terminate.adoc @@ -9,7 +9,7 @@ You can terminate (abort) a long-running transaction from another thread. [TIP] ==== The source code for the examples can befound at: -https://github.com/neo4j/neo4j-documentation/blob/{neo4j-version}/embedded-examples/src/main/java/org/neo4j/examples/TerminateTransactions.java[TerminateTransactions.java^] +https://github.com/neo4j/neo4j-documentation/blob/dev/embedded-examples/src/main/java/org/neo4j/examples/TerminateTransactions.java[TerminateTransactions.java^] ==== First, start the database server: From 392b672ea5187bde8bf20a098cec316dda8c2fef Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Mon, 30 Jun 2025 11:55:59 +0200 Subject: [PATCH 14/48] Update Java driver to 5.28.6 (#283) --- antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/antora.yml b/antora.yml index 11958e8..6700714 100644 --- a/antora.yml +++ b/antora.yml @@ -9,7 +9,7 @@ asciidoc: neo4j-version: '2025.06' neo4j-version-exact: '2025.06.0' neo4j-buildnumber: '2025.06' - java-driver-version: '5.28.5' + java-driver-version: '5.28.6' neo4j-documentation-branch: 'dev' page-origin-private: false neo4j-javadocs-base-uri: "https://neo4j.com/docs/java-reference/5/javadocs" From 3d4c6f34a7dc5640db9297089abd83f02029b61e Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:14:58 +0200 Subject: [PATCH 15/48] Bump Neo4j version to 2025.07 (#286) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index 6700714..de8fc27 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2025.06' +version: '2025.07' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2025.06' - neo4j-version-exact: '2025.06.0' - neo4j-buildnumber: '2025.06' + neo4j-version: '2025.07' + neo4j-version-exact: '2025.07.0' + neo4j-buildnumber: '2025.07' java-driver-version: '5.28.6' neo4j-documentation-branch: 'dev' page-origin-private: false From 3a526d1de41f97638eafb5d743dd7d60ff78610e Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:33:04 +0200 Subject: [PATCH 16/48] Update Java driver to 5.28.7 (#287) --- antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/antora.yml b/antora.yml index de8fc27..eba5628 100644 --- a/antora.yml +++ b/antora.yml @@ -9,7 +9,7 @@ asciidoc: neo4j-version: '2025.07' neo4j-version-exact: '2025.07.0' neo4j-buildnumber: '2025.07' - java-driver-version: '5.28.6' + java-driver-version: '5.28.7' neo4j-documentation-branch: 'dev' page-origin-private: false neo4j-javadocs-base-uri: "https://neo4j.com/docs/java-reference/5/javadocs" From 412325b4bf90fc632158e3dbd3c2114a3e7a9621 Mon Sep 17 00:00:00 2001 From: Neil Dewhurst Date: Fri, 18 Jul 2025 12:22:58 +0100 Subject: [PATCH 17/48] Update path to javadocs (#289) * Update path to javadocs * use docs-base-uri in path --- antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/antora.yml b/antora.yml index eba5628..958b44c 100644 --- a/antora.yml +++ b/antora.yml @@ -12,4 +12,4 @@ asciidoc: java-driver-version: '5.28.7' neo4j-documentation-branch: 'dev' page-origin-private: false - neo4j-javadocs-base-uri: "https://neo4j.com/docs/java-reference/5/javadocs" + neo4j-javadocs-base-uri: "{neo4j-docs-base-uri}/java-reference/{neo4j-version}/javadocs" From 1af8cfc3d5c5edd0ee1a8e1325d2cb93342a28fd Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Tue, 29 Jul 2025 11:00:27 +0200 Subject: [PATCH 18/48] Update Java driver version to 5.28.9 (#290) --- antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/antora.yml b/antora.yml index 958b44c..f0ac936 100644 --- a/antora.yml +++ b/antora.yml @@ -9,7 +9,7 @@ asciidoc: neo4j-version: '2025.07' neo4j-version-exact: '2025.07.0' neo4j-buildnumber: '2025.07' - java-driver-version: '5.28.7' + java-driver-version: '5.28.9' neo4j-documentation-branch: 'dev' page-origin-private: false neo4j-javadocs-base-uri: "{neo4j-docs-base-uri}/java-reference/{neo4j-version}/javadocs" From 264b5d03ba2f477a7678f5f1bff10647c8aec1e0 Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Thu, 31 Jul 2025 14:58:03 +0200 Subject: [PATCH 19/48] Update to 2025.08 (#294) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index f0ac936..ed565a3 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2025.07' +version: '2025.08' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2025.07' - neo4j-version-exact: '2025.07.0' - neo4j-buildnumber: '2025.07' + neo4j-version: '2025.08' + neo4j-version-exact: '2025.08.0' + neo4j-buildnumber: '2025.08' java-driver-version: '5.28.9' neo4j-documentation-branch: 'dev' page-origin-private: false From e65d354f9211696bb5c332d5208c7d3caae19ed8 Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Tue, 2 Sep 2025 14:40:02 +0200 Subject: [PATCH 20/48] Update to 2025.09 (#298) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index ed565a3..d5bb37d 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2025.08' +version: '2025.09' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2025.08' - neo4j-version-exact: '2025.08.0' - neo4j-buildnumber: '2025.08' + neo4j-version: '2025.09' + neo4j-version-exact: '2025.09.0' + neo4j-buildnumber: '2025.09' java-driver-version: '5.28.9' neo4j-documentation-branch: 'dev' page-origin-private: false From 92582a80c4f1fce4de6ab98594fbbfb15d898e0b Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:21:07 +0200 Subject: [PATCH 21/48] Bump to 2025.10, Java driver to 5.28.10 (#302) --- antora.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/antora.yml b/antora.yml index d5bb37d..29d7fee 100644 --- a/antora.yml +++ b/antora.yml @@ -1,15 +1,15 @@ name: java-reference title: Java Reference -version: '2025.09' +version: '2025.10' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2025.09' - neo4j-version-exact: '2025.09.0' - neo4j-buildnumber: '2025.09' - java-driver-version: '5.28.9' + neo4j-version: '2025.10' + neo4j-version-exact: '2025.10.0' + neo4j-buildnumber: '2025.10' + java-driver-version: '5.28.10' neo4j-documentation-branch: 'dev' page-origin-private: false neo4j-javadocs-base-uri: "{neo4j-docs-base-uri}/java-reference/{neo4j-version}/javadocs" From cbae1f374bdc92b7bba2b4158e0338195cb6ab45 Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Fri, 17 Oct 2025 11:59:40 +0200 Subject: [PATCH 22/48] Update Java to 21 (#306) * Update Java to 21 * Add a link to the Bolt docs * Update setup.adoc --- modules/ROOT/pages/extending-neo4j/project-setup.adoc | 6 +++--- modules/ROOT/pages/java-embedded/bolt.adoc | 5 +---- modules/ROOT/pages/java-embedded/setup.adoc | 4 ++-- modules/ROOT/pages/jmx-metrics.adoc | 6 +++--- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/modules/ROOT/pages/extending-neo4j/project-setup.adoc b/modules/ROOT/pages/extending-neo4j/project-setup.adoc index c9c6cb7..a8482a8 100644 --- a/modules/ROOT/pages/extending-neo4j/project-setup.adoc +++ b/modules/ROOT/pages/extending-neo4j/project-setup.adoc @@ -38,7 +38,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs A template project for building a Neo4j Procedure - 17 + 21 ${java.version} {neo4j-version-exact} @@ -114,8 +114,8 @@ Once the procedure has been deployed to the _plugins_ directory of each Neo4j in maven-compiler-plugin - 17 - 17 + 21 + 21 diff --git a/modules/ROOT/pages/java-embedded/bolt.adoc b/modules/ROOT/pages/java-embedded/bolt.adoc index 027c52e..f9cc2fe 100644 --- a/modules/ROOT/pages/java-embedded/bolt.adoc +++ b/modules/ROOT/pages/java-embedded/bolt.adoc @@ -1,13 +1,10 @@ :description: How to open a Bolt connector to your embedded instance to get GUI administration and other benefits. -:org-neo4j-graphdb-factory-GraphDatabaseFactory: {neo4j-javadocs-base-uri}/org/neo4j/graphdb/factory/GraphDatabaseFactory.html - - [[java-embedded-bolt]] = Bolt connector This describes how to open a Bolt connector to your embedded instance to get GUI administration and other benefits. -Accessing Neo4j embedded via the Bolt protocol. +Accessing Neo4j embedded via the link:https://neo4j.com/docs/bolt/current/[Bolt protocol]. The Neo4j Browser and the official Neo4j Drivers use the Bolt database protocol to communicate with Neo4j. By default, Neo4j embedded does not expose a Bolt connector, but you can enable one. diff --git a/modules/ROOT/pages/java-embedded/setup.adoc b/modules/ROOT/pages/java-embedded/setup.adoc index 3c4b6d0..2b69849 100644 --- a/modules/ROOT/pages/java-embedded/setup.adoc +++ b/modules/ROOT/pages/java-embedded/setup.adoc @@ -17,9 +17,9 @@ The following examples use the top-level artifact approach. [NOTE] -.[enterprise-edition] ==== The examples are only valid for Neo4j Community Edition. + To add Neo4j Enterprise Edition as a dependency, please get in contact with link:https://neo4j.com/contact-us/[Neo4j Professional Services^]. See link:{neo4j-docs-base-uri}/operations-manual/{page-version}/introduction[Operations Manual -> Introduction] for details about the Community and Enterprise Editions. ==== @@ -51,7 +51,7 @@ Where the `artifactId` is found in the <> table. === Eclipse and Maven -For development in link:http://www.eclipse.org[Eclipse^], it is recommended to install the link:http://www.eclipse.org/m2e/[m2e plugin^] and let Maven manage the project build classpath instead. +For development in link:https://www.eclipse.org[Eclipse^], it is recommended to install the link:https://www.eclipse.org/m2e/[m2e plugin^] and let Maven manage the project build classpath instead. This also adds the possibility to build your project both via the command line with Maven and have a working Eclipse setup for development. diff --git a/modules/ROOT/pages/jmx-metrics.adoc b/modules/ROOT/pages/jmx-metrics.adoc index fd877d8..32d9b57 100644 --- a/modules/ROOT/pages/jmx-metrics.adoc +++ b/modules/ROOT/pages/jmx-metrics.adoc @@ -43,7 +43,7 @@ server.jvm.additional=-Dcom.sun.management.jmxremote.ssl=false [IMPORTANT] ==== -Although SSL for JMX Remote Management is disabled throughout this document, to configure it based on your requirements, you can follow the instructions in the link:https://docs.oracle.com/en/java/javase/11/management/monitoring-and-management-using-jmx-technology.html[Java SE 11 Monitoring and Management Guide^]. +Although SSL for JMX Remote Management is disabled throughout this document, to configure it based on your requirements, you can follow the instructions in the link:https://docs.oracle.com/en/java/javase/21/management/monitoring-and-management-using-jmx-technology.html[Java SE 21 Monitoring and Management Guide^]. ==== @@ -53,7 +53,7 @@ Although SSL for JMX Remote Management is disabled throughout this document, to Password authentication is enabled by default in JMX Remote Management. You can find information about setting up authentication with LDAP and file-based approach in the following sections. -Refer to the link:https://docs.oracle.com/en/java/javase/11/management/monitoring-and-management-using-jmx-technology.html[Java SE 11 Monitoring and Management Guide^] for more options, including configuration steps for SSL client authentication. +Refer to the link:https://docs.oracle.com/en/java/javase/21/management/monitoring-and-management-using-jmx-technology.html[Java SE 21 Monitoring and Management Guide^] for more options, including configuration steps for SSL client authentication. [[ldap]] @@ -184,7 +184,7 @@ The `` value is configured by the `com.sun.management.jmxremote.port` prop Besides the MBeans, exposed by the JVM, you also see be default `neo4j.metrics` section in the MBeans tab. Under that, you have access to all the monitoring information exposed by Neo4j. -For opening JMX to remote monitoring access, please see <> and link:https://docs.oracle.com/en/java/javase/11/management/monitoring-and-management-using-jmx-technology.html#GUID-805517EC-2D33-4D61-81D8-4D0FA770D1B8[the JMX documention^]. +For opening JMX to remote monitoring access, please see <> and link:https://docs.oracle.com/en/java/javase/21/management/monitoring-and-management-using-jmx-technology.html#GUID-805517EC-2D33-4D61-81D8-4D0FA770D1B8[the JMX documention^]. .Neo4j MBeans view image::jconsole-beans1.png[alt="Neo4j MBeans view", width=600] From 905a70dc0e4cc7101c8e946611034613c3d289e3 Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Thu, 30 Oct 2025 17:20:17 +0100 Subject: [PATCH 23/48] Update antora.yml (#312) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index 29d7fee..86fc960 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2025.10' +version: '2025.11' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2025.10' - neo4j-version-exact: '2025.10.0' - neo4j-buildnumber: '2025.10' + neo4j-version: '2025.11' + neo4j-version-exact: '2025.11.0' + neo4j-buildnumber: '2025.11' java-driver-version: '5.28.10' neo4j-documentation-branch: 'dev' page-origin-private: false From 279219fef8c3e44d5167f8850331a1e5b013a43a Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:18:30 +0100 Subject: [PATCH 24/48] Update Java Driver to 6.0.2 (#315) * Update Neo4j v. to 2025.12, Java Driver to 6.0.2 * Back to 2025.11 --- antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/antora.yml b/antora.yml index 86fc960..baa2fd7 100644 --- a/antora.yml +++ b/antora.yml @@ -9,7 +9,7 @@ asciidoc: neo4j-version: '2025.11' neo4j-version-exact: '2025.11.0' neo4j-buildnumber: '2025.11' - java-driver-version: '5.28.10' + java-driver-version: '6.0.2' neo4j-documentation-branch: 'dev' page-origin-private: false neo4j-javadocs-base-uri: "{neo4j-docs-base-uri}/java-reference/{neo4j-version}/javadocs" From 8e8ee39f551487623b43844b1dc3e3fac51f5f44 Mon Sep 17 00:00:00 2001 From: JoelBergstrand Date: Tue, 9 Dec 2025 11:08:38 +0100 Subject: [PATCH 25/48] Clarified naming rules for user defined callables and added list for reserved and deprecated namespaces (#310) * Clarified naming rules for user defined callables and added list for reserved and deprecated namespaces * Apply suggestions from code review Co-authored-by: Richard Sill <156673635+rsill-neo4j@users.noreply.github.com> * Updated deprecating root for procedures * Update modules/ROOT/pages/extending-neo4j/procedures.adoc * Apply suggestions from code review --------- Co-authored-by: Richard Sill <156673635+rsill-neo4j@users.noreply.github.com> Co-authored-by: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> --- .../aggregation-functions.adoc | 61 +++++++++++++++++++ .../ROOT/pages/extending-neo4j/functions.adoc | 59 ++++++++++++++++++ .../pages/extending-neo4j/procedures.adoc | 29 ++++++++- 3 files changed, 148 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/extending-neo4j/aggregation-functions.adoc b/modules/ROOT/pages/extending-neo4j/aggregation-functions.adoc index c431189..f016a8c 100644 --- a/modules/ROOT/pages/extending-neo4j/aggregation-functions.adoc +++ b/modules/ROOT/pages/extending-neo4j/aggregation-functions.adoc @@ -32,6 +32,13 @@ An aggregator class contains one method annotated with `@UserAggregationUpdate` The method annotated with `@UserAggregationUpdate` will be called multiple times and enables the class to aggregate data. When the aggregation is done, the method annotated with `@UserAggregationResult` will be called once and the result of the aggregation will be returned. +Particular things to note: + +* All functions are annotated with `@UserAggregationFunction`. +* The aggregation function name must be namespaced and is not allowed in reserved namespaces. +* If a user-defined aggregation function is registered with the same name as a built-in function in a deprecated namespace, the built-in function is shadowed. + + See xref:extending-neo4j/values-and-types.adoc[] for details on values and types. For more details, see the Neo4j Javadocs for link:{org-neo4j-procedure-UserAggregationFunction}[`org.neo4j.procedure.UserAggregationFunction`^]. @@ -132,3 +139,57 @@ public class LongestStringTest } ---- +[[reserved-and-deprecated-namespaces]] +== Reserved and deprecated function namespaces + +Note that deprecated function namespaces will be moved to reserved in the next major Cypher version. +For more information about Neo4j and Cypher versioning, see link:https://neo4j.com/docs/operations-manual/current/introduction/#_cypher_versions[Operations manual -> Introduction]. +[[reserved-and-deprecated-function-namespaces]] +.Overview of reserved and deprecated function namespaces and names +[options="header", cols="m,m"] +|=== +| Reserved | Deprecated in Cypher 25 since Neo4j 2025.11 +| * | abac.* +| date | aura.* +| date.realtime | builtin.* +| date.statement | cdc.* +| date.transaction | coll.* +| date.truncate | date.* +| datetime | datetime.* +| datetime.fromepoch | db.* +| datetime.fromepochmillis | dbms.* +| datetime.realtime | duration.* +| datetime.statement | graph.* +| datetime.transaction | internal.* +| datetime.truncate | localdatetime.* +| db.nameFromElementId | localtime.* +| duration | math.* +| duration.between | plugin.* +| duration.inDays | point.* +| duration.inMonths | stored.* +| duration.inSeconds | string.* +| graph.byElementId | time.* +| graph.byName | tx.* +| graph.names | unsupported.* +| graph.propertiesByName | vector.* +| localdatetime | +| localdatetime.realtime | +| localdatetime.statement | +| localdatetime.transaction | +| localdatetime.truncate | +| localtime | +| localtime.realtime | +| localtime.statement | +| localtime.transaction | +| localtime.truncate | +| point.distance | +| point.withinBBox | +| time | +| time.realtime | +| time.statement | +| time.transaction | +| time.truncate | +| vector.similarity.cosine | +| vector.similarity.euclidean | +|=== + diff --git a/modules/ROOT/pages/extending-neo4j/functions.adoc b/modules/ROOT/pages/extending-neo4j/functions.adoc index 147957f..b783674 100644 --- a/modules/ROOT/pages/extending-neo4j/functions.adoc +++ b/modules/ROOT/pages/extending-neo4j/functions.adoc @@ -30,6 +30,12 @@ RETURN org.neo4j.examples.join(collect(p.names)) User-defined functions are created similarly to how procedures are created. But unlike procedures, they are annotated with `@UserFunction` and return a single value instead of a stream of values. +Particular things to note: + +* All functions are annotated with `@UserFunction`. +* The function name must be namespaced and is not allowed in reserved namespaces. +* If a function is registered with the same name as a built-in function in a deprecated namespace, the built-in function is shadowed. + See xref:extending-neo4j/values-and-types.adoc[] for details on values and types. For more details, see the link:{org-neo4j-procedure-UserFunction}[Neo4j Javadocs for `org.neo4j.procedure.UserFunction`^]. @@ -120,3 +126,56 @@ public class JoinTest { } ---- +[[reserved-and-deprecated-namespaces]] +== Reserved and deprecated function namespaces + +Note that deprecated function namespaces will be moved to reserved in the next major Cypher version. +For more information about Neo4j and Cypher versioning, see link:https://neo4j.com/docs/operations-manual/current/introduction/#_cypher_versions[Operations manual -> Introduction]. +[[reserved-and-deprecated-function-namespaces]] +.Overview of reserved and deprecated function namespaces and names +[options="header", cols="m,m"] +|=== +| Reserved | Deprecated in Cypher 25 since Neo4j 2025.11 +| * | abac.* +| date | aura.* +| date.realtime | builtin.* +| date.statement | cdc.* +| date.transaction | coll.* +| date.truncate | date.* +| datetime | datetime.* +| datetime.fromepoch | db.* +| datetime.fromepochmillis | dbms.* +| datetime.realtime | duration.* +| datetime.statement | graph.* +| datetime.transaction | internal.* +| datetime.truncate | localdatetime.* +| db.nameFromElementId | localtime.* +| duration | math.* +| duration.between | plugin.* +| duration.inDays | point.* +| duration.inMonths | stored.* +| duration.inSeconds | string.* +| graph.byElementId | time.* +| graph.byName | tx.* +| graph.names | unsupported.* +| graph.propertiesByName | vector.* +| localdatetime | +| localdatetime.realtime | +| localdatetime.statement | +| localdatetime.transaction | +| localdatetime.truncate | +| localtime | +| localtime.realtime | +| localtime.statement | +| localtime.transaction | +| localtime.truncate | +| point.distance | +| point.withinBBox | +| time | +| time.realtime | +| time.statement | +| time.transaction | +| time.truncate | +| vector.similarity.cosine | +| vector.similarity.euclidean | +|=== \ No newline at end of file diff --git a/modules/ROOT/pages/extending-neo4j/procedures.adoc b/modules/ROOT/pages/extending-neo4j/procedures.adoc index 2d61214..75df9d0 100644 --- a/modules/ROOT/pages/extending-neo4j/procedures.adoc +++ b/modules/ROOT/pages/extending-neo4j/procedures.adoc @@ -143,6 +143,8 @@ Particular things to note: * The procedure annotation can take three optional arguments: `name`, `mode`, and `eager`. ** `name` is used to specify a different name for the procedure than the default generated, which is `class.path.nameOfMethod`. If `mode` is specified, `name` must be specified as well. +** `name` is not allowed in a reserved namespace, and having a `name` without a namespace is deprecated behavior. +** If a procedure is registered with the same name as a built-in procedure in a deprecated namespace, the built-in procedure is shadowed. ** `mode` is used to declare the types of interactions that the procedure performs. A procedure fails if it attempts to execute database operations that violate its mode. The default `mode` is `READ`. @@ -163,7 +165,7 @@ Particular things to note: MATCH (n) WHERE n.key = 'value' WITH n -CALL deleteNeighbours(n, 'FOLLOWS') +CALL example.deleteNeighbours(n, 'FOLLOWS') ---- This query can delete some of the nodes that are matched by the Cypher query, and the `n.key` lookup will fail. Marking this procedure as `eager` prevents this from causing an error in Cypher code. @@ -273,3 +275,28 @@ public class MyProcedures { } ---- + +[[reserved-and-deprecated-namespaces]] +== Reserved and deprecated procedure namespaces + +Note that deprecated procedure namespaces will be moved to reserved in the next major Cypher version. +For more information about Neo4j and Cypher versioning, see link:https://neo4j.com/docs/operations-manual/current/introduction/#_cypher_versions[Operations manual -> Introduction]. +[[reserved-and-deprecated-procedure-namespaces]] +.Overview of reserved and deprecated procedure namespaces +[options="header", cols="m,m"] +|=== +| Reserved | Deprecated in Cypher 25 since Neo4j 2025.11 +| cdc.* | * +| date.* | abac.* +| datetime.* | aura.* +| db.* | builtin.* +| dbms.* | coll.* +| duration.* | math.* +| graph.* | plugin.* +| internal.* | point.* +| localdatetime.* | stored.* +| localtime.* | string.* +| time.* | vector.* +| tx.* | +| unsupported.* | +|=== From 406f85384097ba9a858b3da0020444f5fa86082b Mon Sep 17 00:00:00 2001 From: Louise Berglund Date: Thu, 18 Dec 2025 15:45:10 +0100 Subject: [PATCH 26/48] We have reverted the deprecation of aura.* in product. (#321) --- .../aggregation-functions.adoc | 44 +++++++++---------- .../ROOT/pages/extending-neo4j/functions.adoc | 44 +++++++++---------- .../pages/extending-neo4j/procedures.adoc | 18 ++++---- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/modules/ROOT/pages/extending-neo4j/aggregation-functions.adoc b/modules/ROOT/pages/extending-neo4j/aggregation-functions.adoc index f016a8c..4db23ed 100644 --- a/modules/ROOT/pages/extending-neo4j/aggregation-functions.adoc +++ b/modules/ROOT/pages/extending-neo4j/aggregation-functions.adoc @@ -150,28 +150,28 @@ For more information about Neo4j and Cypher versioning, see link:https://neo4j.c |=== | Reserved | Deprecated in Cypher 25 since Neo4j 2025.11 | * | abac.* -| date | aura.* -| date.realtime | builtin.* -| date.statement | cdc.* -| date.transaction | coll.* -| date.truncate | date.* -| datetime | datetime.* -| datetime.fromepoch | db.* -| datetime.fromepochmillis | dbms.* -| datetime.realtime | duration.* -| datetime.statement | graph.* -| datetime.transaction | internal.* -| datetime.truncate | localdatetime.* -| db.nameFromElementId | localtime.* -| duration | math.* -| duration.between | plugin.* -| duration.inDays | point.* -| duration.inMonths | stored.* -| duration.inSeconds | string.* -| graph.byElementId | time.* -| graph.byName | tx.* -| graph.names | unsupported.* -| graph.propertiesByName | vector.* +| date | builtin.* +| date.realtime | cdc.* +| date.statement | coll.* +| date.transaction | date.* +| date.truncate | datetime.* +| datetime | db.* +| datetime.fromepoch | dbms.* +| datetime.fromepochmillis | duration.* +| datetime.realtime | graph.* +| datetime.statement | internal.* +| datetime.transaction | localdatetime.* +| datetime.truncate | localtime.* +| db.nameFromElementId | math.* +| duration | plugin.* +| duration.between | point.* +| duration.inDays | stored.* +| duration.inMonths | string.* +| duration.inSeconds | time.* +| graph.byElementId | tx.* +| graph.byName | unsupported.* +| graph.names | vector.* +| graph.propertiesByName | | localdatetime | | localdatetime.realtime | | localdatetime.statement | diff --git a/modules/ROOT/pages/extending-neo4j/functions.adoc b/modules/ROOT/pages/extending-neo4j/functions.adoc index b783674..fcfb550 100644 --- a/modules/ROOT/pages/extending-neo4j/functions.adoc +++ b/modules/ROOT/pages/extending-neo4j/functions.adoc @@ -137,28 +137,28 @@ For more information about Neo4j and Cypher versioning, see link:https://neo4j.c |=== | Reserved | Deprecated in Cypher 25 since Neo4j 2025.11 | * | abac.* -| date | aura.* -| date.realtime | builtin.* -| date.statement | cdc.* -| date.transaction | coll.* -| date.truncate | date.* -| datetime | datetime.* -| datetime.fromepoch | db.* -| datetime.fromepochmillis | dbms.* -| datetime.realtime | duration.* -| datetime.statement | graph.* -| datetime.transaction | internal.* -| datetime.truncate | localdatetime.* -| db.nameFromElementId | localtime.* -| duration | math.* -| duration.between | plugin.* -| duration.inDays | point.* -| duration.inMonths | stored.* -| duration.inSeconds | string.* -| graph.byElementId | time.* -| graph.byName | tx.* -| graph.names | unsupported.* -| graph.propertiesByName | vector.* +| date | builtin.* +| date.realtime | cdc.* +| date.statement | coll.* +| date.transaction | date.* +| date.truncate | datetime.* +| datetime | db.* +| datetime.fromepoch | dbms.* +| datetime.fromepochmillis | duration.* +| datetime.realtime | graph.* +| datetime.statement | internal.* +| datetime.transaction | localdatetime.* +| datetime.truncate | localtime.* +| db.nameFromElementId | math.* +| duration | plugin.* +| duration.between | point.* +| duration.inDays | stored.* +| duration.inMonths | string.* +| duration.inSeconds | time.* +| graph.byElementId | tx.* +| graph.byName | unsupported.* +| graph.names | vector.* +| graph.propertiesByName | | localdatetime | | localdatetime.realtime | | localdatetime.statement | diff --git a/modules/ROOT/pages/extending-neo4j/procedures.adoc b/modules/ROOT/pages/extending-neo4j/procedures.adoc index 75df9d0..64d1bfb 100644 --- a/modules/ROOT/pages/extending-neo4j/procedures.adoc +++ b/modules/ROOT/pages/extending-neo4j/procedures.adoc @@ -288,15 +288,15 @@ For more information about Neo4j and Cypher versioning, see link:https://neo4j.c | Reserved | Deprecated in Cypher 25 since Neo4j 2025.11 | cdc.* | * | date.* | abac.* -| datetime.* | aura.* -| db.* | builtin.* -| dbms.* | coll.* -| duration.* | math.* -| graph.* | plugin.* -| internal.* | point.* -| localdatetime.* | stored.* -| localtime.* | string.* -| time.* | vector.* +| datetime.* | builtin.* +| db.* | coll.* +| dbms.* | math.* +| duration.* | plugin.* +| graph.* | point.* +| internal.* | stored.* +| localdatetime.* | string.* +| localtime.* | vector.* +| time.* | | tx.* | | unsupported.* | |=== From 6c6f5e808bf8fd982451858920eb33039b38b35d Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Mon, 22 Dec 2025 10:34:26 +0100 Subject: [PATCH 27/48] Update antora.yml to 2025.12 (#325) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index baa2fd7..b6c5b04 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2025.11' +version: '2025.12' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2025.11' - neo4j-version-exact: '2025.11.0' - neo4j-buildnumber: '2025.11' + neo4j-version: '2025.12' + neo4j-version-exact: '2025.12.0' + neo4j-buildnumber: '2025.12' java-driver-version: '6.0.2' neo4j-documentation-branch: 'dev' page-origin-private: false From 9ce8b0466e70b2416923bfcb4950d193bde5fdd6 Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Fri, 16 Jan 2026 16:38:22 +0100 Subject: [PATCH 28/48] Update antora.yml to 2026.01 (#326) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index b6c5b04..fbae9b5 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2025.12' +version: '2026.01' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2025.12' - neo4j-version-exact: '2025.12.0' - neo4j-buildnumber: '2025.12' + neo4j-version: '2026.01' + neo4j-version-exact: '2026.01.0' + neo4j-buildnumber: '2026.01' java-driver-version: '6.0.2' neo4j-documentation-branch: 'dev' page-origin-private: false From d997cd362860e93a5632b77e64c89ab00bd194cf Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:50:35 +0100 Subject: [PATCH 29/48] DOCS-279 Update antora.yml to 2026.02 (#331) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index fbae9b5..b8b82ea 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2026.01' +version: '2026.02' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2026.01' - neo4j-version-exact: '2026.01.0' - neo4j-buildnumber: '2026.01' + neo4j-version: '2026.02' + neo4j-version-exact: '2026.02.0' + neo4j-buildnumber: '2026.02' java-driver-version: '6.0.2' neo4j-documentation-branch: 'dev' page-origin-private: false From 57019f7660ce3135c09a1a90057be7040ffec239 Mon Sep 17 00:00:00 2001 From: Reneta Popova Date: Thu, 12 Feb 2026 11:37:46 +0000 Subject: [PATCH 30/48] Change copyright: 2025 to copyright: 2026 (#334) --- preview.yml | 2 +- publish.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/preview.yml b/preview.yml index be732e8..62d08e3 100644 --- a/preview.yml +++ b/preview.yml @@ -42,7 +42,7 @@ asciidoc: includePDF: false nonhtmloutput: "" experimental: '' - copyright: 2024 + copyright: 2026 common-license-page-uri: https://neo4j.com/docs/license/ # attributes for doc links to other manuals in publish playbook neo4j-base-uri: https://neo4j.com diff --git a/publish.yml b/publish.yml index 9d06b0a..de4edc5 100644 --- a/publish.yml +++ b/publish.yml @@ -42,7 +42,7 @@ asciidoc: includePDF: false nonhtmloutput: "" experimental: '' - copyright: 2024 + copyright: 2026 common-license-page-uri: https://neo4j.com/docs/license/ # attributes for doc links to other manuals in publish playbook neo4j-base-uri: '' From 9812de94cf72ce8e6c3152591b5da049bf261b75 Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:57:54 +0100 Subject: [PATCH 31/48] Update antora.yml to 2026.03 (#341) --- antora.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/antora.yml b/antora.yml index b8b82ea..c4b919a 100644 --- a/antora.yml +++ b/antora.yml @@ -1,15 +1,15 @@ name: java-reference title: Java Reference -version: '2026.02' +version: '2026.03' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2026.02' - neo4j-version-exact: '2026.02.0' - neo4j-buildnumber: '2026.02' - java-driver-version: '6.0.2' + neo4j-version: '2026.03' + neo4j-version-exact: '2026.03.0' + neo4j-buildnumber: '2026.03' + java-driver-version: '6.0.3' neo4j-documentation-branch: 'dev' page-origin-private: false neo4j-javadocs-base-uri: "{neo4j-docs-base-uri}/java-reference/{neo4j-version}/javadocs" From 8d04c6c6ec09b8cff9e55dfa9337cb874ea01897 Mon Sep 17 00:00:00 2001 From: Hannes Voigt <30618026+hvub@users.noreply.github.com> Date: Tue, 10 Mar 2026 14:09:02 +0100 Subject: [PATCH 32/48] Fix use of non-public method (#339) * fix use of non-public method resolves of SURF-131 * Update traversal-framework-java-api.adoc --------- Co-authored-by: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> --- .../traversal-framework/traversal-framework-java-api.adoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/traversal-framework/traversal-framework-java-api.adoc b/modules/ROOT/pages/traversal-framework/traversal-framework-java-api.adoc index 8007edc..14d7646 100644 --- a/modules/ROOT/pages/traversal-framework/traversal-framework-java-api.adoc +++ b/modules/ROOT/pages/traversal-framework/traversal-framework-java-api.adoc @@ -370,7 +370,7 @@ class MaxWeightPathExpander implements PathExpander filtered.add(relationship); } } - return Iterables.asResourceIterable(filtered); + return ResourceIterable.of(filtered); } @Override @@ -381,6 +381,8 @@ class MaxWeightPathExpander implements PathExpander } ---- +`ResourceIterable.of` is available starting from Neo4j 2026.03. + Here is an example of how to use the custom `PathExpander` and set the initial state: [source, java, role="nocopy"] From 26e6007e29647cfff896c987798ac23faf05f2d4 Mon Sep 17 00:00:00 2001 From: Reneta Popova Date: Thu, 2 Apr 2026 14:03:25 +0100 Subject: [PATCH 33/48] Update the version to 2026.04 (#346) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index c4b919a..dd346da 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2026.03' +version: '2026.04' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2026.03' - neo4j-version-exact: '2026.03.0' - neo4j-buildnumber: '2026.03' + neo4j-version: '2026.04' + neo4j-version-exact: '2026.04.0' + neo4j-buildnumber: '2026.04' java-driver-version: '6.0.3' neo4j-documentation-branch: 'dev' page-origin-private: false From 2b631885b162cc8165cf19c692bf85b355f2cf21 Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Tue, 21 Apr 2026 10:15:17 +0200 Subject: [PATCH 34/48] Update workflows (#347) * Update workflows * Update reference to Traversal Framework * Apply suggestion from @NataliaIvakina --- .github/workflows/docs-deploy-surge.yml | 129 ++++++++++++++---- .github/workflows/docs-generate-html.yml | 92 +++++++++++++ .github/workflows/docs-pr-checks.yml | 25 ++-- .github/workflows/docs-teardown.yml | 16 ++- .../ROOT/pages/java-embedded/traversal.adoc | 2 +- package.json | 38 +++++- 6 files changed, 251 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/docs-generate-html.yml diff --git a/.github/workflows/docs-deploy-surge.yml b/.github/workflows/docs-deploy-surge.yml index 2399928..54035a1 100644 --- a/.github/workflows/docs-deploy-surge.yml +++ b/.github/workflows/docs-deploy-surge.yml @@ -10,6 +10,11 @@ name: "Deploy docs preview" +permissions: + actions: read + contents: read + pull-requests: write + on: workflow_run: workflows: ["Verify docs PR"] @@ -17,18 +22,35 @@ on: - completed jobs: - publish-docs: - # Uncomment this if statement to deploy only when the PR builds cleanly - # if: github.event.workflow_run.conclusion == 'success' + # [Optional] Restrict automatic dpeloyment to PRs from the upstream repo + # For fork PRs, requires manual approval via the "preview" environment. + # For PRs from the main repository this job is skipped and deploy-docs runs immediately. + # Setup: create a "preview" environment in Settings → Environments with required reviewers. + # approve-fork: + # if: github.event.workflow_run.head_repository.full_name != github.repository + # environment: preview + # runs-on: ubuntu-latest + # steps: + # - name: Fork PR approved for deployment + # run: echo "Approved" + + deploy-docs: + # needs: [approve-fork] + # Run when approve-fork succeeded (fork, approved) or was skipped (non-fork). + # Uncomment the conclusion check to deploy only when the PR builds cleanly: + # && github.event.workflow_run.conclusion == 'success' + # if: | + # always() && + # (needs.approve-fork.result == 'success' || needs.approve-fork.result == 'skipped') runs-on: ubuntu-latest steps: - name: "Download built documentation" - uses: actions/github-script@v7 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: RUN_ID: ${{ github.event.workflow_run.id }} - WORKSPACE: ${{ github.workspace }} + ARTIFACT_DIR: ${{ runner.temp }}/artifacts with: script: | var artifacts = await github.rest.actions.listWorkflowRunArtifacts({ @@ -47,7 +69,8 @@ jobs: archive_format: 'zip', }); var fs = require('fs'); - fs.writeFileSync('${{ env.WORKSPACE }}/docs.zip', Buffer.from(downloadDocs.data)); + fs.mkdirSync(process.env.ARTIFACT_DIR + '/docs', { recursive: true }); + fs.writeFileSync(process.env.ARTIFACT_DIR + '/docs/docs.zip', Buffer.from(downloadDocs.data)); var matchArtifactChangelog = artifacts.data.artifacts.filter((artifact) => { return artifact.name == "changelog" @@ -58,27 +81,68 @@ jobs: artifact_id: matchArtifactChangelog.id, archive_format: 'zip', }); - fs.writeFileSync('${{ env.WORKSPACE }}/changelog.zip', Buffer.from(downloadChangelog.data)); + fs.mkdirSync(process.env.ARTIFACT_DIR + '/changelog', { recursive: true }); + fs.writeFileSync(process.env.ARTIFACT_DIR + '/changelog/changelog.zip', Buffer.from(downloadChangelog.data)); + + - id: suspicious-path-check + name: Suspicious paths check + env: + ARTIFACT_DIR: ${{ runner.temp }}/artifacts/docs + run: | + cd "$ARTIFACT_DIR" + if unzip -l docs.zip | grep -q "\.\./"; then + exit 1 + fi + + - id: hidden-files-check + name: Hidden files check + env: + ARTIFACT_DIR: ${{ runner.temp }}/artifacts/docs + run: | + cd "$ARTIFACT_DIR" + HIDDEN_FILES=$(find . -type f -name ".*" | wc -l) + if [ "$HIDDEN_FILES" -ne 0 ]; then + echo "Security Alert: Unexpected hidden files detected!" + exit 1 + fi - id: unzip-docs - run: unzip docs.zip + name: Unzip docs artifact + env: + ARTIFACT_DIR: ${{ runner.temp }}/artifacts/docs + run: | + cd "$ARTIFACT_DIR" + unzip docs.zip - - id: get-top-dir + - id: find-changelog + name: Get changelog run: | - root=$(ls -d */index.html | sed -r 's/(.*)\/index\.html/\1/') - echo "top-dir=$root" >> $GITHUB_OUTPUT + if [ -f "${{ runner.temp }}/artifacts/changelog/changelog.zip" ]; then + echo "has-changelog=true" >> $GITHUB_OUTPUT + else + echo "has-changelog=false" >> $GITHUB_OUTPUT + fi - id: unzip-changelog - if: ${{ hashFiles('changelog.zip') != '' }} - run: unzip changelog.zip + name: Unzip changelog artifact + if: ${{ steps.find-changelog.outputs.has-changelog == 'true' }} + env: + ARTIFACT_DIR: ${{ runner.temp }}/artifacts/changelog + run: | + cd "$ARTIFACT_DIR" + unzip changelog.zip - id: get-deploy-id + name: Get deploy ID + env: + ARTIFACT_DIR: ${{ runner.temp }}/artifacts/docs run: | - deployid=$(> "$GITHUB_OUTPUT" - id: get-deploy-url + name: Get deploy URL env: ORG: ${{ github.event.repository.owner.login }} REPO: ${{ github.event.repository.name }} @@ -87,38 +151,53 @@ jobs: deployurl=$ORG-$REPO-$DEPLOYID.surge.sh echo "deploy-url=$deployurl" >> $GITHUB_OUTPUT - - uses: actions/setup-node@v4 + - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 with: node-version: lts/* + + - id: prepare-deploy-dir + name: Prepare deploy directory + shell: bash + env: + DOCS_SRC_DIR: ${{ runner.temp }}/artifacts/docs + DOCS_DEPLOY_DIR: ${{ runner.temp }}/deploy-docs + run: | + mkdir -p "$DOCS_DEPLOY_DIR" + # Copy only the built docs into a clean directory for deployment + cp -R "$DOCS_SRC_DIR"/. "$DOCS_DEPLOY_DIR"/ - - name: Deploy docs to surge + - id: surge-deploy + name: Deploy docs to surge shell: bash env: DEPLOY_URL: ${{ steps.get-deploy-url.outputs.deploy-url }} SURGE_TOKEN: "${{ secrets.DOCS_SURGE_TOKEN }}" - SITE_DIR: ${{ steps.get-top-dir.outputs.top-dir }} + DEPLOY_DIR: ${{ runner.temp }}/deploy-docs run: | npm install -g surge - surge ./$SITE_DIR $DEPLOY_URL --token "$SURGE_TOKEN" + cd "$DEPLOY_DIR" + surge . "$DEPLOY_URL" --token "$SURGE_TOKEN" # If the PR artifacts include a changelog file, add it to the PR as a comment # The changelog contains links to new and changed files in the deployed docs - - name: Comment on PR (changelog) - if: ${{ hashFiles('changelog') != '' }} - uses: marocchino/sticky-pull-request-comment@331f8f5b4215f0445d3c07b4967662a32a2d3e31 #v2.9.0 + - id: comment-changelog + name: Prepare changelog comment + if: ${{ steps.find-changelog.outputs.has-changelog == 'true' }} + uses: marocchino/sticky-pull-request-comment@70d2764d1a7d5d9560b100cbea0077fc8f633987 #v3 with: number: ${{ steps.get-deploy-id.outputs.deploy-id }} recreate: true header: docs-pr-changes - path: changelog + path: ${{ runner.temp }}/artifacts/changelog/changelog GITHUB_TOKEN: ${{ secrets.DOCS_PR_COMMENT_TOKEN }} # If there's no changelog, add a generic comment to the PR - - name: Comment on PR (no changelog) - if: ${{ hashFiles('changelog') == '' }} + - id: comment-no-changelog + name: Comment on PR (no changelog) + if: ${{ steps.find-changelog.outputs.has-changelog == 'false' }} env: DEPLOY_URL: ${{ steps.get-deploy-url.outputs.deploy-url }} - uses: marocchino/sticky-pull-request-comment@331f8f5b4215f0445d3c07b4967662a32a2d3e31 #v2.9.0 + uses: marocchino/sticky-pull-request-comment@70d2764d1a7d5d9560b100cbea0077fc8f633987 #v3 with: number: ${{ steps.get-deploy-id.outputs.deploy-id }} header: docs-pr-changes diff --git a/.github/workflows/docs-generate-html.yml b/.github/workflows/docs-generate-html.yml new file mode 100644 index 0000000..546fc2e --- /dev/null +++ b/.github/workflows/docs-generate-html.yml @@ -0,0 +1,92 @@ + +name: "Generate HTML" + +# edit the list of branches according to your repository +# the list of branches should contain all the branches in your Antora publish playbooks +on: + push: + branches: + - "main" + - "dev" + - "5.x" + - "4.4" + workflow_dispatch: + +# change `dev` and `main` according to your repository's branch names +# `dev` is the branch you use to build and publish to staging +# `main` is the branch you use to build and publish to neo4j.com/docs +# in some cases, PROD_BRANCH and DEV_BRANCH may be the same branch +env: + DEV_BRANCH: 'dev' + PROD_BRANCH: 'main' + +jobs: + + prepare-ref-env: + name: Set build branch and environments + runs-on: ubuntu-latest + outputs: + build-ref: ${{ steps.set-ref-env.outputs.build-ref }} + environments: ${{ steps.set-ref-env.outputs.environments }} + steps: + - name: Set Build Ref + id: set-ref-env + run: | + if [[ "${GITHUB_REF}" == "refs/heads/${{ env.DEV_BRANCH }}" ]]; then + build_from=${{ env.DEV_BRANCH }} + environments='["dev"]' + else + build_from=${{ env.PROD_BRANCH }} + environments='["prod"]' + fi + # if dev branch = prod branch publish to both + if [[ "${{ env.DEV_BRANCH }}" == "${{ env.PROD_BRANCH }}" ]]; then + environments='["dev","prod"]' + fi + echo "build-ref=${build_from}" >> $GITHUB_OUTPUT + echo "environments=${environments[@]}" >> $GITHUB_OUTPUT + + docs-build: + name: Generate HTML + needs: prepare-ref-env + uses: neo4j/docs-tools/.github/workflows/reusable-docs-build.yml@v2 + with: + package-script: 'verify:publish' + build-ref: ${{needs.prepare-ref-env.outputs.build-ref}} + fetch-depth: 0 + + docs-verify: + name: Verify HTML + needs: docs-build + uses: neo4j/docs-tools/.github/workflows/reusable-docs-verify.yml@v2 + with: + failOnWarnings: true + + publish-html: + name: Publish HTML + needs: [docs-verify, prepare-ref-env] + runs-on: ubuntu-latest + + strategy: + matrix: + environments: ${{ fromJson(needs.prepare-ref-env.outputs.environments) }} + + steps: + - name: Publish to ${{ matrix.environments }} + uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 #v4 + with: + token: ${{ secrets.DOCS_DISPATCH_TOKEN }} + repository: neo4j/docs-publish + event-type: publish-html + client-payload: |- + { + "org": "${{ github.repository_owner }}", + "repo": "${{ github.event.repository.name }}", + "run_id": "${{ github.run_id }}", + "publish_env": "${{ matrix.environments }}" + } + + - name: Echo + if: ${{ matrix.environments == 'prod' }} + run: | + echo "If this step runs then approval has been granted" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/docs-pr-checks.yml b/.github/workflows/docs-pr-checks.yml index 1e0d4b0..bfb342b 100644 --- a/.github/workflows/docs-pr-checks.yml +++ b/.github/workflows/docs-pr-checks.yml @@ -1,19 +1,22 @@ - name: "Verify docs PR" +permissions: + contents: read + pull-requests: read + on: pull_request: branches: - - "main" - - "dev" - - "5.x" - - "4.4" + - "main" + - "dev" + - "5.x" + - "4.4" jobs: # Generate HTML docs-build-pr: - uses: neo4j/docs-tools/.github/workflows/reusable-docs-build.yml@v1.2.0 + uses: neo4j/docs-tools/.github/workflows/reusable-docs-build.yml@v2 with: deploy-id: ${{ github.event.number }} retain-artifacts: 14 @@ -23,7 +26,7 @@ jobs: # By default, the job fails if there are errors, passes if there are warnings only. docs-verify-pr: needs: docs-build-pr - uses: neo4j/docs-tools/.github/workflows/reusable-docs-verify.yml@v1.2.0 + uses: neo4j/docs-tools/.github/workflows/reusable-docs-verify.yml@v2 with: failOnWarnings: true @@ -40,14 +43,14 @@ jobs: steps: - name: Get file changes id: get-file-changes - uses: tj-actions/changed-files@2f7c5bfce28377bc069a65ba478de0a74aa0ca32 # v46.0.1 + uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47 with: separator: ',' files_yaml: | pages: - - modules/**/pages/**/*.adoc + - '**/modules/**/pages/**/*.adoc' asciidoc: - - modules/**/*.adoc + - '**/modules/**/*.adoc' # Generate a PR comment if the docs are using the pageList extension # The extension maps asciidoc source files to their HTML output paths @@ -55,7 +58,7 @@ jobs: docs-updates-comment-pr: if: needs.docs-build-pr.outputs.pages-listed == 'success' needs: [docs-build-pr, docs-changes-pr] - uses: neo4j/docs-tools/.github/workflows/reusable-docs-pr-changes.yml@v1.2.0 + uses: neo4j/docs-tools/.github/workflows/reusable-docs-pr-changes.yml@v2 with: pages-modified: ${{ needs.docs-changes-pr.outputs.pages-modified }} pages-added: ${{ needs.docs-changes-pr.outputs.pages-added }} diff --git a/.github/workflows/docs-teardown.yml b/.github/workflows/docs-teardown.yml index 12d486b..277bd41 100644 --- a/.github/workflows/docs-teardown.yml +++ b/.github/workflows/docs-teardown.yml @@ -1,13 +1,15 @@ # copy this workflow into your repo name: "Documentation Teardown" +permissions: + contents: read + pull-requests: write + on: pull_request_target: branches: - - "main" - - "dev" - - "5.x" - - "4.4" + - main + - dev types: - closed @@ -16,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/setup-node@v4 + - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f #v6 with: node-version: lts/* @@ -39,7 +41,7 @@ jobs: surge teardown $DEPLOY_URL --token "$SURGE_TOKEN" - name: Comment on PR - uses: marocchino/sticky-pull-request-comment@331f8f5b4215f0445d3c07b4967662a32a2d3e31 #v2.9.0 + uses: marocchino/sticky-pull-request-comment@70d2764d1a7d5d9560b100cbea0077fc8f633987 #v3 with: number: ${{ github.event.pull_request.number }} header: docs-pr-changes @@ -48,4 +50,4 @@ jobs: The preview documentation has now been torn down - reopening this PR will republish it. GITHUB_TOKEN: ${{ secrets.DOCS_PR_COMMENT_TOKEN }} - \ No newline at end of file + diff --git a/modules/ROOT/pages/java-embedded/traversal.adoc b/modules/ROOT/pages/java-embedded/traversal.adoc index 6e9d7f8..e9dfe49 100644 --- a/modules/ROOT/pages/java-embedded/traversal.adoc +++ b/modules/ROOT/pages/java-embedded/traversal.adoc @@ -4,7 +4,7 @@ [[java-embedded-traversal]] = Traversing a graph -This page describes how to traverse a graph using the <>. +This page describes how to traverse a graph using the xref:traversal-framework/index.adoc[Traversal Framework]. == The Matrix example diff --git a/package.json b/package.json index 2222a84..a22e239 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,16 @@ "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "nodemon -e adoc --exec \"npm run build && npm run serve\"", + "prestart": "npm update", + "start": "nodemon --exec \"npm run build\"", "serve": "node server.js", - "build": "antora --stacktrace preview.yml", - "build-verify": "antora --stacktrace --fetch preview.yml --log-format=json --log-level=info --log-file ./build/log/log.json", - "publish-verify": "antora --stacktrace --fetch publish.yml --log-format=json --log-file ./build/log/log.json" + "clean": "rm -rf build", + "build": "npm run build:preview", + "postbuild": "node server.js", + "build:preview": "antora preview.yml --stacktrace --log-format=pretty", + "build:publish": "npm run clean && antora publish.yml --stacktrace --log-format=pretty", + "verify:preview": "antora --stacktrace --fetch preview.yml --log-format=json --log-level=info --log-file ./build/log/log.json", + "verify:publish": "antora --stacktrace --fetch publish.yml --log-format=json --log-level=info --log-file ./build/log/log.json" }, "repository": { "type": "git", @@ -23,16 +28,35 @@ }, "homepage": "https://github.com/neo4j/docs-java-reference#readme", "dependencies": { + "@neo4j-antora/aliases-redirects": "^0.2.7", "@neo4j-antora/antora-add-notes": "^0.3.2", "@neo4j-antora/antora-listing-roles": "^0.1.0", "@neo4j-antora/antora-table-footnotes": "^0.3.3", + "@neo4j-antora/mark-terms": "^1.1.4", + "@neo4j-antora/roles-labels": "^0.1.8", "@neo4j-antora/selector-labels": "^0.1.1", + "@neo4j-antora/table-footnotes": "^1.0.1", + "@neo4j-antora/xref-hash-validator": "^0.1.4", "@neo4j-documentation/macros": "^1.0.4", "@neo4j-documentation/remote-include": "^1.0.0", - "antora": "^3.1.10" + "antora": "3.1.14" }, "devDependencies": { - "express": "^5.0.1", - "nodemon": "^3.1.9" + "express": "5.2.1", + "nodemon": "3.1.14" + }, + "nodemonConfig": { + "watch": [ + "**/modules/**", + "**/antora.yml", + "**/preview.yml", + "**/publish.yml" + ], + "ext": "yml,yaml,adoc,svg,png,jpg", + "ignore": [ + "build/**", + "node_modules/**" + ], + "delay": 1000 } } From cb8b474b54d3843dc0392e74bc75c21685ab33a3 Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Thu, 23 Apr 2026 11:44:24 +0200 Subject: [PATCH 35/48] Update Neo4j version to 2026.05 (#352) --- antora.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/antora.yml b/antora.yml index dd346da..29bc936 100644 --- a/antora.yml +++ b/antora.yml @@ -1,15 +1,15 @@ name: java-reference title: Java Reference -version: '2026.04' +version: '2026.05' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2026.04' - neo4j-version-exact: '2026.04.0' - neo4j-buildnumber: '2026.04' - java-driver-version: '6.0.3' + neo4j-version: '2026.05' + neo4j-version-exact: '2026.05.0' + neo4j-buildnumber: '2026.05' + java-driver-version: '6.0.5' neo4j-documentation-branch: 'dev' page-origin-private: false neo4j-javadocs-base-uri: "{neo4j-docs-base-uri}/java-reference/{neo4j-version}/javadocs" From d3ea0185bf1068545194df3255ce0a6f3e2915b9 Mon Sep 17 00:00:00 2001 From: Reneta Popova Date: Fri, 29 May 2026 10:34:46 +0200 Subject: [PATCH 36/48] Update the version to 2026.06 (#356) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index 29bc936..e7b0b4f 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2026.05' +version: '2026.06' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2026.05' - neo4j-version-exact: '2026.05.0' - neo4j-buildnumber: '2026.05' + neo4j-version: '2026.06' + neo4j-version-exact: '2026.06.0' + neo4j-buildnumber: '2026.06' java-driver-version: '6.0.5' neo4j-documentation-branch: 'dev' page-origin-private: false From d1c017408c6b4084fe4b3c00ac6b0bc7ba337ebf Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Wed, 8 Jul 2026 13:42:45 +0200 Subject: [PATCH 37/48] Update version and attributes in antora.yml (#360) * Update version and attributes in antora.yml * Apply suggestion from @NataliaIvakina --- antora.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/antora.yml b/antora.yml index e7b0b4f..b7cf198 100644 --- a/antora.yml +++ b/antora.yml @@ -1,15 +1,15 @@ name: java-reference title: Java Reference -version: '2026.06' +version: '2026.07' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2026.06' - neo4j-version-exact: '2026.06.0' - neo4j-buildnumber: '2026.06' - java-driver-version: '6.0.5' + neo4j-version: '2026.07' + neo4j-version-exact: '2026.07.0' + neo4j-buildnumber: '2026.07' + java-driver-version: '6.2.0' neo4j-documentation-branch: 'dev' page-origin-private: false neo4j-javadocs-base-uri: "{neo4j-docs-base-uri}/java-reference/{neo4j-version}/javadocs" From 6c3f8f997efda6c8516a974b29bef7175f2d0cec Mon Sep 17 00:00:00 2001 From: Neil Dewhurst Date: Tue, 21 Jul 2026 12:14:45 +0100 Subject: [PATCH 38/48] Harden docs-deploy-surge.yml against artifact poisoning (sync from docs-template) (#361) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Syncs .github/workflows/docs-deploy-surge.yml to the canonical neo4j/docs-template version to resolve the critical CodeQL artifact-poisoning alert. Adds: - validate-changelog step (rejects a symlinked changelog before it is read into the PR comment – prevents arbitrary-file-read from a poisoned artifact) - process.env.RUN_ID instead of ${{ env.RUN_ID }} in the github-script step (avoids GitHub Actions expression injection) - extended zipinfo suspicious-path-check: rejects empty archives, absolute paths, path traversal (..), and Windows-style backslash separators No branch or path filters changed. --- .github/workflows/docs-deploy-surge.yml | 47 ++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs-deploy-surge.yml b/.github/workflows/docs-deploy-surge.yml index 54035a1..682c6cf 100644 --- a/.github/workflows/docs-deploy-surge.yml +++ b/.github/workflows/docs-deploy-surge.yml @@ -22,7 +22,7 @@ on: - completed jobs: - # [Optional] Restrict automatic dpeloyment to PRs from the upstream repo + # [Optional] Restrict automatic deployment to PRs from the upstream repo # For fork PRs, requires manual approval via the "preview" environment. # For PRs from the main repository this job is skipped and deploy-docs runs immediately. # Setup: create a "preview" environment in Settings → Environments with required reviewers. @@ -56,7 +56,7 @@ jobs: var artifacts = await github.rest.actions.listWorkflowRunArtifacts({ owner: context.repo.owner, repo: context.repo.repo, - run_id: ${{ env.RUN_ID }}, + run_id: process.env.RUN_ID, }); var matchArtifactDocs = artifacts.data.artifacts.filter((artifact) => { @@ -86,13 +86,32 @@ jobs: - id: suspicious-path-check name: Suspicious paths check + shell: bash env: ARTIFACT_DIR: ${{ runner.temp }}/artifacts/docs run: | + set -euo pipefail cd "$ARTIFACT_DIR" - if unzip -l docs.zip | grep -q "\.\./"; then + + mapfile -t ZIP_ENTRIES < <(zipinfo -1 docs.zip) + if [ "${#ZIP_ENTRIES[@]}" -eq 0 ]; then + echo "docs.zip is empty" exit 1 fi + for entry in "${ZIP_ENTRIES[@]}"; do + if [[ "$entry" =~ ^/ ]]; then + echo "Blocked absolute path in artifact: $entry" + exit 1 + fi + if [[ "$entry" =~ (^|/)\.\.(/|$) ]]; then + echo "Blocked path traversal in artifact: $entry" + exit 1 + fi + if [[ "$entry" == *\\* ]]; then + echo "Blocked Windows-style path separator in artifact: $entry" + exit 1 + fi + done - id: hidden-files-check name: Hidden files check @@ -131,7 +150,27 @@ jobs: run: | cd "$ARTIFACT_DIR" unzip changelog.zip - + + # The changelog file is built from untrusted PR content and its contents + # are posted to the PR as a comment. A malicious artifact could make + # `changelog` a symlink pointing at an arbitrary file the runner can read, + # turning the comment step into an arbitrary-file-read. Reject anything + # that isn't a plain regular file before we read it. + - id: validate-changelog + name: Validate changelog is a regular file + if: ${{ steps.find-changelog.outputs.has-changelog == 'true' }} + env: + CHANGELOG_FILE: ${{ runner.temp }}/artifacts/changelog/changelog + run: | + if [ -L "$CHANGELOG_FILE" ]; then + echo "Security Alert: changelog is a symlink — refusing!" + exit 1 + fi + if [ ! -f "$CHANGELOG_FILE" ]; then + echo "changelog missing or not a regular file" + exit 1 + fi + - id: get-deploy-id name: Get deploy ID env: From cd45b1ed38de87259bba69558979e7690b0d9fa5 Mon Sep 17 00:00:00 2001 From: Reneta Popova Date: Fri, 24 Jul 2026 12:10:35 +0100 Subject: [PATCH 39/48] Remove the edition table and update the links (#362) * Remove the edition table and update the links * apply suggestions --- modules/ROOT/pages/java-embedded/setup.adoc | 23 ++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/modules/ROOT/pages/java-embedded/setup.adoc b/modules/ROOT/pages/java-embedded/setup.adoc index 2b69849..ee6cae6 100644 --- a/modules/ROOT/pages/java-embedded/setup.adoc +++ b/modules/ROOT/pages/java-embedded/setup.adoc @@ -298,12 +298,11 @@ NetBeans:: [[editions]] == Editions -The following table outlines the available editions and their names for use with dependency management tools. +You can choose between the Neo4j Community and Neo4j Enterprise edition artifacts. +The listed dependencies do not contain the implementation, but pull it transitively. -[TIP] -==== -Follow the links in the table for details on dependency configuration with Apache Maven, Apache Buildr, Apache Ivy, Groovy Grape, Grails, and Scala SBT. -==== +The following table contains links to the available editions for use with dependency management tools. +There you can find details on dependency configuration with Apache Maven, Apache Buildr, Apache Ivy, Groovy Grape, Grails, and Scala SBT. .Neo4j editions [cols="<20,<30,<50", options="header"] @@ -314,17 +313,17 @@ Follow the links in the table for details on dependency configuration with Apach | Description | Community -| link:http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.neo4j%22%20AND%20a%3A%22neo4j%22[org.neo4j:neo4j^] +| link:https://central.sonatype.com/artifact/org.neo4j/neo4j/overview[`org.neo4j:neo4j`] | A high-performance, fully ACID transactional graph database. | Enterprise -| link:http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.neo4j%22%20AND%20a%3A%22neo4j-enterprise%22[org.neo4j:neo4j-enterprise^] +| `com.neo4j:neo4j-enterprise` | Adding advanced monitoring, online backup, and clustering. - |=== -Note that the listed dependencies do not contain the implementation, but pull it transitively. -For information regarding licensing, see the link:https://neo4j.com/licensing[Licensing Guide^]. - -Javadocs can be downloaded in JAR files from Maven Central or read in link:{neo4j-javadocs-base-uri}/[Neo4j Javadocs^]. +[TIP] +==== +Javadocs can be downloaded in JAR files from Maven Central or read in link:{neo4j-javadocs-base-uri}/[Neo4j Javadocs]. +For information regarding licensing, see the link:https://neo4j.com/licensing[Licensing Guide]. +==== From 96b6794420312c46ff3dd2353392faa3a0c4570c Mon Sep 17 00:00:00 2001 From: Neil Dewhurst Date: Fri, 31 Jul 2026 14:31:30 +0100 Subject: [PATCH 40/48] DOCOPS-176 Add page-tabs attributes to publish playbook (#366) Adds `page-tabs`, `page-tabs-index` and `page-tabs-group` to `publish.yml`: --- publish.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/publish.yml b/publish.yml index de4edc5..9df1ddd 100644 --- a/publish.yml +++ b/publish.yml @@ -29,6 +29,9 @@ asciidoc: - "@neo4j-antora/antora-listing-roles" - "@neo4j-antora/antora-table-footnotes" attributes: + page-tabs: reference@ + page-tabs-index: 20 + page-tabs-group: dbms page-theme: docs page-type: Docs page-search-type: Docs From 602ba13b003752c3e84c2600f51ffd3bed4d951b Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Wed, 5 Aug 2026 15:30:47 +0200 Subject: [PATCH 41/48] Update version and dependencies in antora.yml (#368) --- antora.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/antora.yml b/antora.yml index b7cf198..91499a4 100644 --- a/antora.yml +++ b/antora.yml @@ -1,15 +1,15 @@ name: java-reference title: Java Reference -version: '2026.07' +version: '2026.08' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2026.07' - neo4j-version-exact: '2026.07.0' - neo4j-buildnumber: '2026.07' - java-driver-version: '6.2.0' + neo4j-version: '2026.08' + neo4j-version-exact: '2026.08.0' + neo4j-buildnumber: '2026.08' + java-driver-version: '6.2.1' neo4j-documentation-branch: 'dev' page-origin-private: false neo4j-javadocs-base-uri: "{neo4j-docs-base-uri}/java-reference/{neo4j-version}/javadocs" From c6c151fa25aee289d3c408d74e0776ae9384bf57 Mon Sep 17 00:00:00 2001 From: Reneta Popova Date: Thu, 10 Sep 2026 12:49:32 +0100 Subject: [PATCH 42/48] Update the version to 2026.09 (#374) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index 91499a4..5108dc1 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2026.08' +version: '2026.09' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2026.08' - neo4j-version-exact: '2026.08.0' - neo4j-buildnumber: '2026.08' + neo4j-version: '2026.09' + neo4j-version-exact: '2026.09.0' + neo4j-buildnumber: '2026.09' java-driver-version: '6.2.1' neo4j-documentation-branch: 'dev' page-origin-private: false From a96929dc6dd1aae2dd3c0a2647f1336c02edf279 Mon Sep 17 00:00:00 2001 From: Reneta Popova Date: Tue, 22 Sep 2026 11:03:55 +0100 Subject: [PATCH 43/48] Document reloadable procedures (#163) Co-authored-by: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Co-authored-by: Neil Dewhurst --- modules/ROOT/content-nav.adoc | 4 +- .../aggregation-functions.adoc | 195 ----- .../extending-neo4j/customized-code.adoc | 105 ++- .../ROOT/pages/extending-neo4j/functions.adoc | 181 ----- .../pages/extending-neo4j/procedures.adoc | 302 -------- .../user-defined-procedures-functions.adoc | 731 ++++++++++++++++++ .../ROOT/pages/traversal-framework/index.adoc | 4 +- .../traversal-framework-example.adoc | 2 +- .../partials/user-procedures-functions.adoc | 8 + 9 files changed, 841 insertions(+), 691 deletions(-) delete mode 100644 modules/ROOT/pages/extending-neo4j/aggregation-functions.adoc delete mode 100644 modules/ROOT/pages/extending-neo4j/functions.adoc delete mode 100644 modules/ROOT/pages/extending-neo4j/procedures.adoc create mode 100644 modules/ROOT/pages/extending-neo4j/user-defined-procedures-functions.adoc create mode 100644 modules/ROOT/partials/user-procedures-functions.adoc diff --git a/modules/ROOT/content-nav.adoc b/modules/ROOT/content-nav.adoc index 16c8b51..7af6e5b 100644 --- a/modules/ROOT/content-nav.adoc +++ b/modules/ROOT/content-nav.adoc @@ -5,9 +5,7 @@ ** xref:extending-neo4j/customized-code.adoc[] ** xref:extending-neo4j/project-setup.adoc[] ** xref:extending-neo4j/values-and-types.adoc[] -** xref:extending-neo4j/procedures.adoc[] -** xref:extending-neo4j/functions.adoc[] -** xref:extending-neo4j/aggregation-functions.adoc[] +** xref:extending-neo4j/user-defined-procedures-functions.adoc[] ** xref:extending-neo4j/security-plugins.adoc[] ** xref:extending-neo4j/full-text-analyzer-provider.adoc[] ** xref:extending-neo4j/unmanaged-extensions.adoc[] diff --git a/modules/ROOT/pages/extending-neo4j/aggregation-functions.adoc b/modules/ROOT/pages/extending-neo4j/aggregation-functions.adoc deleted file mode 100644 index 4db23ed..0000000 --- a/modules/ROOT/pages/extending-neo4j/aggregation-functions.adoc +++ /dev/null @@ -1,195 +0,0 @@ -:description: How to write, test, and deploy a user-defined aggregation function for Neo4j. - -:org-neo4j-procedure-UserAggregationFunction: {neo4j-javadocs-base-uri}/org/neo4j/procedure/UserAggregationFunction.html - - -[[extending-neo4j-aggregation-functions]] -= User-defined aggregation functions - -_User-defined aggregation functions_ are functions that aggregate data and return a single result. -For a comparison between user-defined procedures, functions, and aggregation functions, see xref:extending-neo4j/customized-code.adoc[]. - - -[[call-user-defined-aggregation-function]] -== Call an aggregation function - -User-defined aggregation functions are called in the same way as any other Cypher aggregation function. -The function name must be fully qualified, so a function named `longestString` defined in the package `org.neo4j.examples` could be called using: - -[source, cypher, role="noplay"] ----- -MATCH (p: Person) WHERE p.age = 36 -RETURN org.neo4j.examples.longestString(p.name) ----- - - -[[writing-user-defined-aggregation-function]] -== Writing a user-defined aggregation function - -User-defined aggregation functions are annotated with `@UserAggregationFunction`. -The annotated function must return an instance of an aggregator class. -An aggregator class contains one method annotated with `@UserAggregationUpdate` and one method annotated with `@UserAggregationResult`. -The method annotated with `@UserAggregationUpdate` will be called multiple times and enables the class to aggregate data. -When the aggregation is done, the method annotated with `@UserAggregationResult` will be called once and the result of the aggregation will be returned. - -Particular things to note: - -* All functions are annotated with `@UserAggregationFunction`. -* The aggregation function name must be namespaced and is not allowed in reserved namespaces. -* If a user-defined aggregation function is registered with the same name as a built-in function in a deprecated namespace, the built-in function is shadowed. - - -See xref:extending-neo4j/values-and-types.adoc[] for details on values and types. - -For more details, see the Neo4j Javadocs for link:{org-neo4j-procedure-UserAggregationFunction}[`org.neo4j.procedure.UserAggregationFunction`^]. - -[NOTE] -==== -The correct way to signal an error from within an aggregation function is to throw `RuntimeException`. -==== - -[source, java] ----- -package example; - -import org.neo4j.procedure.Description; -import org.neo4j.procedure.Name; -import org.neo4j.procedure.UserAggregationFunction; -import org.neo4j.procedure.UserAggregationResult; -import org.neo4j.procedure.UserAggregationUpdate; - -public class LongestString -{ - @UserAggregationFunction - @Description( "org.neo4j.function.example.longestString(string) - aggregates the longest string found" ) - public LongStringAggregator longestString() - { - return new LongStringAggregator(); - } - - public static class LongStringAggregator - { - private int longest; - private String longestString; - - @UserAggregationUpdate - public void findLongest( - @Name( "string" ) String string ) - { - if ( string != null && string.length() > longest) - { - longest = string.length(); - longestString = string; - } - } - - @UserAggregationResult - public String result() - { - return longestString; - } - } -} ----- - - -== Integration tests - -Tests for user-defined aggregation functions are created in the same way as those for normal user-defined functions. - - -.A template for testing a user-defined aggregation function that finds the longest string. -[source, java] ----- -package example; - -import org.junit.Rule; -import org.junit.Test; -import org.neo4j.driver.v1.*; -import org.neo4j.harness.junit.Neo4jRule; - -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; - -public class LongestStringTest -{ - // This rule starts a Neo4j instance - @Rule - public Neo4jRule neo4j = new Neo4jRule() - - // This is the function to test - .withAggregationFunction( LongestString.class ); - - @Test - public void shouldAllowIndexingAndFindingANode() throws Throwable - { - // This is in a try-block, to make sure you close the driver after the test - try( Driver driver = GraphDatabase.driver( neo4j.boltURI() , Config.build().withEncryptionLevel( Config.EncryptionLevel.NONE ).toConfig() ) ) - { - // Given - Session session = driver.session(); - - // When - String result = session.run( "UNWIND ["abc", "abcd", "ab"] AS string RETURN example.longestString(string) AS result").single().get("result").asString(); - - // Then - assertThat( result, equalTo( "abcd" ) ); - } - } -} ----- - -[[reserved-and-deprecated-namespaces]] -== Reserved and deprecated function namespaces - -Note that deprecated function namespaces will be moved to reserved in the next major Cypher version. -For more information about Neo4j and Cypher versioning, see link:https://neo4j.com/docs/operations-manual/current/introduction/#_cypher_versions[Operations manual -> Introduction]. -[[reserved-and-deprecated-function-namespaces]] -.Overview of reserved and deprecated function namespaces and names -[options="header", cols="m,m"] -|=== -| Reserved | Deprecated in Cypher 25 since Neo4j 2025.11 -| * | abac.* -| date | builtin.* -| date.realtime | cdc.* -| date.statement | coll.* -| date.transaction | date.* -| date.truncate | datetime.* -| datetime | db.* -| datetime.fromepoch | dbms.* -| datetime.fromepochmillis | duration.* -| datetime.realtime | graph.* -| datetime.statement | internal.* -| datetime.transaction | localdatetime.* -| datetime.truncate | localtime.* -| db.nameFromElementId | math.* -| duration | plugin.* -| duration.between | point.* -| duration.inDays | stored.* -| duration.inMonths | string.* -| duration.inSeconds | time.* -| graph.byElementId | tx.* -| graph.byName | unsupported.* -| graph.names | vector.* -| graph.propertiesByName | -| localdatetime | -| localdatetime.realtime | -| localdatetime.statement | -| localdatetime.transaction | -| localdatetime.truncate | -| localtime | -| localtime.realtime | -| localtime.statement | -| localtime.transaction | -| localtime.truncate | -| point.distance | -| point.withinBBox | -| time | -| time.realtime | -| time.statement | -| time.transaction | -| time.truncate | -| vector.similarity.cosine | -| vector.similarity.euclidean | -|=== - diff --git a/modules/ROOT/pages/extending-neo4j/customized-code.adoc b/modules/ROOT/pages/extending-neo4j/customized-code.adoc index c4b44c5..43aa955 100644 --- a/modules/ROOT/pages/extending-neo4j/customized-code.adoc +++ b/modules/ROOT/pages/extending-neo4j/customized-code.adoc @@ -4,8 +4,8 @@ [[neo4j-customized-code]] = Neo4j customized code -_User-defined procedures_ and _user-defined functions_ are mechanisms that enable you to extend Neo4j by writing customized code, which can be invoked directly from Cypher. -This is the preferred means for extending Neo4j. +Neo4j allows you to extend its functionality by writing your own code using _user-defined_ procedures and functions. +They can be invoked directly from Cypher and are the preferred way of extending Neo4j. Examples of use cases for procedures and functions are: @@ -14,10 +14,23 @@ Examples of use cases for procedures and functions are: * To perform graph-global operations, such as counting connected components or finding dense nodes. * To express a procedural operation that is difficult to express declaratively with Cypher. -Procedures and functions are written in Java and compiled into JAR files. -They are deployed to the database by dropping that JAR file into the _plugins_ directory on each standalone or clustered server. +== Writing user-defined procedures and functions + +Procedures and functions should be implemented in a language within the JVM ecosystem and packaged into a JAR file. +See xref:extending-neo4j/user-defined-procedures-functions.adoc#create-user-defined-procedure-or-function[Create a procedure or function] for details. + +== Deploying user-defined procedures and functions + +Once compiled, these JAR files are deployed to the _NEO4J_HOME/plugins_ directory on each standalone or clustered server. For the location of the _plugins_ directory, refer to link:{neo4j-docs-base-uri}/operations-manual/{page-version}/configuration/file-locations[Operations Manual -> Default file locations]. -The database must be restarted on each server to pick up new procedures and functions. + +label:new[Introduced in 2026.09] label:enterprise-only[] You can use the built-in procedure `dbms.reloadProcedures()` to reload procedures and functions without restarting the DBMS. +See xref:extending-neo4j/user-defined-procedures-functions.adoc#reload-procedures-functions[Reloading procedures and functions] for details. + +include::partial$user-procedures-functions.adoc[] + +[[comparison-of-procedures-and-functions]] +== Comparison of procedures and functions Procedures and functions can take arguments and return results. In addition, procedures can perform write operations on the database. @@ -51,11 +64,89 @@ In addition, procedures can perform write operations on the database. |=== +[[memory-resource-tracking]] +== Memory resource tracking + +[NOTE] +==== +The memory resource tracking API for the procedure framework is available for preview. +Future versions of Neo4j might contain breaking changes to this API. +==== + +If your procedure or function allocates significant amounts of heap memory, you can register allocations to count towards the configured transaction limits, see link:{neo4j-docs-base-uri}/operations-manual/{page-version}/performance/memory-configuration/#memory-configuration-limit-transaction-memory[Operations Manual -> Limit transaction memory usage] for more information. +This allows you to avoid `OutOfMemory` errors and terminate queries instead of causing uncontrollable memory consumption. +Memory allocations also show up in query profiles. + +To do this you need to inject `org.neo4j.procedure.memory.ProcedureMemory` as a field in your procedure/function class. +`ProcedureMemory` has various methods to allow you to register allocations. +For example (see javadocs for a full reference): + +* `ProcedureMemoryTracker newTracker()` creates a new memory resource tracker that is bound to the current transaction. +* `HeapEstimator heapEstimator()` estimates the heap size of classes and instances. +* `HeapTrackingCollectionFactory collections()` lets you create collections that have built-in memory tracking of their internal structure. + +It's usually difficult and time-consuming to implement memory resource tracking. +These are a few considerations and caveats that are worth keeping in mind: + +- Limit the scope of the memory management. + Focus only on parts that can grow significantly in memory and ignore minor underestimation. +- Beware of overestimation by registering allocations of the same instance multiple times. + You can add reference counting or other mechanisms to avoid overestimation if that is a concern. +- It's common not to know the size of an instance before it has been allocated, which may lead you to register allocations after they have already been made. + The memory tracker implementation tries to prevent this by always pre-registering a certain amount of memory in the internal memory pools. +- It's cumbersome in Java to know when an instance has been garbage-collected. + Typically, you register the release of memory at the point when it's possible for that memory to be garbage-collected. + To account for this, memory trackers may internally choose not to register the release of memory instantaneously. +- Testing memory resource tracking can be difficult. + One approach is to use a third-party library, like JAMM (Java Agent for Memory Measurements), and assert that the estimates are close enough for some given input. + + +.A basic example of memory resource tracking in user defined procedures +[source, java] +---- +package org.example; + +import org.neo4j.procedure.Context; +import org.neo4j.procedure.Name; +import org.neo4j.procedure.Procedure; +import org.neo4j.procedure.memory.ProcedureMemory; + +import java.util.Arrays; +import java.util.stream.Stream; + +public class MyProcedures { + + @Context + public ProcedureMemory memory; + + record Output(Long value) {} + + @Procedure("org.example.memoryHungryRange") + public Stream memoryHungryRange(@Name("size") int size) { + final var tracker = memory.newTracker(); + + // Register the allocation of the long array below + tracker.allocateHeap(memory.heapEstimator().sizeOfLongArray(size)); + // The actual allocation + final var result = new long[size]; + + for (int i = 0; i < size; i++) result[i] = i; + + return Arrays.stream(result) + .mapToObj(Output::new) + // Release all registered allocations when the stream is closed + .onClose(tracker::close); + } +} + +---- + +== Built-in procedures and functions + Neo4j also comes bundled with a number of _built-in_ procedures and functions. The available built-in procedures vary depending on edition and mode, as described in link:{neo4j-docs-base-uri}/operations-manual/{page-version}/procedures[Operations Manual -> Procedures]. Running `SHOW PROCEDURES` displays the full list of procedures available in your Neo4j DBMS, including user-defined procedures. The built-in functions are described in link:{neo4j-docs-base-uri}/cypher-manual/current/functions[Cypher Manual -> Functions]. -Running `SHOW FUNCTIONS` displays the full list of all the functions available in your Neo4j DBMS, including user-defined functions. - +Running `SHOW FUNCTIONS` displays the full list of all the functions available in your Neo4j DBMS, including user-defined functions. \ No newline at end of file diff --git a/modules/ROOT/pages/extending-neo4j/functions.adoc b/modules/ROOT/pages/extending-neo4j/functions.adoc deleted file mode 100644 index fcfb550..0000000 --- a/modules/ROOT/pages/extending-neo4j/functions.adoc +++ /dev/null @@ -1,181 +0,0 @@ -:description: How to write, test and deploy a user-defined function for Neo4j. - -:org-neo4j-procedure-UserFunction: {neo4j-javadocs-base-uri}/org/neo4j/procedure/UserFunction.html - - -[[extending-neo4j-functions]] -= User-defined functions - -_User-defined functions_ are simpler forms of procedures that return a single value and are read-only. -Although they are less powerful in capability, they are often easier to use and more efficient than procedures for many common tasks. -For a comparison between user-defined procedures, functions, and aggregation functions see xref:extending-neo4j/customized-code.adoc[]. - - -[[call-udf]] -== Call a user-defined function - -User-defined functions are called in the same way as any other Cypher function. -The function name must be fully qualified, so a function named `join` defined in the package `org.neo4j.examples` could be called using: - -[source, cypher, role="noplay"] ----- -MATCH (p: Person) WHERE p.age = 36 -RETURN org.neo4j.examples.join(collect(p.names)) ----- - - -[[writing-udf]] -== Create a function - -User-defined functions are created similarly to how procedures are created. -But unlike procedures, they are annotated with `@UserFunction` and return a single value instead of a stream of values. - -Particular things to note: - -* All functions are annotated with `@UserFunction`. -* The function name must be namespaced and is not allowed in reserved namespaces. -* If a function is registered with the same name as a built-in function in a deprecated namespace, the built-in function is shadowed. - -See xref:extending-neo4j/values-and-types.adoc[] for details on values and types. - -For more details, see the link:{org-neo4j-procedure-UserFunction}[Neo4j Javadocs for `org.neo4j.procedure.UserFunction`^]. - -[NOTE] -==== -The correct way to signal an error from within a function is to throw `RuntimeException`. -==== - -[source, java] ----- -package example; - -import java.util.List; - -import org.neo4j.procedure.Description; -import org.neo4j.procedure.Name; -import org.neo4j.procedure.UserFunction; - -public class Join -{ - @UserFunction - @Description("example.join(['s1','s2',...], delimiter) - join the given strings with the given delimiter.") - public String join( - @Name("strings") List strings, - @Name(value = "delimiter", defaultValue = ",") String delimiter) { - if (strings == null || delimiter == null) { - return null; - } - return String.join(delimiter, strings); - } -} ----- - - -== Integration tests - -Tests for user-defined functions are created in the same way as those for procedures. - -.A template for testing a user-defined function that joins a list of strings. -[source, java] ----- -package example; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.neo4j.driver.Driver; -import org.neo4j.driver.GraphDatabase; -import org.neo4j.driver.Session; -import org.neo4j.harness.Neo4j; -import org.neo4j.harness.Neo4jBuilders; - -import static org.assertj.core.api.Assertions.assertThat; - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -public class JoinTest { - - private Neo4j embeddedDatabaseServer; - - @BeforeAll - void initializeNeo4j() { - this.embeddedDatabaseServer = Neo4jBuilders.newInProcessBuilder() - .withDisabledServer() - .withFunction(Join.class) - .build(); - } - - @AfterAll - void closeNeo4j() { - this.embeddedDatabaseServer.close(); - } - - @Test - void joinsStrings() { - // This is in a try-block, to make sure we close the driver after the test - try(Driver driver = GraphDatabase.driver(embeddedDatabaseServer.boltURI()); - Session session = driver.session()) { - - // When - String result = session.run( "RETURN example.join(['Hello', 'World']) AS result").single().get("result").asString(); - - // Then - assertThat( result).isEqualTo(( "Hello,World" )); - } - } -} ----- - -[[reserved-and-deprecated-namespaces]] -== Reserved and deprecated function namespaces - -Note that deprecated function namespaces will be moved to reserved in the next major Cypher version. -For more information about Neo4j and Cypher versioning, see link:https://neo4j.com/docs/operations-manual/current/introduction/#_cypher_versions[Operations manual -> Introduction]. -[[reserved-and-deprecated-function-namespaces]] -.Overview of reserved and deprecated function namespaces and names -[options="header", cols="m,m"] -|=== -| Reserved | Deprecated in Cypher 25 since Neo4j 2025.11 -| * | abac.* -| date | builtin.* -| date.realtime | cdc.* -| date.statement | coll.* -| date.transaction | date.* -| date.truncate | datetime.* -| datetime | db.* -| datetime.fromepoch | dbms.* -| datetime.fromepochmillis | duration.* -| datetime.realtime | graph.* -| datetime.statement | internal.* -| datetime.transaction | localdatetime.* -| datetime.truncate | localtime.* -| db.nameFromElementId | math.* -| duration | plugin.* -| duration.between | point.* -| duration.inDays | stored.* -| duration.inMonths | string.* -| duration.inSeconds | time.* -| graph.byElementId | tx.* -| graph.byName | unsupported.* -| graph.names | vector.* -| graph.propertiesByName | -| localdatetime | -| localdatetime.realtime | -| localdatetime.statement | -| localdatetime.transaction | -| localdatetime.truncate | -| localtime | -| localtime.realtime | -| localtime.statement | -| localtime.transaction | -| localtime.truncate | -| point.distance | -| point.withinBBox | -| time | -| time.realtime | -| time.statement | -| time.transaction | -| time.truncate | -| vector.similarity.cosine | -| vector.similarity.euclidean | -|=== \ No newline at end of file diff --git a/modules/ROOT/pages/extending-neo4j/procedures.adoc b/modules/ROOT/pages/extending-neo4j/procedures.adoc deleted file mode 100644 index 64d1bfb..0000000 --- a/modules/ROOT/pages/extending-neo4j/procedures.adoc +++ /dev/null @@ -1,302 +0,0 @@ -:description: How to write, test, and deploy a user-defined procedure for Neo4j. - -:procedure-template-url: https://github.com/neo4j-examples/neo4j-procedure-template/ - - -[[extending-neo4j-procedures]] -= User-defined procedures - -A _user-defined procedure_ is a mechanism that enables you to extend Neo4j by writing customized code, which can be invoked directly from Cypher. -Procedures can take arguments, perform operations on the database, and return results. -For a comparison between user-defined procedures, functions, and aggregation functions see xref:extending-neo4j/customized-code.adoc[]. - -[NOTE] -==== -User-defined procedures requiring execution on the system database need to include the annotation `@SystemProcedure` or they will be classed as a user database procedure. -==== - -[[call-procedure]] -== Call a procedure - -To call a user-defined procedure, use a Cypher `CALL` clause. -The procedure name must be fully qualified, so a procedure named `findDenseNodes` defined in the package `org.neo4j.examples` could be called using: - -[source, cypher, role="noplay"] ----- -CALL org.neo4j.examples.findDenseNodes(1000) ----- - -`CALL` may be the only clause within a Cypher statement or may be combined with other clauses. -Arguments can be supplied directly within the query or taken from the associated parameter set. -For full details, see the documentation in link:{neo4j-docs-base-uri}/cypher-manual/current/clauses/call[Cypher Manual -> `CALL` procedure]. - - -[[user-defined-procedures]] -== Create a procedure - -Make sure you have read and followed the preparatory setup instructions in xref:extending-neo4j/project-setup.adoc[]. - -[TIP] -==== -The example discussed below is available as link:{procedure-template-url}[a repository on GitHub^]. -To get started quickly you can fork the repository and work with the code as you follow along in the guide below. -==== - -First, decide what the procedure should do, then write a test that proves that it does it right. -Finally, write a procedure that passes the test. - -== Integration tests - -The test dependencies include _Neo4j Harness_ and _JUnit_. -These can be used to write integration tests for procedures. -The tests should start a Neo4j instance, load the procedure, and execute queries against it. - -.An example using JUnit 5 for testing a procedure that returns relationship types found in the graph. -[source, java] ----- -package example; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.neo4j.driver.Driver; -import org.neo4j.driver.GraphDatabase; -import org.neo4j.driver.Record; -import org.neo4j.driver.Result; -import org.neo4j.driver.Session; -import org.neo4j.driver.Value; -import org.neo4j.harness.Neo4j; -import org.neo4j.harness.Neo4jBuilders; - -import static org.assertj.core.api.Assertions.assertThat; - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -public class GetRelationshipTypesTests { - - private Driver driver; - private Neo4j embeddedDatabaseServer; - - @BeforeAll - void initializeNeo4j() { - this.embeddedDatabaseServer = Neo4jBuilders.newInProcessBuilder() - .withDisabledServer() - .withProcedure(GetRelationshipTypes.class) - .build(); - - this.driver = GraphDatabase.driver(embeddedDatabaseServer.boltURI()); - } - - @AfterAll - void closeDriver(){ - this.driver.close(); - this.embeddedDatabaseServer.close(); - } - - @AfterEach - void cleanDb(){ - try(Session session = driver.session()) { - session.run("MATCH (n) DETACH DELETE n"); - } - } - - /** - * We should be getting the correct values when there is only one type in each direction - */ - @Test - public void shouldReturnTheTypesWhenThereIsOneEachWay() { - final String expectedIncoming = "INCOMING"; - final String expectedOutgoing = "OUTGOING"; - - // In a try-block, to make sure we close the session after the test - try(Session session = driver.session()) { - - //Create our data in the database. - session.run(String.format("CREATE (:Person)-[:%s]->(:Movie {id:1})-[:%s]->(:Person)", expectedIncoming, expectedOutgoing)); - - //Execute our procedure against it. - Record record = session.run("MATCH (u:Movie {id:1}) CALL example.getRelationshipTypes(u) YIELD outgoing, incoming RETURN outgoing, incoming").single(); - - //Get the incoming / outgoing relationships from the result - assertThat(record.get("incoming").asList(Value::asString)).containsOnly(expectedIncoming); - assertThat(record.get("outgoing").asList(Value::asString)).containsOnly(expectedOutgoing); - } - } -} ----- - -[NOTE] -==== -The previous example uses JUnit 5, which requires the use of `org.neo4j.harness.junit.extension.Neo4jExtension`. -If you want to use JUnit 4 with Neo4j 4.x or 5, use `org.neo4j.harness.junit.rule.Neo4jRule` instead. -==== - -== Define a procedure - -With the test in place, write a procedure that fulfills the expectations of the test. -The full example is available in the link:{procedure-template-url}[Neo4j Procedure Template^] repository. - -Particular things to note: - -* All procedures are annotated `@Procedure`. -* The procedure annotation can take three optional arguments: `name`, `mode`, and `eager`. -** `name` is used to specify a different name for the procedure than the default generated, which is `class.path.nameOfMethod`. - If `mode` is specified, `name` must be specified as well. -** `name` is not allowed in a reserved namespace, and having a `name` without a namespace is deprecated behavior. -** If a procedure is registered with the same name as a built-in procedure in a deprecated namespace, the built-in procedure is shadowed. -** `mode` is used to declare the types of interactions that the procedure performs. - A procedure fails if it attempts to execute database operations that violate its mode. - The default `mode` is `READ`. - The following modes are available: -*** `READ` -- This procedure only performs read operations against the graph. -*** `WRITE` -- This procedure performs read and write operations against the graph. -*** `SCHEMA` -- This procedure performs operations against the schema, i.e. create and drop indexes and constraints. - A procedure with this mode can read graph data, but not write. -*** `DBMS` -- This procedure performs system operations such as user management and query management. - A procedure with this mode is not able to read or write graph data. -** `eager` is a boolean setting defaulting to `false`. - If it is set to `true`, the Cypher planner plans an extra `eager` operation before and after calling the procedure. - This is useful in cases where the procedure makes changes to the database in a way that could interact with the operations preceding or following the procedure. - For example: -+ -[source, cypher] ----- -MATCH (n) -WHERE n.key = 'value' -WITH n -CALL example.deleteNeighbours(n, 'FOLLOWS') ----- -This query can delete some of the nodes that are matched by the Cypher query, and the `n.key` lookup will fail. -Marking this procedure as `eager` prevents this from causing an error in Cypher code. -However, it is still possible for the procedure to interfere with itself by trying to read entities it has previously deleted. -It is the responsibility of the procedure author to handle that case. -* The _context_ of the procedure, which is the same as each resource that the procedure wants to use, is annotated `@Context`. - -[NOTE] -==== -The correct way to signal an error from within a procedure is to throw `RuntimeException`. -==== - - -[[injectable-resources]] -== Injectable resources - -When writing procedures, some resources can be injected into the procedure from the database. -To inject these, use the `@Context` annotation. -The classes that can be injected are: - -* `Log` -* `TerminationGuard` -* `GraphDatabaseService` -* `Transaction` -//* `SecurityContext` -//* `ProcedureTransaction` -//* `ProcedureMemory` Candidate for public API but not stable yet - -All of the above classes are considered safe and future-proof and do not compromise the security of the database. -Several unsupported (restricted) classes can also be injected and can be changed with little or no notice. -Procedures written to use these restricted APIs are not loaded by default, and you need to use the `dbms.security.procedures.unrestricted` to load unsafe procedures. -Read more about this config setting in link:{neo4j-docs-base-uri}/operations-manual/{page-version}/security/securing-extensions[Operations Manual -> Securing extensions]. - -[[memory-resource-tracking]] -== Memory Resource Tracking - -[NOTE] -==== -The memory resource tracking API for the procedure framework is available for preview. -Future versions of Neo4j might contain breaking changes to this API. -==== - -If your procedure or function allocates significant amounts of heap memory, you can register allocations to count towards the configured transaction limits, see link:{neo4j-docs-base-uri}/operations-manual/{page-version}/performance/memory-configuration/#memory-configuration-limit-transaction-memory[Operations Manual -> Limit transaction memory usage] for more information. -This allows you to avoid `OutOfMemory` errors that cause database restarts. -Memory allocations also show up in query profiles. - -To do this you need to inject `org.neo4j.procedure.memory.ProcedureMemory` as a field in your procedure/function class. -`ProcedureMemory` has various methods to allow you to register allocations. -For example (see javadocs for a full reference): - -* `ProcedureMemoryTracker newTracker()` creates a new memory resource tracker that is bound to the current transaction. -* `HeapEstimator heapEstimator()` estimates the heap size of classes and instances. -* `HeapTrackingCollectionFactory collections()` lets you create collections that have built-in memory tracking of their internal structure. - -It's usually difficult and time-consuming to implement memory resource tracking. -These are a few considerations and caveats that are worth keeping in mind: - -- Limit the scope of the memory management. - Focus only on parts that can grow significantly in memory and ignore minor underestimation. -- Beware of overestimation by registering allocations of the same instance multiple times. - You can add reference counting or other mechanisms to avoid overestimation if that is a concern. -- It's common not to know the size of an instance before it has been allocated, which may lead you to register allocations after they have already been made. - The memory tracker implementation tries to prevent this by always pre-registering a certain amount of memory in the internal memory pools. -- It's cumbersome in Java to know when an instance has been garbage-collected. - Typically, you register the release of memory at the point when it's possible for that memory to be garbage-collected. - To account for this, memory trackers may internally choose not to register the release of memory instantaneously. -- Testing memory resource tracking can be difficult. - One approach is to use a third-party library, like JAMM (Java Agent for Memory Measurements), and assert that the estimates are close enough for some given input. - - -.A basic example of memory resource tracking in user defined procedures. -[source, java] ----- -package org.example; - -import org.neo4j.procedure.Context; -import org.neo4j.procedure.Name; -import org.neo4j.procedure.Procedure; -import org.neo4j.procedure.memory.ProcedureMemory; - -import java.util.Arrays; -import java.util.stream.Stream; - -public class MyProcedures { - - @Context - public ProcedureMemory memory; - - record Output(Long value) {} - - @Procedure("org.example.memoryHungryRange") - public Stream memoryHungryRange(@Name("size") int size) { - final var tracker = memory.newTracker(); - - // Register the allocation of the long array below - tracker.allocateHeap(memory.heapEstimator().sizeOfLongArray(size)); - // The actual allocation - final var result = new long[size]; - - for (int i = 0; i < size; i++) result[i] = i; - - return Arrays.stream(result) - .mapToObj(Output::new) - // Release all registered allocations when the stream is closed - .onClose(tracker::close); - } -} - ----- - -[[reserved-and-deprecated-namespaces]] -== Reserved and deprecated procedure namespaces - -Note that deprecated procedure namespaces will be moved to reserved in the next major Cypher version. -For more information about Neo4j and Cypher versioning, see link:https://neo4j.com/docs/operations-manual/current/introduction/#_cypher_versions[Operations manual -> Introduction]. -[[reserved-and-deprecated-procedure-namespaces]] -.Overview of reserved and deprecated procedure namespaces -[options="header", cols="m,m"] -|=== -| Reserved | Deprecated in Cypher 25 since Neo4j 2025.11 -| cdc.* | * -| date.* | abac.* -| datetime.* | builtin.* -| db.* | coll.* -| dbms.* | math.* -| duration.* | plugin.* -| graph.* | point.* -| internal.* | stored.* -| localdatetime.* | string.* -| localtime.* | vector.* -| time.* | -| tx.* | -| unsupported.* | -|=== diff --git a/modules/ROOT/pages/extending-neo4j/user-defined-procedures-functions.adoc b/modules/ROOT/pages/extending-neo4j/user-defined-procedures-functions.adoc new file mode 100644 index 0000000..1b40796 --- /dev/null +++ b/modules/ROOT/pages/extending-neo4j/user-defined-procedures-functions.adoc @@ -0,0 +1,731 @@ +:description: How to write, test, and deploy a user-defined procedure, function, or aggregation function for Neo4j. + +:procedure-template-url: https://github.com/neo4j-examples/neo4j-procedure-template/ +:org-neo4j-procedure-UserFunction: {neo4j-javadocs-base-uri}/org/neo4j/procedure/UserFunction.html +:org-neo4j-procedure-UserAggregationFunction: {neo4j-javadocs-base-uri}/org/neo4j/procedure/UserAggregationFunction.html + +[[extending-neo4j-procedures-and-functions]] += User-defined procedures and functions + +Defining procedures and functions enables you to extend Neo4j by writing customized code, which can be invoked directly from Cypher. +Procedures and functions can take arguments, perform operations on the database, and return results. + +* _User-defined procedures_ are the most powerful form of customization, allowing you to perform complex operations and return multiple results. +* _User-defined functions_ are simpler forms of procedures that return a single value and are read-only. +Although they are less powerful in capability, they are often easier to use and more efficient than procedures for many common tasks. +* _User-defined aggregation functions_ are functions that aggregate data and return a single result. + +For a comparison between user-defined procedures, functions, and aggregation functions, see xref:extending-neo4j/customized-code.adoc#comparison-of-procedures-and-functions[Comparison of procedures and functions]. + +[NOTE] +==== +User-defined procedures requiring execution on the system database need to include the annotation `@SystemProcedure` or they will be classified as standard database procedures. +==== + +[[create-user-defined-procedure-or-function]] +== Create a procedure or function + +Make sure you have read and followed the preparatory setup instructions in xref:extending-neo4j/project-setup.adoc[]. + +[TIP] +==== +The example discussed below is available as link:{procedure-template-url}[a repository on GitHub^]. +To get started quickly you can fork the repository and work with the code as you follow along in the guide below. +==== + +First, decide what the procedure, function, or aggregation function should do, then write a test that proves that it does it right. +Finally, write a procedure, function, or aggregation function that passes the test. + +=== Create integration tests + +You can use the test dependencies _Neo4j Harness_ and _JUnit_ to write integration tests for your procedure, function, or aggregation function. +The tests should start a Neo4j server, load the procedure, and execute queries against it. + +[.tabbed-example] +===== +[.include-with-procedure-integration-tests] +====== +The following is an example using Neo4j Harness and JUnit 5 for testing a procedure that returns relationship types found in the graph: + +[source, java] +---- +package example; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.Record; +import org.neo4j.driver.Result; +import org.neo4j.driver.Session; +import org.neo4j.driver.Value; +import org.neo4j.harness.Neo4j; +import org.neo4j.harness.Neo4jBuilders; + +import static org.assertj.core.api.Assertions.assertThat; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class GetRelationshipTypesTests { + + private Driver driver; + private Neo4j embeddedDatabaseServer; + + @BeforeAll + void initializeNeo4j() { + this.embeddedDatabaseServer = Neo4jBuilders.newInProcessBuilder() + .withDisabledServer() + .withProcedure(GetRelationshipTypes.class) + .build(); + + this.driver = GraphDatabase.driver(embeddedDatabaseServer.boltURI()); + } + + @AfterAll + void closeDriver(){ + this.driver.close(); + this.embeddedDatabaseServer.close(); + } + + @AfterEach + void cleanDb(){ + try(Session session = driver.session()) { + session.run("MATCH (n) DETACH DELETE n"); + } + } + + /** + * We should be getting the correct values when there is only one type in each direction + */ + @Test + public void shouldReturnTheTypesWhenThereIsOneEachWay() { + final String expectedIncoming = "INCOMING"; + final String expectedOutgoing = "OUTGOING"; + + // In a try-block, to make sure we close the session after the test + try(Session session = driver.session()) { + + //Create our data in the database. + session.run(String.format("CREATE (:Person)-[:%s]->(:Movie {id:1})-[:%s]->(:Person)", expectedIncoming, expectedOutgoing)); + + //Execute our procedure against it. + Record record = session.run("MATCH (u:Movie {id:1}) CALL example.getRelationshipTypes(u) YIELD outgoing, incoming RETURN outgoing, incoming").single(); + + //Get the incoming / outgoing relationships from the result + assertThat(record.get("incoming").asList(Value::asString)).containsOnly(expectedIncoming); + assertThat(record.get("outgoing").asList(Value::asString)).containsOnly(expectedOutgoing); + } + } +} +---- +====== +[.include-with-function-integration-tests] +====== + +The following is an example that uses Neo4j Harness for testing a user-defined function that joins a list of strings: + +[source, java] +---- +package example; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.Session; +import org.neo4j.harness.Neo4j; +import org.neo4j.harness.Neo4jBuilders; + +import static org.assertj.core.api.Assertions.assertThat; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class JoinTest { + + private Neo4j embeddedDatabaseServer; + + @BeforeAll + void initializeNeo4j() { + this.embeddedDatabaseServer = Neo4jBuilders.newInProcessBuilder() + .withDisabledServer() + .withFunction(Join.class) + .build(); + } + + @AfterAll + void closeNeo4j() { + this.embeddedDatabaseServer.close(); + } + + @Test + void joinsStrings() { + // This is in a try-block, to make sure we close the driver after the test + try(Driver driver = GraphDatabase.driver(embeddedDatabaseServer.boltURI()); + Session session = driver.session()) { + + // When + String result = session.run( "RETURN example.join(['Hello', 'World']) AS result").single().get("result").asString(); + + // Then + assertThat( result).isEqualTo(( "Hello,World" )); + } + } +} +---- + +====== +[.include-with-aggregation-function-integration-tests] +====== + +The following is an example that uses Neo4j Harness and JUnit 5 for testing a user-defined aggregation function that finds the longest string: + +[source, java] +---- +package example; + +import org.junit.Rule; +import org.junit.Test; +import org.neo4j.driver.v1.*; +import org.neo4j.harness.junit.Neo4jRule; + +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; + +public class LongestStringTest +{ + // This rule starts a Neo4j instance + @Rule + public Neo4jRule neo4j = new Neo4jRule() + + // This is the function to test + .withAggregationFunction( LongestString.class ); + + @Test + public void shouldAllowIndexingAndFindingANode() throws Throwable + { + // This is in a try-block, to make sure you close the driver after the test + try( Driver driver = GraphDatabase.driver( neo4j.boltURI() , Config.build().withEncryptionLevel( Config.EncryptionLevel.NONE ).toConfig() ) ) + { + // Given + Session session = driver.session(); + + // When + String result = session.run( "UNWIND ["abc", "abcd", "ab"] AS string RETURN example.longestString(string) AS result").single().get("result").asString(); + + // Then + assertThat( result, equalTo( "abcd" ) ); + } + } +} +---- + +====== +===== + + +=== Define your procedure, function, or aggregation function + +With the test in place, write a procedure, function, or aggregation function that fulfills the expectations of the test. +The full example is available in the link:{procedure-template-url}[Neo4j Procedure Template^] repository. + +See xref:extending-neo4j/values-and-types.adoc[] for details on values and types. + +Particular things to note: + +[.tabbed-example] +===== +[.include-with-procedures] +====== + +* All procedures are annotated `@Procedure`. +* The procedure annotation can take three optional arguments: `name`, `mode`, and `eager`. +** `name` is used to specify a different name for the procedure than the default generated, which is `class.path.nameOfMethod`. + If `mode` is specified, `name` must be specified as well. +** `name` is not allowed in a reserved namespace, and having a `name` without a namespace is deprecated behavior. +** If a procedure is registered with the same name as a built-in procedure in a deprecated namespace, the built-in procedure is shadowed. +** `mode` is used to declare the types of interactions that the procedure performs. + A procedure fails if it attempts to execute database operations that violate its mode. + The default `mode` is `READ`. + The following modes are available: +*** `READ` -- This procedure only performs read operations against the graph. +*** `WRITE` -- This procedure performs read and write operations against the graph. +*** `SCHEMA` -- This procedure performs operations against the schema, i.e. create and drop indexes and constraints. + A procedure with this mode can read graph data, but not write. +*** `DBMS` -- This procedure performs system operations such as user management and query management. + A procedure with this mode is not able to read or write graph data. +** `eager` is a boolean setting defaulting to `false`. + If it is set to `true`, the Cypher planner plans an extra `eager` operation before and after calling the procedure. + This is useful in cases where the procedure makes changes to the database in a way that could interact with the operations preceding or following the procedure. + For example: ++ +[source, cypher] +---- +MATCH (n) +WHERE n.key = 'value' +WITH n +CALL example.deleteNeighbours(n, 'FOLLOWS') +---- +This query can delete some of the nodes that are matched by the Cypher query, and the `n.key` lookup will fail. +Marking this procedure as `eager` prevents this from causing an error in Cypher code. +However, it is still possible for the procedure to interfere with itself by trying to read entities it has previously deleted. +It is the responsibility of the procedure author to handle that case. +* The _context_ of the procedure, which is the same as each resource that the procedure wants to use, is annotated `@Context`. + +====== +[.include-with-functions] +====== + +* All functions are annotated with `@UserFunction`. +* The function name must be namespaced and is not allowed in reserved namespaces. +* If a function is registered with the same name as a built-in function in a deprecated namespace, the built-in function is shadowed. + +For more details, see the link:{org-neo4j-procedure-UserFunction}[Neo4j Javadocs for `org.neo4j.procedure.UserFunction`^]. + +====== +[.include-with-aggregation-functions] +====== + +* All functions are annotated with `@UserAggregationFunction`. +* The annotated function must return an instance of an aggregator class. +* An aggregator class contains one method annotated with `@UserAggregationUpdate` and one method annotated with `@UserAggregationResult`. +The method annotated with `@UserAggregationUpdate` is called multiple times and enables the class to aggregate data. +When the aggregation is done, the method annotated with `@UserAggregationResult` is called once and the result of the aggregation is returned. +* The aggregation function name must be namespaced and is not allowed in reserved namespaces. +* If a user-defined aggregation function is registered with the same name as a built-in function in a deprecated namespace, the built-in function is shadowed. + +For more details, see the Neo4j Javadocs for link:{org-neo4j-procedure-UserAggregationFunction}[`org.neo4j.procedure.UserAggregationFunction`^]. + +====== +===== + +[NOTE] +==== +The correct way to signal an error from within an aggregation function is to throw `RuntimeException`. +==== + +=== Write your user-defined procedure, function, and aggregation function + +The following examples show how to write a user-defined procedure, function, and aggregation function. + +[.tabbed-example] +===== +[.include-with-procedure-example] +====== + +The following is an example of a user-defined procedure that returns all nodes in the graph: + +[source, java] +---- +package example; + +import java.util.stream.Stream; + +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.ResourceIterator; +import org.neo4j.graphdb.Transaction; +import org.neo4j.procedure.Context; +import org.neo4j.procedure.Mode; +import org.neo4j.procedure.Procedure; + +/** + * This is an example returning {@link org.neo4j.graphdb.Entity Entities} from stored procedures. + * {@link Node Nodes} and {@link org.neo4j.graphdb.Relationship relationships} are both entities + * and can only be accessed in their transaction. So it is important that you use the injected one + * and not open a new one; otherwise you can access them from the outside. + */ +public class EntityResultExample { + + @Context + public Transaction tx; + + public record EntityContainer(Node node) { + } + + @Procedure(name = "example.allnodes", mode = Mode.READ) + public Stream allnodes() { + ResourceIterator nodes = tx.execute("MATCH (n) RETURN n").columnAs("n"); + return nodes.stream().map(EntityContainer::new); + } +} +---- + +====== +[.include-with-function-example] +====== + +The following is an example of a user-defined function that joins a list of strings with a given delimiter: + +[source, java] +---- +package example; + +import java.util.List; + +import org.neo4j.procedure.Description; +import org.neo4j.procedure.Name; +import org.neo4j.procedure.UserFunction; + +/** + * This is an example how you can create a simple user-defined function for Neo4j. + */ +public class Join { + + @UserFunction + @Description("example.join(['s1','s2',...], delimiter) - join the given strings with the given delimiter.") + public String join( + @Name("strings") List strings, + @Name(value = "delimiter", defaultValue = ",") String delimiter) { + if (strings == null || delimiter == null) { + return null; + } + return String.join(delimiter, strings); + } +} +---- + +====== +[.include-with-aggregation-function-example] +====== +The following is an example of a user-defined aggregation function that finds the longest string: + +[source, java] +---- +package example; + +import org.neo4j.procedure.Description; +import org.neo4j.procedure.Name; +import org.neo4j.procedure.UserAggregationFunction; +import org.neo4j.procedure.UserAggregationResult; +import org.neo4j.procedure.UserAggregationUpdate; + +public class LongestString +{ + @UserAggregationFunction + @Description( "org.neo4j.function.example.longestString(string) - aggregates the longest string found" ) + public LongStringAggregator longestString() + { + return new LongStringAggregator(); + } + + public static class LongStringAggregator + { + private int longest; + private String longestString; + + @UserAggregationUpdate + public void findLongest( + @Name( "string" ) String string ) + { + if ( string != null && string.length() > longest) + { + longest = string.length(); + longestString = string; + } + } + + @UserAggregationResult + public String result() + { + return longestString; + } + } +} +---- +====== +===== + +[[injectable-resources]] +=== Injectable resources + +When writing procedures, functions, or aggregation functions, some resources can be injected into the procedure from the database. +To inject these, use the `@Context` annotation. +The classes that can be injected are: + +* `Log` +* `TerminationGuard` +* `GraphDatabaseService` +* `Transaction` +//* `SecurityContext` +//* `ProcedureTransaction` +//* `ProcedureMemory` Candidate for public API but not stable yet + +All of the above classes are considered safe and future-proof and do not compromise the security of the database. +Several unsupported (restricted) classes can also be injected and can be changed with little or no notice. +Procedure, functions, and aggregation functions written to use these restricted APIs are not loaded by default, and you need to use the `dbms.security.procedures.unrestricted` to load them. +Read more about this config setting in link:{neo4j-docs-base-uri}/operations-manual/{page-version}/security/securing-extensions[Operations Manual -> Securing extensions]. + +[[call-procedure-or-function]] +== Call user-defined procedures or functions + +You can call user-defined procedures and functions from Cypher queries in the same way as built-in procedures and functions. + +[.tabbed-example] +===== +[.include-with-call-procedures] +====== +To call a user-defined procedure, use a Cypher `CALL` clause. +The procedure name must be fully qualified, so a procedure named `findDenseNodes` defined in the package `org.neo4j.examples` could be called using: + +[source, cypher, role="noplay"] +---- +CALL org.neo4j.examples.findDenseNodes(1000) +---- + +`CALL` may be the only clause within a Cypher statement or may be combined with other clauses. +Arguments can be supplied directly within the query or taken from the associated parameter set. +For full details, see the documentation in link:{neo4j-docs-base-uri}/cypher-manual/current/clauses/call[Cypher Manual -> `CALL` procedure]. + +====== + +[.include-with-call-functions] +====== +User-defined functions are called in the same way as any other Cypher function. +The function name must be fully qualified, so a function named `join` defined in the package `org.neo4j.examples` could be called using: + +[source, cypher, role="noplay"] +---- +MATCH (p: Person) WHERE p.age = 36 +RETURN org.neo4j.examples.join(collect(p.names)) +---- + +====== +[.include-with-call-aggregation-functions] +====== + +User-defined aggregation functions are called in the same way as any other Cypher aggregation function. +The function name must be fully qualified, so a function named `longestString` defined in the package `org.neo4j.examples` could be called using: + +[source, cypher, role="noplay"] +---- +MATCH (p: Person) WHERE p.age = 36 +RETURN org.neo4j.examples.longestString(p.name) +---- +====== +===== + +[role=label--new-2026.09 label--enterprise-only label--admin-only label--cypher-25] +[[reload-procedures-functions]] +== Reload procedures and functions + +You can use the built-in procedure `dbms.reloadProcedures()` to reload the user supplied procedure or function JAR files from the _plugins_ directory into a running Neo4j, without restarting it. +This procedure is not supported on Windows. + +For more information about plugins, see link:https://neo4j.com/docs/operations-manual/current/configuration/plugins/[Operations Manual -> Configure plugins]. + +=== Syntax + +The syntax for the `dbms.reloadProcedures()` procedure is as follows: + +.Details +|=== +| *Syntax* 3+m| dbms.reloadProcedures(namespaces = * :: STRING) :: (name :: STRING, type :: STRING) +| *Description* 3+a| Reload procedures from disk. +.2+| *Input arguments* | *Name* | *Type* | *Description* +| namespaces | STRING | Optional. A glob pattern selecting which namespaces to reload. Defaults to '\*', meaning everything. Example: 'com.example.*'. +.3+| *Returned arguments* | *Name* | *Type* | *Description* +| name | STRING | The fully qualified name of each entry point that was reloaded. +| type | STRING | The type of each entry point that was reloaded. Possible values are: PROCEDURE, FUNCTION or AGGREGATION FUNCTION. +| *Mode* 3+| DBMS +|=== + +A successful call returns one row for every entry point it brought back into service. +An empty result means nothing matched the pattern. + +[NOTE] +==== +The namespace argument genuinely limits the operation. +It is not advisory. +A plugin whose namespace does not match the pattern is left untouched, even if its JAR file changed on disk. +Three namespaces `apoc.{asterisk}`, `gds.{asterisk}`, and `aura.{asterisk}` are not reloadable by default. +==== + +=== Example + +include::partial$user-procedures-functions.adoc[] + +You can use the following example to test the `dbms.reloadProcedures()` procedure to reload a user-defined procedure or function without restarting the server, as well as withdraw a procedure or function. + +The example assumes you have a Neo4j server running with the `example-v1.jar` plugin in the _plugins_ directory, which contains a procedure `com.example.someProcedure()`. + +. Confirm that reload procedure is available by running the following query: ++ +[source, cypher] +---- +SHOW PROCEDURES YIELD name, description, admin +WHERE name = 'dbms.reloadProcedures' +RETURN name, description, admin; +---- ++ +[queryresult] +---- ++------------------------------------------------------------------+ +| name | description | admin | ++------------------------------------------------------------------+ +| "dbms.reloadProcedures" | "Reload procedures from disk." | TRUE | ++------------------------------------------------------------------+ + +1 row +ready to start consuming query after 111 ms, results consumed after another 8 ms +---- + +. Replace the `example-v1.jar` with `example-v2.jar` while the server keeps running. +The new JAR file contains the `com.example.someProcedure` as well as some new procedures and functions: ++ +[source, bash] +---- +rm plugins/example-v1.jar +cp example-v2.jar plugins/ +---- + +. Reload that namespace: ++ +[source, cypher] +---- +CALL dbms.reloadProcedures('com.example.*'); +---- ++ +[queryresult] +---- +name type +"com.example.someProcedure" "PROCEDURE" +"com.example.newProcedure" "PROCEDURE" +"com.example.newFunction" "FUNCTION" +"com.example.newAggregationFunction" "AGGREGATION FUNCTION" +---- ++ +The procedure returns all the entry points in that namespace, including the new ones. + +Similarly, you can withdraw a procedure or function by removing its JAR file and reloading the namespace. + +=== Confirm that no restart happened + +You can check that the server did not restart by checking the server start time and uptime. +The server start time can be read from Cypher and should be unchanged across a reload. + +[source, cypher] +---- +CALL dbms.queryJmx('java.lang:type=Runtime') YIELD attributes +RETURN datetime({epochMillis: attributes.StartTime.value}) AS serverStarted, + duration({milliseconds: attributes.Uptime.value}) AS uptime; +---- + +=== Troubleshooting + +A reload builds an intermediate registry and only swaps it into service if the whole load succeeds. +If any JAR in the directory is invalid, the reload fails and the previously loaded plugins keep serving, unchanged. +When a corrupt file is in the plugins directory, the reload will return https://neo4j.com/docs/status-codes/current/errors/gql-errors/52N24/[52N24] and the plugin that was already in service will continue to answer correctly. +Removing the invalid file and reloading again restores normal operation with no restart. + +==== Logging + +Every reload writes a matched pair of entries to _debug.log_, giving operators an audit trail of what was reloaded and when. +For example: +[source, log] +---- +INFO c.n.d.p.ReloadProcedure "Reloading procedure namespace `com.example.*`." +INFO c.n.d.p.ReloadProcedure "Reloaded 2 procedures, 1 functions, and 1 aggregation functions." +---- + +==== Query cache invalidation + +Cached Cypher plans that reference a changed signature are discarded automatically, so a client does not continue to run a stale plan against the old plugin. +For example, if a procedure signature changes, the following log entry is written to _debug.log_: +[source, log] +---- +INFO o.n.c.i.c.CypherQueryCaches "Discarded stale query from the query cache after 5 seconds. +Reason: Procedure or function signature have been modified. Query id: 79." +---- + +[[reserved-and-deprecated-namespaces]] +== Reserved and deprecated procedure namespaces + +[NOTE] +==== +Note that deprecated procedure and function namespaces will be moved to reserved in the next major Cypher version. +For more information about Neo4j and Cypher versioning, see link:https://neo4j.com/docs/operations-manual/current/introduction/#_cypher_versions[Operations manual -> Introduction]. +==== + +[.tabbed-example] +===== +[.include-with-procedure-namespaces] +====== + +The following table shows the reserved and deprecated procedure namespaces: + +[options="header", cols="m,m"] +|=== +| Reserved | Deprecated in Cypher 25 since Neo4j 2025.11 +| cdc.* | * +| date.* | abac.* +| datetime.* | builtin.* +| db.* | coll.* +| dbms.* | math.* +| duration.* | plugin.* +| graph.* | point.* +| internal.* | stored.* +| localdatetime.* | string.* +| localtime.* | vector.* +| time.* | +| tx.* | +| unsupported.* | +|=== + +====== + +[.include-with-function-namespaces] +====== + +The following table shows the reserved and deprecated function namespaces: + +[options="header", cols="m,m"] +|=== +| Reserved | Deprecated in Cypher 25 since Neo4j 2025.11 +| * | abac.* +| date | builtin.* +| date.realtime | cdc.* +| date.statement | coll.* +| date.transaction | date.* +| date.truncate | datetime.* +| datetime | db.* +| datetime.fromepoch | dbms.* +| datetime.fromepochmillis | duration.* +| datetime.realtime | graph.* +| datetime.statement | internal.* +| datetime.transaction | localdatetime.* +| datetime.truncate | localtime.* +| db.nameFromElementId | math.* +| duration | plugin.* +| duration.between | point.* +| duration.inDays | stored.* +| duration.inMonths | string.* +| duration.inSeconds | time.* +| graph.byElementId | tx.* +| graph.byName | unsupported.* +| graph.names | vector.* +| graph.propertiesByName | +| localdatetime | +| localdatetime.realtime | +| localdatetime.statement | +| localdatetime.transaction | +| localdatetime.truncate | +| localtime | +| localtime.realtime | +| localtime.statement | +| localtime.transaction | +| localtime.truncate | +| point.distance | +| point.withinBBox | +| time | +| time.realtime | +| time.statement | +| time.transaction | +| time.truncate | +| vector.similarity.cosine | +| vector.similarity.euclidean | +|=== + +====== +===== \ No newline at end of file diff --git a/modules/ROOT/pages/traversal-framework/index.adoc b/modules/ROOT/pages/traversal-framework/index.adoc index 50e6810..065dac0 100644 --- a/modules/ROOT/pages/traversal-framework/index.adoc +++ b/modules/ROOT/pages/traversal-framework/index.adoc @@ -28,7 +28,7 @@ image::graphdb-traversal-description.svg[role="middle"] == Using the Traversal Framework The Traversal Framework can be used xref:java-embedded/traversal.adoc[embedded in Java applications]. -It can also be used when extending Neo4j with a xref:/extending-neo4j/procedures.adoc[User-defined Procedure]. +It can also be used when extending Neo4j with a xref:extending-neo4j/user-defined-procedures-functions.adoc[User-defined procedures and functions]. For an example, see xref:traversal-framework/traversal-framework-example.adoc#traversal-in-a-procedure-example[User-defined procedure with a Traversal Framework]. [[traversal-vs-cypher]] @@ -44,7 +44,7 @@ Some of the advantages of using the Traversal Framework over Cypher include: See xref:/traversal-framework/traversal-framework-java-api.adoc#traversal-java-api-evaluator[Evaluator] for more information. * With Cypher, it is not possible to specify the order in which paths are expanded (e.g. depth-first). However, with the Traversal Framework, it is possible to specify the xref:/traversal-framework/traversal-framework-java-api.adoc#traversal-java-api-branchselector[order of paths traversed]. -* With Cypher, relationships are only traversed when `RELATIONSHIP_GLOBAL` uniqueness is specified. +* With Cypher, relationships are only traversed when `RELATIONSHIP_GLOBAL` uniqueness is specified. By using the Traversal Framework, it is possible to specify the xref:/traversal-framework/traversal-framework-java-api.adoc#traversal-java-api-uniqueness[uniqueness constraints on the path traversed]. [WARNING] diff --git a/modules/ROOT/pages/traversal-framework/traversal-framework-example.adoc b/modules/ROOT/pages/traversal-framework/traversal-framework-example.adoc index d5b1355..af8b60f 100644 --- a/modules/ROOT/pages/traversal-framework/traversal-framework-example.adoc +++ b/modules/ROOT/pages/traversal-framework/traversal-framework-example.adoc @@ -173,7 +173,7 @@ KNOWS [[traversal-in-a-procedure-example]] == Implementing a user-defined procedure -This example shows how to implement a xref:/extending-neo4j/procedures.adoc[user-defined procedure] using the Traversal Framework. +This example shows how to implement a xref:extending-neo4j/user-defined-procedures-functions.adoc[user-defined procedure] using the Traversal Framework. The transaction and logger are made available through the Procedure Framework: [source, java] diff --git a/modules/ROOT/partials/user-procedures-functions.adoc b/modules/ROOT/partials/user-procedures-functions.adoc new file mode 100644 index 0000000..9fb2904 --- /dev/null +++ b/modules/ROOT/partials/user-procedures-functions.adoc @@ -0,0 +1,8 @@ +[CAUTION] +==== +Keep in mind that in a cluster deployment, you need to deploy the JAR files and run the `dbms.reloadProcedures()` procedure on each cluster member. +Otherwise, the cluster members will be out of sync, leading to unexpected behavior. + +The reload process is isolated so that the operation only affects new transactions. +Already running transactions continue to execute with a snapshot of the available procedures or functions at their respective initialization. +==== \ No newline at end of file From c299ad9821af7b7165d751b629d9228822740ac9 Mon Sep 17 00:00:00 2001 From: Natalia Ivakina <82437520+NataliaIvakina@users.noreply.github.com> Date: Tue, 22 Sep 2026 13:37:28 +0200 Subject: [PATCH 44/48] Update version to 2026.10 in antora.yml (#378) --- antora.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/antora.yml b/antora.yml index 5108dc1..c994a64 100644 --- a/antora.yml +++ b/antora.yml @@ -1,14 +1,14 @@ name: java-reference title: Java Reference -version: '2026.09' +version: '2026.10' start_page: ROOT:index.adoc nav: - modules/ROOT/content-nav.adoc asciidoc: attributes: - neo4j-version: '2026.09' - neo4j-version-exact: '2026.09.0' - neo4j-buildnumber: '2026.09' + neo4j-version: '2026.10' + neo4j-version-exact: '2026.10.0' + neo4j-buildnumber: '2026.10' java-driver-version: '6.2.1' neo4j-documentation-branch: 'dev' page-origin-private: false From a48aa89eb6ff3ed4bcc38e2c5e7b298c946a5e8b Mon Sep 17 00:00:00 2001 From: Reneta Popova Date: Tue, 22 Sep 2026 13:03:45 +0100 Subject: [PATCH 45/48] =?UTF-8?q?Update=20the=20procedure=20example=20to?= =?UTF-8?q?=20show=20the=20equivalent=20of=20the=20integratio=E2=80=A6=20(?= =?UTF-8?q?#381)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …n test --- .../user-defined-procedures-functions.adoc | 56 +++++++++++-------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/modules/ROOT/pages/extending-neo4j/user-defined-procedures-functions.adoc b/modules/ROOT/pages/extending-neo4j/user-defined-procedures-functions.adoc index 1b40796..dfe7a1a 100644 --- a/modules/ROOT/pages/extending-neo4j/user-defined-procedures-functions.adoc +++ b/modules/ROOT/pages/extending-neo4j/user-defined-procedures-functions.adoc @@ -315,41 +315,51 @@ The following examples show how to write a user-defined procedure, function, and [.include-with-procedure-example] ====== -The following is an example of a user-defined procedure that returns all nodes in the graph: +The following is an example of a user-defined procedure that returns the relationship types going in and out of a given node: [source, java] ---- package example; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.stream.Stream; +import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.ResourceIterator; -import org.neo4j.graphdb.Transaction; +import org.neo4j.graphdb.Relationship; +import org.neo4j.logging.Log; import org.neo4j.procedure.Context; -import org.neo4j.procedure.Mode; +import org.neo4j.procedure.Description; +import org.neo4j.procedure.Name; import org.neo4j.procedure.Procedure; -/** - * This is an example returning {@link org.neo4j.graphdb.Entity Entities} from stored procedures. - * {@link Node Nodes} and {@link org.neo4j.graphdb.Relationship relationships} are both entities - * and can only be accessed in their transaction. So it is important that you use the injected one - * and not open a new one; otherwise you can access them from the outside. - */ -public class EntityResultExample { - - @Context - public Transaction tx; +public class GetRelationshipTypes { + // This gives us a log instance that outputs messages to the + // standard log, normally found under `data/log/console.log` + @Context + public Log log; - public record EntityContainer(Node node) { - } - - @Procedure(name = "example.allnodes", mode = Mode.READ) - public Stream allnodes() { - ResourceIterator nodes = tx.execute("MATCH (n) RETURN n").columnAs("n"); - return nodes.stream().map(EntityContainer::new); - } -} + /** + * This procedure takes a Node and gets the relationships going in and out of it + * + * @param node The node to get the relationships for + * @return A RelationshipTypes instance with the relations (incoming and outgoing) for a given node. + */ + @Procedure(name = "example.getRelationshipTypes") + @Description("Get the different relationships going in and out of a node.") + public Stream getRelationshipTypes(@Name("node") Node node) { + List outgoing = new ArrayList<>(); + node.getRelationships(Direction.OUTGOING).iterator() + .forEachRemaining(rel -> AddDistinct(outgoing, rel)); + + List incoming = new ArrayList<>(); + node.getRelationships(Direction.INCOMING).iterator() + .forEachRemaining(rel -> AddDistinct(incoming, rel)); + + return Stream.of(new RelationshipTypes(incoming, outgoing)); + } ---- ====== From 88a5b8932ce01703731de3c0f540a401a8700753 Mon Sep 17 00:00:00 2001 From: Neil Dewhurst Date: Thu, 8 Oct 2026 11:18:10 +0100 Subject: [PATCH 46/48] Add PDF generation pipeline, update trigger/generate-html to latest template format (#385) --- .github/workflows/docs-generate-html.yml | 91 ++++++------ .github/workflows/docs-generate-pdf.yml | 85 +++++++++++ .github/workflows/docs-trigger-builds.yml | 169 ++++++++++++++++++++++ 3 files changed, 296 insertions(+), 49 deletions(-) create mode 100644 .github/workflows/docs-generate-pdf.yml create mode 100644 .github/workflows/docs-trigger-builds.yml diff --git a/.github/workflows/docs-generate-html.yml b/.github/workflows/docs-generate-html.yml index 546fc2e..c8960d0 100644 --- a/.github/workflows/docs-generate-html.yml +++ b/.github/workflows/docs-generate-html.yml @@ -1,59 +1,62 @@ - name: "Generate HTML" +run-name: "Generate ${{ inputs.publish-env != '' && inputs.publish-env || (inputs.build-ref == vars.DOCS_PROD_BRANCH && 'prod' || 'dev') }} HTML from ${{ inputs.build-ref }}" + +permissions: + contents: read -# edit the list of branches according to your repository -# the list of branches should contain all the branches in your Antora publish playbooks +# Builds, verifies, and publishes docs for ONE environment, as a run entirely independent +# of any other environment's run. Triggered (via the API, not a workflow_call) by +# docs-trigger-builds.yml, once per environment that applies to a given push (dev, prod, or both) - +# so if dev's run fails, prod's run is completely unaffected, and vice versa. on: - push: - branches: - - "main" - - "dev" - - "5.x" - - "4.4" workflow_dispatch: - -# change `dev` and `main` according to your repository's branch names -# `dev` is the branch you use to build and publish to staging -# `main` is the branch you use to build and publish to neo4j.com/docs -# in some cases, PROD_BRANCH and DEV_BRANCH may be the same branch -env: - DEV_BRANCH: 'dev' - PROD_BRANCH: 'main' + inputs: + build-ref: + description: 'The git ref to build from' + type: string + required: true + publish-env: + description: 'Override for dev/prod. Leave blank to derive it from build-ref against vars.DOCS_PROD_BRANCH - only needs setting explicitly when DOCS_DEV_BRANCH == DOCS_PROD_BRANCH, where build-ref alone cannot tell the two builds apart.' + type: string + required: false + default: '' jobs: - prepare-ref-env: - name: Set build branch and environments + # Resolves publish-env (dev/prod) once, so neither docs-build nor publish-html + # duplicates the override-or-derive logic. + resolve-env: + name: Resolve environment runs-on: ubuntu-latest outputs: - build-ref: ${{ steps.set-ref-env.outputs.build-ref }} - environments: ${{ steps.set-ref-env.outputs.environments }} + publish-env: ${{ steps.resolve.outputs.publish-env }} steps: - - name: Set Build Ref - id: set-ref-env + - name: Resolve publish-env + id: resolve + env: + PUBLISH_ENV_OVERRIDE: ${{ inputs.publish-env }} + BUILD_REF: ${{ inputs.build-ref }} + PROD_BRANCH: ${{ vars.DOCS_PROD_BRANCH }} run: | - if [[ "${GITHUB_REF}" == "refs/heads/${{ env.DEV_BRANCH }}" ]]; then - build_from=${{ env.DEV_BRANCH }} - environments='["dev"]' + if [[ -n "${PUBLISH_ENV_OVERRIDE}" ]]; then + publish_env="${PUBLISH_ENV_OVERRIDE}" + elif [[ "${BUILD_REF}" == "${PROD_BRANCH}" ]]; then + publish_env="prod" else - build_from=${{ env.PROD_BRANCH }} - environments='["prod"]' + publish_env="dev" fi - # if dev branch = prod branch publish to both - if [[ "${{ env.DEV_BRANCH }}" == "${{ env.PROD_BRANCH }}" ]]; then - environments='["dev","prod"]' - fi - echo "build-ref=${build_from}" >> $GITHUB_OUTPUT - echo "environments=${environments[@]}" >> $GITHUB_OUTPUT + + echo "publish-env=${publish_env}" >> $GITHUB_OUTPUT docs-build: name: Generate HTML - needs: prepare-ref-env + needs: resolve-env uses: neo4j/docs-tools/.github/workflows/reusable-docs-build.yml@v2 with: package-script: 'verify:publish' - build-ref: ${{needs.prepare-ref-env.outputs.build-ref}} + build-ref: ${{ inputs.build-ref }} fetch-depth: 0 + publish-env: ${{ needs.resolve-env.outputs.publish-env }} docs-verify: name: Verify HTML @@ -64,15 +67,10 @@ jobs: publish-html: name: Publish HTML - needs: [docs-verify, prepare-ref-env] + needs: [docs-verify, resolve-env] runs-on: ubuntu-latest - - strategy: - matrix: - environments: ${{ fromJson(needs.prepare-ref-env.outputs.environments) }} - steps: - - name: Publish to ${{ matrix.environments }} + - name: Publish to ${{ needs.resolve-env.outputs.publish-env }} uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 #v4 with: token: ${{ secrets.DOCS_DISPATCH_TOKEN }} @@ -83,10 +81,5 @@ jobs: "org": "${{ github.repository_owner }}", "repo": "${{ github.event.repository.name }}", "run_id": "${{ github.run_id }}", - "publish_env": "${{ matrix.environments }}" + "publish_env": "${{ needs.resolve-env.outputs.publish-env }}" } - - - name: Echo - if: ${{ matrix.environments == 'prod' }} - run: | - echo "If this step runs then approval has been granted" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/docs-generate-pdf.yml b/.github/workflows/docs-generate-pdf.yml new file mode 100644 index 0000000..8b167bb --- /dev/null +++ b/.github/workflows/docs-generate-pdf.yml @@ -0,0 +1,85 @@ +name: "Generate PDF" +run-name: "Generate ${{ inputs.publish-env != '' && inputs.publish-env || (inputs.build-ref == vars.DOCS_PROD_BRANCH && 'prod' || 'dev') }} PDF from ${{ inputs.build-ref }}" + +permissions: + contents: read + +# Mirrors docs-generate-html.yml's shape (workflow_dispatch with build-ref and +# publish-env inputs, resolve-env -> build -> publish) and its own reusable-workflow +# reference convention (a pinned neo4j/docs-tools/...@v2 tag, not a relative path - +# this repo doesn't contain reusable-docs-pdf-build.yml itself). Still simpler than +# docs-generate-html.yml in one way: there's no docs-verify step (no equivalent check +# exists yet for a PDF), and build/publish are two plain jobs rather than a +# reusable-workflow call plus a verify call. +on: + workflow_dispatch: + inputs: + build-ref: + description: 'The git ref to build from' + type: string + required: true + publish-env: + description: 'Override for dev/prod. Leave blank to derive it from build-ref against vars.DOCS_PROD_BRANCH - only needs setting explicitly when DOCS_DEV_BRANCH == DOCS_PROD_BRANCH, where build-ref alone cannot tell the two builds apart.' + type: string + required: false + default: '' + +jobs: + + # Resolves publish-env (dev/prod) once, so publish-pdf doesn't duplicate the + # override-or-derive logic - same job as docs-generate-html.yml's own resolve-env. + resolve-env: + name: Resolve environment + runs-on: ubuntu-latest + outputs: + publish-env: ${{ steps.resolve.outputs.publish-env }} + steps: + - name: Resolve publish-env + id: resolve + env: + PUBLISH_ENV_OVERRIDE: ${{ inputs.publish-env }} + BUILD_REF: ${{ inputs.build-ref }} + PROD_BRANCH: ${{ vars.DOCS_PROD_BRANCH }} + run: | + if [[ -n "${PUBLISH_ENV_OVERRIDE}" ]]; then + publish_env="${PUBLISH_ENV_OVERRIDE}" + elif [[ "${BUILD_REF}" == "${PROD_BRANCH}" ]]; then + publish_env="prod" + else + publish_env="dev" + fi + + echo "publish-env=${publish_env}" >> $GITHUB_OUTPUT + + docs-build-pdf: + name: Generate PDF + uses: neo4j/docs-tools/.github/workflows/reusable-docs-pdf-build.yml@v2 + with: + build-ref: ${{ inputs.build-ref }} + fetch-depth: 0 + + # Hand off to docs-publish (a separate repo) to actually publish this run's "pdf" + # artifact - same mechanism docs-generate-html.yml already uses for its "docs" + # artifact. docset/version come from docs-build-pdf itself (read back out of the + # PDF's own build path - see reusable-docs-pdf-build.yml), since there's no HTML + # directory tree here for docs-publish to infer them from the way it does for HTML. + publish-pdf: + name: Publish PDF + needs: [docs-build-pdf, resolve-env] + runs-on: ubuntu-latest + steps: + - name: Publish to ${{ needs.resolve-env.outputs.publish-env }} + uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 #v4 + with: + token: ${{ secrets.DOCS_DISPATCH_TOKEN }} + repository: neo4j/docs-publish + event-type: publish-pdf + client-payload: |- + { + "org": "${{ github.repository_owner }}", + "repo": "${{ github.event.repository.name }}", + "run_id": "${{ github.run_id }}", + "publish_env": "${{ needs.resolve-env.outputs.publish-env }}", + "docset": "${{ needs.docs-build-pdf.outputs.docset }}", + "version": "${{ needs.docs-build-pdf.outputs.version }}" + } diff --git a/.github/workflows/docs-trigger-builds.yml b/.github/workflows/docs-trigger-builds.yml new file mode 100644 index 0000000..049f6ce --- /dev/null +++ b/.github/workflows/docs-trigger-builds.yml @@ -0,0 +1,169 @@ +name: "Trigger docs builds" + +# This workflow's job is dispatching docs-generate-html.yml and docs-generate-pdf.yml +# with the right build-ref(s) for whatever just happened - it is NOT the only valid way +# to wire this up. It doesn't publish anything itself - the dispatched workflows hand +# off to the (separate) docs-publish repo for that. +# +# Use this (docs-trigger-builds.yml -> docs-generate-*.yml) when a single trigger might +# legitimately need to build more than one environment - e.g. a repo where +# DOCS_DEV_BRANCH == DOCS_PROD_BRANCH (one branch serving both, so every push to it +# always means both). +# +# If your repo instead has clean, separate dev/prod branches, you may not need this at +# all: docs-generate-html.yml can be given its own direct `on: push: branches: [...]` +# trigger per environment instead - simpler, and structurally can't build the wrong +# branch's content into the wrong environment. This template still works fine for that +# shape too (it will just always resolve to a single build), so which to use is a +# judgment call, not a hard requirement. + +permissions: + contents: read + actions: write + +# edit the list of branches according to your repository - every branch that should +# trigger a rebuild, including older versioned content branches (a push there still +# needs to refresh dev/prod's current HTML and this push's own PDF). +on: + push: + branches: + - 'dev' + - 'main' + - '5.x' + - '4.4' + workflow_dispatch: + +jobs: + + prepare-builds: + name: Set builds to trigger + runs-on: ubuntu-latest + outputs: + # JSON array of {workflow, buildRef, publishEnv} - one entry per independent + # dispatch to make. publishEnv is left '' for docs-generate-html.yml except in + # the one case where it's genuinely ambiguous (see below) - that workflow + # derives it itself from build-ref against its own vars.DOCS_PROD_BRANCH + # whenever publishEnv is blank. docs-generate-pdf.yml's publishEnv is always + # resolved explicitly here instead, using the same conservative default as the + # HTML rules below: the dev branch is the only case treated as dev, every other + # branch defaults to prod. + builds: ${{ steps.set-builds.outputs.builds }} + steps: + # DOCS_DEV_BRANCH and DOCS_PROD_BRANCH are required repository variables + # (Settings -> Secrets and variables -> Actions -> Variables), not values to edit + # here. docs-generate-html.yml, docs-generate-pdf.yml, and docs-publish (a + # separate repo) all independently read the same variables, so they can't be set + # by editing this file on a branch/PR. + # `dev` is the branch you use to build and publish to staging. + # `main` is the branch you use to build and publish to neo4j.com/docs. + # If your repo has no separate prod environment, set DOCS_PROD_BRANCH equal to + # DOCS_DEV_BRANCH - every push will then resolve to both (see the rules below). + - name: Set builds + id: set-builds + env: + DEV_BRANCH: ${{ vars.DOCS_DEV_BRANCH }} + PROD_BRANCH: ${{ vars.DOCS_PROD_BRANCH }} + run: | + dev_branch="${DEV_BRANCH}" + prod_branch="${PROD_BRANCH}" + + if [[ -z "${dev_branch}" ]]; then + echo "::error::vars.DOCS_DEV_BRANCH is not set for this repository. Set it in Settings -> Secrets and variables -> Actions -> Variables." + exit 1 + fi + if [[ -z "${prod_branch}" ]]; then + echo "::error::vars.DOCS_PROD_BRANCH is not set for this repository. Set it in Settings -> Secrets and variables -> Actions -> Variables." + exit 1 + fi + + # HTML rules: + # - DEV_BRANCH == PROD_BRANCH -> both, always (one branch serves both, so + # there's no "the other one didn't change" case to worry about). + # - The triggering branch IS the dev branch -> dev only (a change on dev has + # no bearing on prod's already-published content). + # - Anything else (including a push to the prod branch, or any other branch) + # -> both. We deliberately don't try to be clever about only rebuilding the + # one that "actually changed" - e.g. a branch that's fallen out of the dev + # set but is still in the prod set would be misdetected either way, so we + # just always rebuild everything except the one case (dev branch) we know + # for certain doesn't affect prod. + if [[ "${dev_branch}" == "${prod_branch}" ]]; then + html_builds=$(jq -nc --arg b "$dev_branch" \ + '[{workflow:"docs-generate-html.yml",buildRef:$b,publishEnv:"dev"},{workflow:"docs-generate-html.yml",buildRef:$b,publishEnv:"prod"}]') + elif [[ "${GITHUB_REF}" == "refs/heads/${dev_branch}" ]]; then + html_builds=$(jq -nc --arg dev "$dev_branch" \ + '[{workflow:"docs-generate-html.yml",buildRef:$dev,publishEnv:""}]') + else + html_builds=$(jq -nc --arg dev "$dev_branch" --arg prod "$prod_branch" \ + '[{workflow:"docs-generate-html.yml",buildRef:$dev,publishEnv:""},{workflow:"docs-generate-html.yml",buildRef:$prod,publishEnv:""}]') + fi + + # PDF always builds from the branch that triggered this run - no dev/prod + # pairing to work out the way HTML has to (there's only ever one PDF build + # per trigger). Its publish-env is still dev or prod, though, resolved with + # the same conservative default the HTML rules above use: the dev branch is + # the one case known for certain not to affect prod, so it's the only one + # that resolves to dev - every other branch (the real prod branch, a third + # long-lived branch, a typo, ...) resolves to prod. + if [[ "${GITHUB_REF}" == "refs/heads/${dev_branch}" ]]; then + pdf_publish_env="dev" + else + pdf_publish_env="prod" + fi + pdf_build=$(jq -nc --arg ref "${GITHUB_REF_NAME}" --arg env "$pdf_publish_env" \ + '[{workflow:"docs-generate-pdf.yml",buildRef:$ref,publishEnv:$env}]') + + builds=$(jq -nc --argjson html "$html_builds" --argjson pdf "$pdf_build" '$html + $pdf') + echo "builds=${builds}" >> $GITHUB_OUTPUT + + # One matrix job instance per build prepare-builds resolved, each dispatching its + # target workflow as its own separate run - not a workflow_call (which would keep + # them all in this one run), so each is fully independent: fail-fast: false means + # one matrix instance failing to dispatch doesn't cancel the others, and each + # dispatched run ends up with its own normally-named artifacts (no collisions, since + # they're separate runs, not jobs sharing one run). + trigger-builds: + name: Trigger ${{ matrix.build.workflow }} (${{ matrix.build.buildRef }}) + needs: prepare-builds + strategy: + fail-fast: false + matrix: + build: ${{ fromJson(needs.prepare-builds.outputs.builds) }} + runs-on: ubuntu-latest + steps: + - name: Dispatch + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + BUILD: ${{ toJson(matrix.build) }} + PROD_BRANCH: ${{ vars.DOCS_PROD_BRANCH }} + with: + script: | + const build = JSON.parse(process.env.BUILD) + const prodBranch = process.env.PROD_BRANCH + // Both docs-generate-html.yml and docs-generate-pdf.yml accept publish-env. + const inputs = { 'build-ref': build.buildRef, 'publish-env': build.publishEnv } + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: build.workflow, + // Dispatch from build.buildRef itself, NOT the branch that triggered + // this workflow - a dispatched run's ref becomes its real head_branch, + // which is exactly what docs-publish's check-build-branch inspects. + // Using a single fixed ref for every build here would make every + // dispatched run's head_branch equal whatever branch triggered THIS + // workflow, regardless of which environment it's actually building for + // - so a trigger from any branch other than build.buildRef (e.g. a + // versioned content branch, or the "other" HTML build when both are + // triggered) would always fail that check downstream, even for an + // otherwise-legitimate build. + ref: build.buildRef, + inputs, + }) + // Mirrors docs-generate-html.yml's own publish-env derivation for + // display purposes only - the real derivation happens inside the + // dispatched run, this is just to show what it will resolve to when no + // explicit override was passed (the empty-string case, only possible for + // an HTML build - see prepare-builds above). + const env = build.publishEnv || (build.buildRef === prodBranch ? 'prod' : 'dev') + core.summary.addRaw(`Triggered \`${build.workflow}\` on branch \`${build.buildRef}\` for \`${env}\``, true) + await core.summary.write() From d97d10d6b072a7eefb7726b7b8e60cc2f2b5c56e Mon Sep 17 00:00:00 2001 From: Neil Dewhurst Date: Thu, 8 Oct 2026 17:35:38 +0100 Subject: [PATCH 47/48] Pass publish-env through to the PDF build, same as the HTML build (#386) --- .github/workflows/docs-generate-pdf.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/docs-generate-pdf.yml b/.github/workflows/docs-generate-pdf.yml index 8b167bb..5954861 100644 --- a/.github/workflows/docs-generate-pdf.yml +++ b/.github/workflows/docs-generate-pdf.yml @@ -53,10 +53,12 @@ jobs: docs-build-pdf: name: Generate PDF + needs: resolve-env uses: neo4j/docs-tools/.github/workflows/reusable-docs-pdf-build.yml@v2 with: build-ref: ${{ inputs.build-ref }} fetch-depth: 0 + publish-env: ${{ needs.resolve-env.outputs.publish-env }} # Hand off to docs-publish (a separate repo) to actually publish this run's "pdf" # artifact - same mechanism docs-generate-html.yml already uses for its "docs" From b73bc460f5ab75861b11492faea16619c6f2650b Mon Sep 17 00:00:00 2001 From: Neil Dewhurst Date: Fri, 9 Oct 2026 12:54:42 +0100 Subject: [PATCH 48/48] Simplify manual dispatch: drop build-ref, make publish-env a dropdown (#387) --- .github/workflows/docs-generate-html.yml | 27 ++++++++++------- .github/workflows/docs-generate-pdf.yml | 35 ++++++++++++----------- .github/workflows/docs-trigger-builds.yml | 5 +++- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/.github/workflows/docs-generate-html.yml b/.github/workflows/docs-generate-html.yml index c8960d0..dbe07aa 100644 --- a/.github/workflows/docs-generate-html.yml +++ b/.github/workflows/docs-generate-html.yml @@ -1,5 +1,5 @@ name: "Generate HTML" -run-name: "Generate ${{ inputs.publish-env != '' && inputs.publish-env || (inputs.build-ref == vars.DOCS_PROD_BRANCH && 'prod' || 'dev') }} HTML from ${{ inputs.build-ref }}" +run-name: "Generate ${{ inputs.publish-env != '' && inputs.publish-env || (github.ref_name == vars.DOCS_PROD_BRANCH && 'prod' || 'dev') }} HTML from ${{ github.ref_name }}" permissions: contents: read @@ -8,18 +8,26 @@ permissions: # of any other environment's run. Triggered (via the API, not a workflow_call) by # docs-trigger-builds.yml, once per environment that applies to a given push (dev, prod, or both) - # so if dev's run fails, prod's run is completely unaffected, and vice versa. +# +# No build-ref input: the git ref to build from is always whatever ref this run was +# itself dispatched against (the "Use workflow from" branch when triggered manually, or +# docs-trigger-builds.yml's own `ref:` when triggered automatically - which it always sets +# to the same value it also used to pass as a build-ref input here, so that separate input +# never actually carried any information github.ref_name didn't already have). Reading +# github.ref_name directly instead removes a second, redundant "which branch" box from +# manual dispatch. on: workflow_dispatch: inputs: - build-ref: - description: 'The git ref to build from' - type: string - required: true publish-env: - description: 'Override for dev/prod. Leave blank to derive it from build-ref against vars.DOCS_PROD_BRANCH - only needs setting explicitly when DOCS_DEV_BRANCH == DOCS_PROD_BRANCH, where build-ref alone cannot tell the two builds apart.' - type: string + description: "The environment to publish to. Provide a value when the same branch publishes to both 'dev' and 'prod' environments. Otherwise, leave blank." + type: choice required: false default: '' + options: + - '' + - 'dev' + - 'prod' jobs: @@ -35,12 +43,11 @@ jobs: id: resolve env: PUBLISH_ENV_OVERRIDE: ${{ inputs.publish-env }} - BUILD_REF: ${{ inputs.build-ref }} PROD_BRANCH: ${{ vars.DOCS_PROD_BRANCH }} run: | if [[ -n "${PUBLISH_ENV_OVERRIDE}" ]]; then publish_env="${PUBLISH_ENV_OVERRIDE}" - elif [[ "${BUILD_REF}" == "${PROD_BRANCH}" ]]; then + elif [[ "${GITHUB_REF_NAME}" == "${PROD_BRANCH}" ]]; then publish_env="prod" else publish_env="dev" @@ -54,7 +61,7 @@ jobs: uses: neo4j/docs-tools/.github/workflows/reusable-docs-build.yml@v2 with: package-script: 'verify:publish' - build-ref: ${{ inputs.build-ref }} + build-ref: ${{ github.ref_name }} fetch-depth: 0 publish-env: ${{ needs.resolve-env.outputs.publish-env }} diff --git a/.github/workflows/docs-generate-pdf.yml b/.github/workflows/docs-generate-pdf.yml index 5954861..eaa3123 100644 --- a/.github/workflows/docs-generate-pdf.yml +++ b/.github/workflows/docs-generate-pdf.yml @@ -1,28 +1,30 @@ name: "Generate PDF" -run-name: "Generate ${{ inputs.publish-env != '' && inputs.publish-env || (inputs.build-ref == vars.DOCS_PROD_BRANCH && 'prod' || 'dev') }} PDF from ${{ inputs.build-ref }}" +run-name: "Generate ${{ inputs.publish-env != '' && inputs.publish-env || (github.ref_name == vars.DOCS_PROD_BRANCH && 'prod' || 'dev') }} PDF from ${{ github.ref_name }}" permissions: contents: read -# Mirrors docs-generate-html.yml's shape (workflow_dispatch with build-ref and -# publish-env inputs, resolve-env -> build -> publish) and its own reusable-workflow -# reference convention (a pinned neo4j/docs-tools/...@v2 tag, not a relative path - -# this repo doesn't contain reusable-docs-pdf-build.yml itself). Still simpler than -# docs-generate-html.yml in one way: there's no docs-verify step (no equivalent check -# exists yet for a PDF), and build/publish are two plain jobs rather than a -# reusable-workflow call plus a verify call. +# Mirrors docs-generate-html.yml's shape (workflow_dispatch with a publish-env input, +# resolve-env -> build -> publish) and its own reusable-workflow reference convention (a +# pinned neo4j/docs-tools/...@v2 tag, not a relative path - this repo doesn't contain +# reusable-docs-pdf-build.yml itself). Still simpler than docs-generate-html.yml in one +# way: there's no docs-verify step (no equivalent check exists yet for a PDF), and +# build/publish are two plain jobs rather than a reusable-workflow call plus a verify call. +# +# No build-ref input - see docs-generate-html.yml's own comment on why: the git ref to +# build from is always whatever ref this run was itself dispatched against. on: workflow_dispatch: inputs: - build-ref: - description: 'The git ref to build from' - type: string - required: true publish-env: - description: 'Override for dev/prod. Leave blank to derive it from build-ref against vars.DOCS_PROD_BRANCH - only needs setting explicitly when DOCS_DEV_BRANCH == DOCS_PROD_BRANCH, where build-ref alone cannot tell the two builds apart.' - type: string + description: "The environment to publish to. Provide a value when the same branch publishes to both 'dev' and 'prod' environments. Otherwise, leave blank." + type: choice required: false default: '' + options: + - '' + - 'dev' + - 'prod' jobs: @@ -38,12 +40,11 @@ jobs: id: resolve env: PUBLISH_ENV_OVERRIDE: ${{ inputs.publish-env }} - BUILD_REF: ${{ inputs.build-ref }} PROD_BRANCH: ${{ vars.DOCS_PROD_BRANCH }} run: | if [[ -n "${PUBLISH_ENV_OVERRIDE}" ]]; then publish_env="${PUBLISH_ENV_OVERRIDE}" - elif [[ "${BUILD_REF}" == "${PROD_BRANCH}" ]]; then + elif [[ "${GITHUB_REF_NAME}" == "${PROD_BRANCH}" ]]; then publish_env="prod" else publish_env="dev" @@ -56,7 +57,7 @@ jobs: needs: resolve-env uses: neo4j/docs-tools/.github/workflows/reusable-docs-pdf-build.yml@v2 with: - build-ref: ${{ inputs.build-ref }} + build-ref: ${{ github.ref_name }} fetch-depth: 0 publish-env: ${{ needs.resolve-env.outputs.publish-env }} diff --git a/.github/workflows/docs-trigger-builds.yml b/.github/workflows/docs-trigger-builds.yml index 049f6ce..883a27a 100644 --- a/.github/workflows/docs-trigger-builds.yml +++ b/.github/workflows/docs-trigger-builds.yml @@ -141,7 +141,10 @@ jobs: const build = JSON.parse(process.env.BUILD) const prodBranch = process.env.PROD_BRANCH // Both docs-generate-html.yml and docs-generate-pdf.yml accept publish-env. - const inputs = { 'build-ref': build.buildRef, 'publish-env': build.publishEnv } + // Neither has a build-ref input - the ref: below is what determines the git + // ref the dispatched run actually builds from (github.ref_name inside it), + // so a separate build-ref input would only ever duplicate this same value. + const inputs = { 'publish-env': build.publishEnv } await github.rest.actions.createWorkflowDispatch({ owner: context.repo.owner, repo: context.repo.repo,