Java API
Reference
Release Notes Application 2.7+ Three Component roles in org.xwiki.contrib.releasenotes create, read and search release notes and changes from Java, so an extension does not have to know which xobject holds what. They are the same components the Script Service and the REST API call.
<dependency>
<groupId>org.xwiki.contrib.releasenotes</groupId>
<artifactId>application-releasenotes-api</artifactId>
<version>2.7</version>
</dependency>ReleaseNoteManager
| Method | Returns | Description |
|---|---|---|
| createReleaseNote(note) | DocumentReference | Creates the release note from its template and returns its page. Throws ReleaseNoteAlreadyExistsException when that version of that product already has one. |
| updateReleaseNote(note) | ReleaseNote | Release Notes Application 2.8+ Replaces the release note that product and version locate, and returns it as stored. Only date and released are written, and a value the passed note leaves out is emptied rather than kept. |
| getReleaseNoteReference(product, version) | DocumentReference | The page a release note has, or would have, whether or not it exists. |
| getReleaseNote(reference) | ReleaseNote | Reads a release note back. Throws ReleaseNotesNotFoundException when the page carries none. |
| getReleaseNotes(product) | List<ReleaseNote> | Every release note of a product, or of every product when product is null. |
| getAggregatedVersions(noteReference) | List<String> | The versions a note covers: its own, plus its milestones and release candidates when it is a final version. |
ChangeManager
| Method | Returns | Description |
|---|---|---|
| createChange(change) | DocumentReference | Allocates the next Entry001 page of the release note, writes both objects and saves once. |
| reserveNextEntry(product, version) | DocumentReference | Allocates and saves that page empty, for a caller that then opens it in the editor: the edit action applies the change template to a page with no content, so the objects are created once, by the template. This is what the "Add Change" buttons use. |
| updateChange(reference, change) | Change | Release Notes Application 2.8+ Replaces the change that page holds and returns it as stored. Every property is written, so one the passed change leaves out is emptied; product and version are not, since they are the release note it belongs to. |
| getChange(reference) | Change | Reads a change back. Throws ReleaseNotesNotFoundException when the page carries none. |
| search(query) | ChangeSearchResult | Runs a ChangeQuery and reports the pages found, their compact references and whether a further page exists. |
ReleaseNotesConfiguration
| Method | Returns | Description |
|---|---|---|
| getDefaultProduct() | String | The product new release notes get when the caller names none. |
| getDefaultTemplate() | DocumentReference | The template new release notes start from when the caller names none. |
Model
| Type | Holds |
|---|---|
| ReleaseNote | product, version, date (Date), released (boolean), template (DocumentReference). |
| Change | product, version, title, summary, description, audience, importance, category, screenshots (List<String>). It is both the write input and the read output, and carries no reference of its own: the reference is what createChange returns and what getChange takes. |
| Audience | USER, ADMINISTRATOR, DEVELOPER. |
| Importance | LOW, MEDIUM, HIGH, stored as 0, 1 and 2. |
| ChangeQuery | A List<ChangeFilter> per filtered field, plus limit (100 by default) and offset. A ChangeFilter is an Operator, one of LIKE, EQUALS, LT, LTE, GT or GTE, and a value. |
| ChangeSearchResult | getChanges(), getChangeNames() and hasMore(). |
A ChangeQuery is built field by field, or parsed from the lenient comma-separated strings the macros and the REST resources take, with ChangeQueryParser:
@Inject
private ChangeManager changeManager;
@Inject
private ChangeQueryParser queryParser;
public List<DocumentReference> highImportanceUserChanges(String version) throws ReleaseNotesException
{
ChangeQuery query = this.queryParser.parse(Map.of(
"products", "MyProduct", "versions", version, "audience", "user", "importance", ">=medium"));
return this.changeManager.search(query).getChanges();
}Writing a change is typed, so an invalid value fails at the call rather than in the database, while querying keeps the wildcards and the operator prefixes of the filter language:
Change change = new Change();
change.setProduct("MyProduct");
change.setVersion("3.0-milestone-1");
change.setTitle("Live Data replaces the Live Table");
change.setAudience(Audience.USER);
change.setImportance(Importance.HIGH);
DocumentReference created = this.changeManager.createChange(change);Rights and errors
Every write checks edit right on the page it is about to create, for the context user and for the context author, inside the component. A caller cannot skip that check by going through Java rather than through a script, and a component reached from a script service must not assume its own author's rights are enough. A refusal is a ReleaseNotesAccessDeniedException.
Everything that can fail throws ReleaseNotesException, a checked exception; ReleaseNoteAlreadyExistsException, ReleaseNotesAccessDeniedException and ReleaseNotesNotFoundException extend it and carry the page concerned.
The whole surface is @Unstable, so it may still change from one release to the next.
FAQ
Is the change search rights-filtered?
No. search reports every change matching the query, which is what the release notes and the reports themselves display.
Why is there no method to delete a change?
Deleting needs no name allocated and no template applied, so it stays an ordinary document write. Replacing one does not: updateChange exists because a caller that only set the ChangeClass properties itself would have to know which of them a change is made of.
Which module do I depend on?
application-releasenotes-api. The XAR of the application already brings it, so an extension only needs it at compile time.