diff --git a/README.md b/README.md index 09ec90dc..e3922781 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,8 @@ Verify changes by running `yarn lint && yarn test` before committing. To create a release: 1. Run `yarn version --new-version ` which will create a change log commit and version tag. -2. Run `git push --atomic origin master TAG` which will trigger a GitHub release job. This will publish the new version to the "gh-pages" branch. +2. Run `git push --atomic origin master TAG` (e.g. `git push --atomic origin master v0.0.14`) which will trigger a GitHub release job. + This will publish the new version to the "gh-pages" branch. ## Adding a new extension diff --git a/extensions/aerial-photo/schema.json b/extensions/aerial-photo/schema.json index fedf2041..4aa48fb2 100644 --- a/extensions/aerial-photo/schema.json +++ b/extensions/aerial-photo/schema.json @@ -58,7 +58,7 @@ "type": "object", "allOf": [ { - "required": ["type", "summaries"] + "required": ["type"] }, { "$ref": "#/definitions/fields" diff --git a/extensions/aerial-photo/tests/aerial_photo_collection.test.js b/extensions/aerial-photo/tests/aerial_photo_collection.test.js index 8fead2b5..b1f124bc 100644 --- a/extensions/aerial-photo/tests/aerial_photo_collection.test.js +++ b/extensions/aerial-photo/tests/aerial_photo_collection.test.js @@ -30,6 +30,18 @@ o.spec('Aerial Photo Extension Collection', () => { o(valid).equals(true)(JSON.stringify(validate.errors, null, 2)); }); + o('Missing summaries section should pass validation', async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example.summaries; + + // when + let valid = validate(example); + + // then + o(valid).equals(true)(JSON.stringify(validate.errors, null, 2)); + }); + o("Summaries with no 'aerial-photo:run' property should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); diff --git a/extensions/camera/tests/camera_collection.test.js b/extensions/camera/tests/camera_collection.test.js index 967f8dc4..971e3cc1 100644 --- a/extensions/camera/tests/camera_collection.test.js +++ b/extensions/camera/tests/camera_collection.test.js @@ -29,4 +29,16 @@ o.spec('Camera Extension Collection', () => { // then o(valid).equals(true)(JSON.stringify(validate.errors, null, 2)); }); + + o('Missing summaries section should pass validation', async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example.summaries; + + // when + let valid = validate(example); + + // then + o(valid).equals(true)(JSON.stringify(validate.errors, null, 2)); + }); }); diff --git a/extensions/film/schema.json b/extensions/film/schema.json index 8312b1d6..5ae73a27 100644 --- a/extensions/film/schema.json +++ b/extensions/film/schema.json @@ -58,7 +58,7 @@ "type": "object", "allOf": [ { - "required": ["type", "summaries"] + "required": ["type"] }, { "$ref": "#/definitions/fields" diff --git a/extensions/film/tests/film_collection.test.js b/extensions/film/tests/film_collection.test.js index 3496f60f..c60a8638 100644 --- a/extensions/film/tests/film_collection.test.js +++ b/extensions/film/tests/film_collection.test.js @@ -30,6 +30,18 @@ o.spec('Film Extension Collection', () => { o(valid).equals(true)(JSON.stringify(validate.errors, null, 2)); }); + o('Missing summaries section should pass validation', async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example.summaries; + + // when + let valid = validate(example); + + // then + o(valid).equals(true)(JSON.stringify(validate.errors, null, 2)); + }); + o("Summaries with no 'film:id' property should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); diff --git a/extensions/historical-imagery/examples/collection.json b/extensions/historical-imagery/examples/collection.json index 2be2229b..8c0208d9 100644 --- a/extensions/historical-imagery/examples/collection.json +++ b/extensions/historical-imagery/examples/collection.json @@ -3,9 +3,13 @@ "stac_version": "1.0.0", "stac_extensions": [ "https://stac.linz.govt.nz/_STAC_VERSION_/historical-imagery/schema.json", + "https://stac.linz.govt.nz/_STAC_VERSION_/linz/schema.json", + "https://stac.linz.govt.nz/_STAC_VERSION_/quality/schema.json", "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/processing/v1.0.0/schema.json", "https://stac-extensions.github.io/projection/v1.0.0/schema.json", "https://stac-extensions.github.io/file/v2.0.0/schema.json", + "https://stac-extensions.github.io/version/v1.0.0/schema.json", "https://stac.linz.govt.nz/_STAC_VERSION_/aerial-photo/schema.json", "https://stac.linz.govt.nz/_STAC_VERSION_/camera/schema.json", "https://stac.linz.govt.nz/_STAC_VERSION_/film/schema.json", @@ -23,6 +27,32 @@ "interval": [["1947-03-28T12:00:00Z", "1952-04-22T12:00:00Z"]] } }, + "linz:security_classification": "unclassified", + "linz:lifecycle": "completed", + "linz:history": "LINZ and its predecessors, Lands & Survey and Department of Survey and Land Information (DOSLI), commissioned aerial photography for the Crown between 1936 and 2008.\nOne of the predominant uses of the aerial photography at the time was the photogrammetric mapping of New Zealand, initially at 1inch to 1mile followed by the NZMS 260 and Topo50 map series at 1:50,000.\nThese photographs were scanned through the Crown Aerial Film Archive scanning project.", + "linz:providers": [ + { + "name": "Toitū Te Whenua LINZ", + "description": "The New Zealand Government's lead agency for location and property information, Crown land and managing overseas investment.", + "roles": ["custodian"], + "url": "https://www.linz.govt.nz/about-linz/what-were-doing/projects/crown-aerial-film-archive-historical-imagery-scanning-project" + }, + { + "name": "Manager Partnership Programmes", + "roles": ["manager"] + } + ], + "linz:geospatial_type": "black and white image", + "linz:asset_summaries": { + "created": { + "minimum": "1999-01-01T00:00:00Z", + "maximum": "2021-12-09T00:04:09Z" + }, + "updated": { + "minimum": "1999-01-02T00:00:00Z", + "maximum": "2021-12-09T00:04:09Z" + } + }, "providers": [ { "name": "NZ Aerial Mapping", @@ -36,6 +66,10 @@ "url": "https://www.linz.govt.nz/about-linz/what-were-doing/projects/crown-aerial-film-archive-historical-imagery-scanning-project" } ], + "processing:software": { + "Topo Processor": "0.1.0" + }, + "version": "1", "summaries": { "platform": ["Fixed-wing Aircraft"], "instruments": ["EAGLE IV"], diff --git a/extensions/historical-imagery/examples/item.json b/extensions/historical-imagery/examples/item.json index ca9bea6e..a4dea4db 100644 --- a/extensions/historical-imagery/examples/item.json +++ b/extensions/historical-imagery/examples/item.json @@ -1,16 +1,19 @@ { + "type": "Feature", "stac_version": "1.0.0", "stac_extensions": [ "https://stac.linz.govt.nz/_STAC_VERSION_/historical-imagery/schema.json", + "https://stac.linz.govt.nz/_STAC_VERSION_/linz/schema.json", "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/processing/v1.0.0/schema.json", "https://stac-extensions.github.io/projection/v1.0.0/schema.json", "https://stac-extensions.github.io/file/v2.0.0/schema.json", + "https://stac-extensions.github.io/version/v1.0.0/schema.json", "https://stac.linz.govt.nz/_STAC_VERSION_/aerial-photo/schema.json", "https://stac.linz.govt.nz/_STAC_VERSION_/camera/schema.json", "https://stac.linz.govt.nz/_STAC_VERSION_/film/schema.json", "https://stac.linz.govt.nz/_STAC_VERSION_/scanning/schema.json" ], - "type": "Feature", "id": "215354", "bbox": [170.54524, -45.80237, 170.56431, -45.81345], "geometry": { @@ -44,7 +47,11 @@ "film:physical_condition": "Film scratched", "film:physical_size": "18cm x 23cm", "scan:is_original": true, - "scan:scanned": "2018-09-30T11:00:00Z" + "scan:scanned": "2018-09-30T11:00:00Z", + "processing:software": { + "Topo Processor": "0.1.0" + }, + "version": "1" }, "links": [ { @@ -68,7 +75,9 @@ "name": "gray", "common_name": "pan" } - ] + ], + "created": "2021-12-09T00:04:09Z", + "updated": "2021-12-09T00:04:09Z" } }, "collection": "01FJ0SE46TT5TGBHBVX64TMEPA" diff --git a/extensions/historical-imagery/schema.json b/extensions/historical-imagery/schema.json index 1f2e41bd..7fda438a 100644 --- a/extensions/historical-imagery/schema.json +++ b/extensions/historical-imagery/schema.json @@ -29,7 +29,7 @@ "properties": { "type": "object", "$comment": "Require fields here for Item Properties.", - "required": ["platform", "mission"] + "required": ["platform", "mission", "processing:software"] }, "assets": { "type": "object", @@ -57,7 +57,7 @@ "allOf": [ { "type": "object", - "required": ["type", "title", "providers", "summaries"] + "required": ["type", "title", "providers", "summaries", "processing:software"] } ] }, @@ -78,6 +78,11 @@ "const": "https://stac.linz.govt.nz/_STAC_VERSION_/historical-imagery/schema.json" } }, + { + "contains": { + "const": "https://stac.linz.govt.nz/_STAC_VERSION_/linz/schema.json" + } + }, { "contains": { "const": "https://stac-extensions.github.io/eo/v1.0.0/schema.json" diff --git a/extensions/historical-imagery/tests/historical-imagery_collection.test.js b/extensions/historical-imagery/tests/historical-imagery_collection.test.js index e421160b..f54ee749 100644 --- a/extensions/historical-imagery/tests/historical-imagery_collection.test.js +++ b/extensions/historical-imagery/tests/historical-imagery_collection.test.js @@ -79,6 +79,23 @@ o.spec('Historical Imagery Extension Collection', () => { ); }); + o("Example with missing 'processing:software' property should fail validation", async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example['processing:software']; + + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => error.instancePath === '' && error.message === "must have required property 'processing:software'", + ), + ).equals(true)(JSON.stringify(validate.errors)); + }); + o("Example without 'providers' should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); @@ -227,4 +244,21 @@ o.spec('Historical Imagery Extension Collection', () => { // then o(valid).equals(true); }); + + o("Example with no 'summaries' should fail validation", async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example.summaries; + + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => error.instancePath === '' && error.message === "must have required property 'summaries'", + ), + ).equals(true)(JSON.stringify(validate.errors)); + }); }); diff --git a/extensions/historical-imagery/tests/historical-imagery_item.test.js b/extensions/historical-imagery/tests/historical-imagery_item.test.js index d6c421f8..5f6e6d2e 100644 --- a/extensions/historical-imagery/tests/historical-imagery_item.test.js +++ b/extensions/historical-imagery/tests/historical-imagery_item.test.js @@ -122,4 +122,21 @@ o.spec('Historical Imagery Extension Item', () => { ), ).equals(true)(JSON.stringify(validate.errors)); }); + + o("Example without mandatory 'processing:software' property should fail validation", async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example.properties['processing:software']; + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.instancePath === '/properties' && error.message === "must have required property 'processing:software'", + ), + ).equals(true)(JSON.stringify(validate.errors)); + }); }); diff --git a/extensions/scanning/tests/scanning_collection.test.js b/extensions/scanning/tests/scanning_collection.test.js index 7db6152d..5e0efd10 100644 --- a/extensions/scanning/tests/scanning_collection.test.js +++ b/extensions/scanning/tests/scanning_collection.test.js @@ -29,4 +29,16 @@ o.spec('Scanning Extension Collection', () => { // then o(valid).equals(true)(JSON.stringify(validate.errors, null, 2)); }); + + o('Missing summaries section should pass validation', async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example.summaries; + + // when + let valid = validate(example); + + // then + o(valid).equals(true)(JSON.stringify(validate.errors, null, 2)); + }); });