Skip to content

Commit

Permalink
Add a first inventory snapshot feature (for CI/CD)
Browse files Browse the repository at this point in the history
  • Loading branch information
ioanlucut committed Aug 8, 2023
1 parent 825cc90 commit fe27a56
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 3 deletions.
37 changes: 34 additions & 3 deletions src/core.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { first, last, parseInt, trim } from 'lodash';
import chalk from 'chalk';
import { SequenceChar } from './types';
import {
filter,
first,
includes,
last,
parseInt,
size,
trim,
uniq,
} from 'lodash';
import { SequenceChar, SongMeta } from './types';
import {
COLON,
COMMA,
Expand All @@ -10,6 +19,7 @@ import {
NEW_LINE_TUPLE,
TEST_ENV,
} from './constants';
import assert from 'node:assert';

const MISSING_SEQUENCE_NUMBER = 1;

Expand Down Expand Up @@ -84,7 +94,7 @@ export const getMetaSectionsFromTitle = (titleContent: string) => {
const [sequence, content] = entry.split(COLON);

return { ...accumulator, [sequence]: trim(content) };
}, {});
}, {}) as Record<SongMeta, string>;
};

export const createSongMock = (
Expand Down Expand Up @@ -119,3 +129,24 @@ ${tuples

export const convertSequenceToNumber = (sequenceOrderQualifier: string) =>
parseInt(sequenceOrderQualifier) || MISSING_SEQUENCE_NUMBER;

export const getTodayAsDateString = () => {
const now = new Date();

return (
('0' + now.getDate()).slice(-2) +
'-' +
('0' + (now.getMonth() + 1)).slice(-2) +
'-' +
now.getFullYear()
);
};

export const assertUniqueness = (array: string[]) =>
assert.equal(
size(uniq(array)),
size(array),
`There are duplicates: ${filter(array, (value, index, iteratee) =>
includes(iteratee, value, index + 1),
).join(COMMA)}`,
);
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './inventorySnapshotRunner';
export * from './migratorRunner';
export * from './proPresenter7SongConverter';
export * from './songsParser';
Expand Down
141 changes: 141 additions & 0 deletions src/inventorySnapshotRunner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import fs from 'fs';
import path from 'path';
import dotenv from 'dotenv';
import recursive from 'recursive-readdir';
import { isEqual, last, reject } from 'lodash';
import {
assertUniqueness,
getMetaSectionsFromTitle,
getSongInSectionTuples,
getTitleWithoutMeta,
getTodayAsDateString,
logFileWithLinkInConsole,
logProcessingFile,
} from './core';
import assert from 'node:assert';
import {
SongInventoryChange,
SongMeta,
SongsInventory,
SongsInventoryEntry,
} from './types';
import { TXT_EXTENSION } from './constants';

dotenv.config();

const inventoryChangelogFilename = path.join(
__dirname,
'..',
'inventoryChangelog.json',
);

const snapshotInventory = async (dir: string) => {
console.log(`"Reprocessing file names from ${dir} directory.."`);

const currentInventory = JSON.parse(
fs.readFileSync(inventoryChangelogFilename).toString(),
) as SongsInventory;

const { songs } = currentInventory;

const songsAsHashMap = songs.reduce(
(accumulator, entry) => ({
...accumulator,
[entry.id]: entry,
}),
{} as {
[id: string]: SongsInventoryEntry;
},
);

const songsMeta = (await recursive(dir))
.filter((filePath) => path.extname(filePath) === TXT_EXTENSION)
.map((filePath) => {
const filename = path.basename(filePath);
const fileContent = fs.readFileSync(filePath).toString();

logProcessingFile(filename, 'inventory generation');
logFileWithLinkInConsole(filePath);

const rawTitle = getSongInSectionTuples(fileContent)[1];

assert.ok(
rawTitle.includes(SongMeta.CONTENT_HASH),
`The ${SongMeta.CONTENT_HASH} should be defined.`,
);

return {
filename,
metaSections: getMetaSectionsFromTitle(rawTitle),
titleWithoutMetaSections: getTitleWithoutMeta(rawTitle),
};
});

assertUniqueness(
songsMeta.map(({ metaSections }) => metaSections[SongMeta.ID]),
);

const dateAsString = getTodayAsDateString();
const updatedSongsInventory = songsMeta.map(({ filename, metaSections }) => {
const id = metaSections[SongMeta.ID];
const contentHash = metaSections[SongMeta.CONTENT_HASH];
const currentInventory = songsAsHashMap[id];

if (!currentInventory) {
return {
id,
filename,
changes: [
{
date: dateAsString,
contentHash,
},
],
} as SongsInventoryEntry;
}

const { changes } = currentInventory;
const {
filename: lastChangeFilename,
contentHash: lastChangedContentHash,
date: lastChangedDate,
} = last(changes) as SongInventoryChange;

if (isEqual(lastChangedContentHash, contentHash)) {
return currentInventory;
}

const isFilenameChanged = !isEqual(lastChangeFilename, filename);
return {
id,
filename,
changes: [
...(isEqual(lastChangedDate, dateAsString)
? reject(changes, { date: lastChangedDate })
: changes),
{
date: dateAsString,
contentHash,
...(isFilenameChanged ? { filename, isFilenameChanged } : {}),
},
],
} as SongsInventoryEntry;
});

assertUniqueness(Object.keys(updatedSongsInventory).map((id) => id));

const nextSongs = updatedSongsInventory.sort((a, b) =>
a.filename.localeCompare(b.filename),
);
fs.writeFileSync(
inventoryChangelogFilename,
JSON.stringify(
isEqual(songs, nextSongs)
? currentInventory
: {
updatedOn: dateAsString,
songs: nextSongs,
},
),
);
};
19 changes: 19 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,22 @@ export type Song = {
verses: Section[];
version?: string;
};

export type SongInventoryChange = {
date: string;
contentHash: string;
filename: string;
isFilenameChanged?: boolean;
isDeleted?: boolean;
};

export type SongsInventoryEntry = {
id: string;
filename: string;
changes: SongInventoryChange[];
};

export type SongsInventory = {
updatedOn: string;
songs: SongsInventoryEntry[];
};

0 comments on commit fe27a56

Please sign in to comment.