Compare commits

...

13 Commits

Author SHA1 Message Date
Simon
aae97ec78a Merge branch 'BL2_frozen_wastelands' into 'main'
feat(#5): Publie le set "Frozen Wastelands"

See merge request Thoscellen/Wallset!10
2023-05-18 22:09:47 +00:00
Simon
f1845c7101 feat(#5): Publie le set "Frozen Wastelands" 2023-05-18 22:09:46 +00:00
Simon
f56b7877dc Merge branch 'BL2_frozen_wasteland' into 'main'
See merge request Thoscellen/Wallset!8
2023-05-18 21:40:52 +00:00
Simon
181caf6092 Publie le set "Frozen Wastelands" 2023-05-18 21:40:52 +00:00
Simon
e31f02cd38 Merge branch 'cicd' into 'main'
Tente un fixe pour la pipeline.

See merge request Thoscellen/Wallset!9
2023-05-18 21:17:34 +00:00
Simon
123733def0 Tente un fixe pour la pipeline. 2023-05-18 21:17:34 +00:00
Simon
226a3a3856 Merge branch 'cicd' into 'main'
Règle la CI pour se déclencher après une demande de fusion

See merge request Thoscellen/Wallset!7
2023-05-18 13:15:09 +00:00
Simon
6ec4d836cc Règle la CI pour se déclencher après une demande de fusion 2023-05-18 13:15:09 +00:00
Simon
4d394dc080 Merge branch 'cicd' into 'main'
Détecte si un thème est déjà présent

See merge request Thoscellen/Wallset!6
2023-05-18 12:30:10 +00:00
Simon
d541628920 Détecte si un thème est déjà présent 2023-05-18 12:30:10 +00:00
Simon
9d6ddf6e25 Fusionnne les jobs node en un 2023-05-17 22:58:37 +02:00
Simon
e0c1ad7e03 Ecrit le générateur de manifeste 2023-05-17 22:58:26 +02:00
Simon
6fe5481363 Initialise le fichier .gitlab-ci.yml 2023-05-17 22:57:54 +02:00
49 changed files with 1630 additions and 2022 deletions

10
.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
# Ignore node_module
**/node_modules/
# Ignore python stuff
**/__pycache__
**/.pytest_cache
# Ignore les fichiers système de MacOS
**/.DS_Store

101
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,101 @@
include:
- .gitlab/*.yml
stages:
- Manifest
- Test
- Bundle
- Distribute
- Release
variables:
ENTRY_FOLDER: assets
RELEASE_VERSION: v$CI_PIPELINE_IID
PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${PACKAGE_NAME}/${RELEASE_VERSION}"
# Jobs from here run on Merge Requests as prerequisite for merging.
.manifest-job:
stage: Manifest
image: node:latest
rules:
- if: $CI_COMMIT_TAG
when: never
- changes:
- ${ENTRY_FOLDER}/${PACKAGE_NAME}/*
script:
- cd src/
- npm install
- npm run start
- cat ../${ENTRY_FOLDER}/${PACKAGE_NAME}/theme.json
- npm run test
artifacts:
paths:
- ${ENTRY_FOLDER}/${PACKAGE_NAME}/theme.json
when: on_success
expire_in: "1 hour"
.test-job:
stage: Test
image: python:latest
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- ${ENTRY_FOLDER}/${PACKAGE_NAME}/*
script:
- pip install -U pytest pillow iteration_utilities
- python -m pytest src/test_images.py --tb=line -rA --color=yes
allow_failure: true
# Jobs from here run Merged_results or Push/Merge Commits to the main branch. Tag is created on release so no run with tag creation
.bundle-job:
stage: Bundle
image: javieraviles/zip:latest
rules:
- if: $CI_COMMIT_TAG
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
changes:
- ${ENTRY_FOLDER}/${PACKAGE_NAME}/*
script:
- zip -j ${PACKAGE_NAME}.zip ${ENTRY_FOLDER}/${PACKAGE_NAME}/*
artifacts:
paths:
- ${PACKAGE_NAME}.zip
when: on_success
expire_in: "1 hour"
.upload-job:
stage: Distribute
image: curlimages/curl:latest
rules:
- if: $CI_COMMIT_TAG
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
changes:
- ${ENTRY_FOLDER}/${PACKAGE_NAME}/*
script:
- |
curl --fail \
--header "JOB-TOKEN: ${CI_JOB_TOKEN}" \
--upload-file ${PACKAGE_NAME}.zip "${PACKAGE_REGISTRY_URL}/${PACKAGE_NAME}.zip?select=package_file"
.release-job:
stage: Release
image: registry.gitlab.com/gitlab-org/release-cli:latest
rules:
- if: $CI_COMMIT_TAG
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
changes:
- ${ENTRY_FOLDER}/${PACKAGE_NAME}/*
script:
- echo "Releasing assets for $PACKAGE_NAME"
release:
name: "Release $PACKAGE_NAME $RELEASE_VERSION"
tag_name: "$PACKAGE_NAME.$RELEASE_VERSION"
description: "Version $RELEASE_VERSION"
ref: "$CI_COMMIT_SHA"
assets:
links:
- name: ${PACKAGE_NAME}
url: "${PACKAGE_REGISTRY_URL}/${PACKAGE_NAME}.zip"

View File

@@ -0,0 +1,32 @@
manifest-job/BL2_frozen_wastelands:
variables:
PACKAGE_NAME: "BL2_frozen_wastelands"
extends: .manifest-job
test-images-job/BL2_frozen_wastelands:
needs:
- manifest-job/BL2_frozen_wastelands
variables:
PACKAGE_NAME: "BL2_frozen_wastelands"
extends: .test-job
bundle-job/BL2_frozen_wastelands:
needs:
- manifest-job/BL2_frozen_wastelands
variables:
PACKAGE_NAME: "BL2_frozen_wastelands"
extends: .bundle-job
upload-job/BL2_frozen_wastelands:
needs:
- bundle-job/BL2_frozen_wastelands
variables:
PACKAGE_NAME: "BL2_frozen_wastelands"
extends: .upload-job
release-job/BL2_frozen_wastelands:
needs:
- upload-job/BL2_frozen_wastelands
variables:
PACKAGE_NAME: "BL2_frozen_wastelands"
extends: .release-job

121
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,121 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Gen-Manifest Valid_set",
"cwd": "${workspaceFolder}/src",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"start"
],
"env": {
"CI_PROJECT_DIR": "${workspaceFolder}",
"ENTRY_FOLDER": "test",
"PACKAGE_NAME": "valid_set"
},
"skipFiles": [
"<node_internals>/**"
],
},
{
"name": "Test-Manifest Valid_set",
"cwd": "${workspaceFolder}/src",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"test"
],
"env": {
"CI_PROJECT_DIR": "${workspaceFolder}",
"ENTRY_FOLDER": "test",
"PACKAGE_NAME": "valid_set"
},
"skipFiles": [
"<node_internals>/**"
],
},
{
"name": "Test-Images Valid_set",
"cwd": "${workspaceFolder}/src",
"console": "internalConsole",
"type": "python",
"request": "launch",
"module": "pytest",
"args": [
"test_images.py",
"-rA",
"--tb=line",
"--color=yes"
],
"env": {
"CI_PROJECT_DIR": "${workspaceFolder}",
"ENTRY_FOLDER": "test",
"PACKAGE_NAME": "valid_set"
},
"justMyCode": true
},
{
"name": "Gen-Manifest existing_valid_theme_set",
"cwd": "${workspaceFolder}/src",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"start"
],
"env": {
"CI_PROJECT_DIR": "${workspaceFolder}",
"ENTRY_FOLDER": "test",
"PACKAGE_NAME": "existing_valid_theme_set"
},
"skipFiles": [
"<node_internals>/**"
],
},
{
"name": "Test-Manifest existing_valid_theme_set",
"cwd": "${workspaceFolder}/src",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"test"
],
"env": {
"CI_PROJECT_DIR": "${workspaceFolder}",
"ENTRY_FOLDER": "test",
"PACKAGE_NAME": "existing_valid_theme_set"
},
"skipFiles": [
"<node_internals>/**"
],
},
{
"name": "Test-Images existing_valid_theme_set",
"cwd": "${workspaceFolder}/src",
"console": "internalConsole",
"type": "python",
"request": "launch",
"module": "pytest",
"args": [
"test_images.py",
"-rA",
"--tb=line",
"--color=yes"
],
"env": {
"CI_PROJECT_DIR": "${workspaceFolder}",
"ENTRY_FOLDER": "test",
"PACKAGE_NAME": "existing_valid_theme_set"
},
"justMyCode": true
},
]
}

5
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"conventionalCommits.scopes": [
"cicd"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 977 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 952 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1009 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

78
src/build-manifest.js Normal file
View File

@@ -0,0 +1,78 @@
const fs = require("fs");
const path = require("path");
const iptc = require("node-iptc");
const { exit } = require("process");
// Fetch envs to target the right folder
const workDir = process.env["CI_PROJECT_DIR"];
const root = process.env["ENTRY_FOLDER"];
const slug = process.env["PACKAGE_NAME"];
if (!workDir || !slug || !root) exit(1);
let workingDirectory = path.join(workDir, root, slug);
// extract metadata from them
fs.readdir(workingDirectory, (err, files) => {
if (err) { throw err }; // If IO error, exit with an error message
// If there is already a theme.json silentely exit and let mocha running afterwards
if (files.find(file => path.extname(file) == '.json')) exit(0);
// construct a JSON object
let theme = new Object();
theme.dayImageList = [];
theme.nightImageList = [];
theme.sunsetImageList = [];
theme.sunriseImageList = [];
// iterate each files
files.filter(file => path.extname(file) == '.jpg').forEach(image => {
buffer = fs.readFileSync(path.join(workingDirectory, image));
// extract metadata
let metadata = iptc(buffer);
theme.imageFilename ||= metadata.special_instructions + "_*" + path.extname(image);
theme.imageCredits ||= metadata.copyright_notice;
theme.displayName ||= metadata.headline;
// explore categories to find if image is dayHighlight or nightHighlight
metadata.supplemental_categories?.forEach(cat => {
switch (cat) {
case "dayHighlight":
theme.dayHighlight ||= parseInt(metadata.original_transmission_reference);
break;
case "nightHighlight":
theme.nightHighlight ||= parseInt(metadata.original_transmission_reference);
break;
default:
break;
}
});
switch (metadata.category) {
case "day":
theme.dayImageList.push(parseInt(metadata.original_transmission_reference));
break;
case "night":
case "nig":
theme.nightImageList.push(parseInt(metadata.original_transmission_reference));
break;
case "sunset":
case "twilight":
case "twi":
theme.sunsetImageList.push(parseInt(metadata.original_transmission_reference));
break;
case "sunrise":
case "dawn":
case "daw":
theme.sunriseImageList.push(parseInt(metadata.original_transmission_reference));
break;
default:
break;
}
});
// make it the theme.json
fs.writeFileSync(path.join(workingDirectory, 'theme.json'), JSON.stringify(theme));
});

View File

@@ -0,0 +1,86 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"imageFilename",
"imageCredits",
"displayName",
"dayImageList",
"nightImageList"
],
"properties": {
"imageFilename": {
"type": "string"
},
"imageCredits": {
"type": "string"
},
"displayName": {
"type": "string"
},
"dayHighlight": {
"type": "integer",
"minimum": 0
},
"nightHighlight": {
"type": "integer",
"minimum": 0
},
"sunriseImageList": {
"type": "array",
"minItems": 0,
"uniqueItems": true,
"items": {
"type": "integer",
"minimum": 0
}
},
"dayImageList": {
"type": "array",
"minItems": 0,
"uniqueItems": true,
"items": {
"type": "integer",
"minimum": 0
}
},
"sunsetImageList": {
"type": "array",
"minItems": 0,
"uniqueItems": true,
"items": {
"type": "integer",
"minimum": 0
}
},
"nightImageList": {
"type": "array",
"minItems": 0,
"uniqueItems": true,
"items": {
"type": "integer",
"minimum": 0
}
}
},
"errorMessage": {
"required": {
"imageFilename": "The imageFilename property is missing.",
"imageCredits": "The imageCredits property is missing.",
"displayName": "The displayName property is missing.",
"dayImageList": "The dayImageList property is missing.",
"nightImageList": "The nightImageList property is missing."
},
"properties": {
"imageFilename": "The imageFilename property must be of type string.",
"imageCredits": "The imageCredits property must be of type string.",
"displayName": "The displayName property must be of type string.",
"dayHighlight": "The dayHighlight property must be a counting number.",
"nightHighlight": "The nightHighlight property must be a counting number.",
"sunriseImageList": "The sunriseImageList property must be a list of counting numbers.",
"dayImageList": "The dayImageList property must be a list of counting numbers.",
"sunsetImageList": "The sunsetImageList property must be a list of counting numbers.",
"nightImageList": "The nightImageList property must be a list of counting numbers."
}
}
}

74
src/manifest.spec.js Normal file
View File

@@ -0,0 +1,74 @@
const fs = require("fs");
const path = require("path");
const expect = require("chai").expect;
const Ajv = require("ajv").default;
const ajv = new Ajv({ allErrors: true });
require("ajv-errors")(ajv);
const themeSchemaFile = "json_theme_schema.jsonc";
let manifest;
let validator;
let files;
let workingDirectory;
function leftOuterJoin(leftArray, rightArray) {
return leftArray.filter(function (el) {
return this.indexOf(el) < 0;
}, rightArray);
}
function flatReferences(manifest) {
allImageIds = [
manifest.dayHighlight,
manifest.nightHighlight,
...manifest.dayImageList,
...manifest.nightImageList,
...(manifest.sunsetImageList || []),
...(manifest.sunriseImageList || [])
];
return allImageIds.filter(el => el !== undefined).map(el => {
return manifest.imageFilename.replace("*", el);
});
}
describe('Mandatory Checks', function () {
before(function () {
const workDir = process.env["CI_PROJECT_DIR"];
expect(workDir).to.be.a("string").that.is.not.empty;
const slug = process.env["PACKAGE_NAME"];
expect(slug).to.be.a("string").that.is.not.empty;
const root = process.env["ENTRY_FOLDER"];
expect(root).to.be.a("string").that.is.not.empty;
workingDirectory = path.join(workDir, root, slug);
files = fs.readdirSync(workingDirectory);
expect(files).to.be.an('array').that.is.not.empty;
validator = ajv.compile(JSON.parse(fs.readFileSync(themeSchemaFile, 'utf8')));
});
step('Manifest is an existing json file', function () {
manifest = JSON.parse(fs.readFileSync(path.join(workingDirectory, "theme.json"), "utf8"));
});
step('Manifest passes the schema', function () {
const isValid = validator(manifest);
if (!isValid) expect.fail(`\n\t${validator.errors.map(el => { return el.message; }).join('\n\t• ')}`);
});
step('There are no missing files', function () {
let references = flatReferences(manifest);
references.push("theme.json");
let missings = leftOuterJoin(references, files);
expect(missings,
`The following reference${(missings.length > 1) ? "s" : ""} from theme.json ${(missings.length > 1) ? "are" : "is"} missing in the pack. Consider adding ${(missings.length > 1) ? "them" : " it"} to the pack or removing the reference${(missings.length > 1) ? "s" : ""} from the theme.json:\n\t${missings.join('\n\t• ')}\n`
).to.be.lengthOf(0,);
});
step('There are no orphan files', function () {
let references = flatReferences(manifest);
let orphans = leftOuterJoin(files.filter(x => x !== "theme.json"), references);
expect(orphans,
`The following orphan file${(orphans.length > 1) ? "s are" : " is"} not referenced in this theme.json. Consider removing the file${(orphans.length > 1) ? "s" : ""} or referencing ${(orphans.length > 1) ? "them" : "it"} in the theme.json:\n\t${orphans.join('\n\t• ')}\n`
).to.be.lengthOf(0);
});
});

1066
src/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

20
src/package.json Normal file
View File

@@ -0,0 +1,20 @@
{
"name": "build-manifest",
"version": "1.0.0",
"description": "Generate the manifest file of the project, based on metadata contained in the pictures.",
"main": "build-manifest.js",
"scripts": {
"start": "node build-manifest.js",
"test": "mocha --require mocha-steps --timeout 0 --colors manifest.spec.js"
},
"author": "Simon",
"license": "ISC",
"dependencies": {
"ajv": "^8.5.0",
"ajv-errors": "^3.0.0",
"chai": "^4.3.4",
"mocha": "^10.2.0",
"mocha-steps": "^1.3.0",
"node-iptc": "^1.0.5"
}
}

View File

@@ -1,6 +1,5 @@
import glob import glob
from PIL import Image, ImageStat from PIL import Image, ImageStat
# from _pytest.outcomes import skip
from iteration_utilities import duplicates from iteration_utilities import duplicates
from pathlib import Path from pathlib import Path
import json import json
@@ -8,18 +7,15 @@ import os
import pytest import pytest
def validate_brightness_image(working_path, theme_config, high_light, image_list, brightness_way): def _validate_brightness_image(working_path, theme_config, high_light, image_list, brightness_way):
# get a dict<filename:string, mean:int> of all images to scan them
image_pattern = theme_config.get("imageFilename") image_pattern = theme_config.get("imageFilename")
# if image_filenames is None:
image_filenames = {}.fromkeys(glob.glob(str(Path(working_path, image_pattern)))) image_filenames = {}.fromkeys(glob.glob(str(Path(working_path, image_pattern))))
# generate an image statistics for each images # generate an image statistics for each images
for an_imagefile in image_filenames: for an_imagefile in image_filenames:
this_image = Image.open(an_imagefile).convert("L") this_image = Image.open(an_imagefile).convert("L")
this_image_stats = ImageStat.Stat(this_image) this_image_stats = ImageStat.Stat(this_image)
image_filenames[an_imagefile] = this_image_stats.mean[0] image_filenames[an_imagefile] = this_image_stats.mean[0]
#print(f'{an_imagefile} : {image_filenames[an_imagefile]}')
# get the brightest observed image from the list # get the brightest observed image from the list
if high_light == "dayHighlight": if high_light == "dayHighlight":
@@ -32,7 +28,6 @@ def validate_brightness_image(working_path, theme_config, high_light, image_list
an_image = image_pattern.replace("*", str(theme_config.get(high_light))) an_image = image_pattern.replace("*", str(theme_config.get(high_light)))
ref_est_file = str(Path(working_path, an_image)) ref_est_file = str(Path(working_path, an_image))
assert actual_est_image == ref_est_file, f"{brightness_way} image is {actual_est_image}, but the {high_light} image is {ref_est_file}." assert actual_est_image == ref_est_file, f"{brightness_way} image is {actual_est_image}, but the {high_light} image is {ref_est_file}."
else: else:
# if not highlight is given in theme.json, we suppose that brightest images are in the daylist # if not highlight is given in theme.json, we suppose that brightest images are in the daylist
ref_est_files = [] ref_est_files = []
@@ -40,15 +35,15 @@ def validate_brightness_image(working_path, theme_config, high_light, image_list
an_image = image_pattern.replace('*', str(an_id)) an_image = image_pattern.replace('*', str(an_id))
ref_est_files.append(str(Path(working_path, an_image))) ref_est_files.append(str(Path(working_path, an_image)))
assert actual_est_image in ref_est_files, f"{brightness_way} image {actual_est_image} was not found in the '{image_list}' attribute." assert actual_est_image in ref_est_files, f"{brightness_way} image {actual_est_image} was not found in the '{image_list}' attribute."
# print(f"✔ {brightness_way} image is {actual_est_image}, as expected.")
@pytest.fixture @pytest.fixture
def working_path(): def working_path():
# get the global variables containing gitlab-given project slug. # get the global variables containing gitlab-given project slug.
project_slug = os.environ["WPP_SLUG"] work_directory = os.environ["CI_PROJECT_DIR"]
root_folder = os.environ["WPP_ROOT"] entry_folder = os.environ["ENTRY_FOLDER"]
working_path = Path(root_folder, project_slug) project_slug = os.environ["PACKAGE_NAME"]
working_path = Path(work_directory, entry_folder, project_slug)
if not working_path.is_dir(): if not working_path.is_dir():
raise FileNotFoundError(f"No project found for the given {working_path}.") raise FileNotFoundError(f"No project found for the given {working_path}.")
return working_path return working_path
@@ -61,21 +56,18 @@ def manifest(working_path):
def test_brightest_image(working_path, manifest): def test_brightest_image(working_path, manifest):
validate_brightness_image(working_path, manifest, "dayHighlight", "dayImageList", "Brightest") _validate_brightness_image(working_path, manifest, "dayHighlight", "dayImageList", "Brightest")
def test_darkest_image(working_path, manifest): def test_darkest_image(working_path, manifest):
validate_brightness_image(working_path, manifest, "nightHighlight", "nightImageList", "Darkest") _validate_brightness_image(working_path, manifest, "nightHighlight", "nightImageList", "Darkest")
def test_image_size(working_path, manifest): def test_image_size(working_path, manifest):
image_filename = manifest["imageFilename"].replace("*", str(manifest["dayImageList"][0])) image_filename = manifest["imageFilename"].replace("*", str(manifest["dayImageList"][0]))
img = Image.open(Path(working_path, image_filename)) w, h = Image.open(Path(working_path, image_filename)).size
w, h = img.size
assert w >= 1920 and h >= 1080, f"✖ Image size is too small (must be at least 1920×1080, is {w}×{h})" assert w >= 1920 and h >= 1080, f"✖ Image size is too small (must be at least 1920×1080, is {w}×{h})"
assert w >= h, "✖ Image orientation is portrait (must be landscape or square)" assert w >= h, "✖ Image orientation is portrait (must be landscape or square)"
# print(f"✔ Images are big enough ({w}×{h}) and landscape.")
def test_overlapping_images(manifest): def test_overlapping_images(manifest):
jointed_lists = manifest.get("dayImageList") jointed_lists = manifest.get("dayImageList")
@@ -87,5 +79,4 @@ def test_overlapping_images(manifest):
str_dup_refs = [manifest["imageFilename"].replace("*", str(int)) for int in dup_refs] str_dup_refs = [manifest["imageFilename"].replace("*", str(int)) for int in dup_refs]
separator = ", " separator = ", "
assert not dup_refs, f"✖ Some images are referenced twice or more times: {separator.join(str_dup_refs)}." assert not dup_refs, f"✖ Some images are referenced twice or more: {separator.join(str_dup_refs)}."
# print("✔ There is no overlapping references of images in the theme.json.")

View File

@@ -1,56 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["imageFilename","imageCredits","displayName","dayImageList","nightImageList"],
"properties": {
"imageFilename": {"type": "string"},
"imageCredits": {"type": "string"},
"displayName": {"type": "string"},
"dayHighlight": {"type": "integer", "minimum": 0},
"nightHighlight": {"type": "integer", "minimum": 0},
"sunriseImageList": {
"type": "array",
"minItems" : 0,
"uniqueItems" : true,
"items": {"type": "integer", "minimum": 0}
},
"dayImageList": {
"type": "array",
"minItems" : 0,
"uniqueItems" : true,
"items": {"type": "integer", "minimum": 0}
},
"sunsetImageList": {
"type": "array",
"minItems" : 0,
"uniqueItems" : true,
"items": {"type": "integer", "minimum": 0}
},
"nightImageList": {
"type": "array",
"minItems" : 0,
"uniqueItems" : true,
"items": {"type": "integer", "minimum": 0}
}
},
"errorMessage": {
"required": {
"imageFilename":"The imageFilename property is missing. Consider adding it.",
"imageCredits":"The imageCredits property is missing. Consider adding it.",
"displayName":"The displayName property is missing. Consider adding it.",
"dayImageList":"The dayImageList property is missing. Consider adding it.",
"nightImageList":"The nightImageList property is missing. Consider adding it."
},
"properties": {
"imageFilename": "The imageFilename property must be of type string and reflect a glob of an image, i.e.: myWallpaper_*.jpg.",
"imageCredits": "The imageCredits property must be of type string.",
"displayName": "The displayName property must be of type string.",
"dayHighlight": "The dayHighlight property must be a counting number referencing an image, i.e.: 5 in myWallpaper_5.jpg.",
"nightHighlight": "The nightHighlight property must be a counting number referencing an image, i.e.: 13 in myWallpaper_13.jpg.",
"sunriseImageList": "The sunriseImageList property must be a list of counting numbers referencing images, i.e.: [1, 2, 3, 4].",
"dayImageList": "The dayImageList property must be a list of counting numbers referencing images, i.e.: [1, 2, 3, 4].",
"sunsetImageList": "The sunsetImageList property must be a list of counting numbers referencing images, i.e.: [1, 2, 3, 4].",
"nightImageList": "The nightImageList property must be a list of counting numbers referencing images, i.e.: [1, 2, 3, 4]."
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +0,0 @@
{
"name": "wppchecker",
"version": "1.0.0",
"description": "",
"main": "wppChecker.js",
"scripts": {
"test": "mocha wppChecker.js --require mocha-step --colors"
},
"author": "PtiSimon",
"license": "ISC",
"dependencies": {
"ajv": "^8.5.0",
"ajv-errors": "^3.0.0",
"chai": "^4.3.4",
"mocha": "^8.4.0",
"mocha-steps": "^1.3.0"
}
}

View File

@@ -1,76 +0,0 @@
const fs = require("fs");
const path = require("path");
const { env, exit } = require("process");
const expect = require("chai").expect;
const Ajv = require("ajv").default;
const ajv = new Ajv({allErrors: true});
require("ajv-errors")(ajv);
//let root, slug;
//let workingDirectory = path.join(root, slug);
//console.log(`👷‍♂️ Working with ${slug} slug.`);
const themeSchemaFile = ".gitlab/node_job/json_theme_schema.jsonc";
let wppManifest;
let validator;
let files;
function leftOuterJoin(leftArray, rightArray) {
return leftArray.filter(function(el) {
return this.indexOf(el) < 0;
}, rightArray);
}
function flatReferences(wppManifest) {
allImageIds = [
wppManifest.dayHighlight,
wppManifest.nightHighlight,
...wppManifest.dayImageList,
...wppManifest.nightImageList,
...(wppManifest.sunsetImageList || []),
...(wppManifest.sunriseImageList || [])
];
return allImageIds.filter(el => el !== undefined).map(el => {
return wppManifest.imageFilename.replace("*", el);
});
}
describe('Mandatory Checks', function() {
before(function() {
slug = env.WPP_SLUG;
expect(slug).to.be.a("string").that.is.not.empty;
root = env.WPP_ROOT;
expect(root).to.be.a("string").that.is.not.empty;
workingDirectory = path.join(root, slug);
files = fs.readdirSync(workingDirectory);
expect(files).to.be.an('array').that.is.not.empty;
validator = ajv.compile(JSON.parse(fs.readFileSync(themeSchemaFile, 'utf8')));
});
step('Manifest is an existing json file', function() {
wppManifest = JSON.parse(fs.readFileSync(path.join(workingDirectory, "theme.json"), "utf8"));
});
step('Manifest passes the schema', function() {
const isValid = validator(wppManifest);
if(!isValid) expect.fail(`\n\t${validator.errors.map(el => {return el.message;}).join('\n\t• ')}`);
});
step('There are no missing files', function() {
let references = flatReferences(wppManifest);
references.push("theme.json");
missings = leftOuterJoin(references, files);
expect(missings,
`The following reference${(missings.length > 1)? "s": ""} from theme.json ${(missings.length > 1)? "are": "is"} missing in the pack. Consider adding ${(missings.length > 1)? "them": " it"} to the pack or removing the reference${(missings.length > 1)? "s": ""} from the theme.json:\n\t${missings.join('\n\t• ')}\n`
).to.be.lengthOf(0, );
});
step('There are no orphan files', function() {
let references = flatReferences(wppManifest);
orphans = leftOuterJoin(files.filter(x => x !== "theme.json"), references);
expect(orphans,
`The following orphan file${(orphans.length > 1)? "s are": " is"} not referenced in this theme.json. Consider removing the file${(orphans.length > 1)? "s": ""} or referencing ${(orphans.length > 1)? "them": "it"} in the theme.json:\n\t${orphans.join('\n\t• ')}\n`
).to.be.lengthOf(0);
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

View File

@@ -0,0 +1,13 @@
{
"dayImageList": [
1
],
"imageFilename": "stray__*.jpg",
"nightImageList": [
2
],
"imageCredits": "©Thoscellen, ©BlueTwelve",
"sunriseImageList": [],
"displayName": "Stray",
"sunsetImageList": []
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

View File

@@ -0,0 +1,14 @@
{
"imageFilename": "bl3_landscape_*.jpg",
"displayName": "BL3",
"imageCredits": "© Gearbox",
"dayImageList": [
2
],
"sunsetImageList": [
2
],
"nightImageList": [
3
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB