Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): add option to preserve ids on specific collections #74

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 53 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,45 +18,43 @@ for targeted updates and clearer oversight of your Directus configurations.
**Table of Contents**

<!-- TOC -->

* [Directus Sync](#directus-sync)
* [Requirements](#requirements)
* [Usage](#usage)
* [Commands](#commands)
* [Pull](#pull)
* [Diff](#diff)
* [Push](#push)
* [Available options](#available-options)
* [CLI and environment variables](#cli-and-environment-variables)
* [Configuration file](#configuration-file)
* [Collections hooks](#collections-hooks)
* [Simple example](#simple-example)
* [Filtering out elements](#filtering-out-elements)
* [Using the Directus client](#using-the-directus-client)
* [Snapshot hooks](#snapshot-hooks)
* [Helpers](#helpers)
* [Untrack](#untrack)
* [Remove permission duplicates](#remove-permission-duplicates)
* [Lifecycle & hooks](#lifecycle--hooks)
* [`Pull` command](#pull-command)
* [`Diff` command](#diff-command)
* [`Push` command](#push-command)
* [Tracked Elements](#tracked-elements)
* [Roles](#roles)
* [Presets](#presets)
* [Dependency: `directus-extension-sync`](#dependency-directus-extension-sync)
* [Installation](#installation)
* [How It Works](#how-it-works)
* [Tagging and Tracking](#tagging-and-tracking)
* [Mapping Table](#mapping-table)
* [Synchronization Process](#synchronization-process)
* [Schema Management](#schema-management)
* [Non-Tracked Elements and Ignored Fields](#non-tracked-elements-and-ignored-fields)
* [Strengths of `directus-sync`](#strengths-of-directus-sync)
* [Directus upgrades](#directus-upgrades)
* [Use Cases](#use-cases)
* [Troubleshooting](#troubleshooting)

* [Requirements](#requirements)
* [Usage](#usage)
* [Commands](#commands)
* [Pull](#pull)
* [Diff](#diff)
* [Push](#push)
* [Available options](#available-options)
* [CLI and environment variables](#cli-and-environment-variables)
* [Configuration file](#configuration-file)
* [Collections hooks](#collections-hooks)
* [Simple example](#simple-example)
* [Filtering out elements](#filtering-out-elements)
* [Using the Directus client](#using-the-directus-client)
* [Snapshot hooks](#snapshot-hooks)
* [Helpers](#helpers)
* [Untrack](#untrack)
* [Remove permission duplicates](#remove-permission-duplicates)
* [Lifecycle & hooks](#lifecycle--hooks)
* [`Pull` command](#pull-command)
* [`Diff` command](#diff-command)
* [`Push` command](#push-command)
* [Tracked Elements](#tracked-elements)
* [Roles](#roles)
* [Presets](#presets)
* [Dependency: `directus-extension-sync`](#dependency-directus-extension-sync)
* [Installation](#installation)
* [How It Works](#how-it-works)
* [Tagging and Tracking](#tagging-and-tracking)
* [Mapping Table](#mapping-table)
* [Synchronization Process](#synchronization-process)
* [Schema Management](#schema-management)
* [Non-Tracked Elements and Ignored Fields](#non-tracked-elements-and-ignored-fields)
* [Strengths of `directus-sync`](#strengths-of-directus-sync)
* [Directus upgrades](#directus-upgrades)
* [Use Cases](#use-cases)
* [Troubleshooting](#troubleshooting)
<!-- TOC -->

## Requirements
Expand Down Expand Up @@ -123,7 +121,7 @@ Options are merged from the following sources, in order of precedence:

These options can be used with any command to configure the operation of `directus-sync`:

- `-c, --config-path <configPath>`
- `-c, --config-path <configPath>`
Change the path to the config file. Default paths are: `./directus-sync.config.js`, `./directus-sync.config.cjs` or
`./directus-sync.config.json`.

Expand All @@ -141,7 +139,7 @@ These options can be used with any command to configure the operation of `direct
- `-e, --directus-email <directusEmail> `
Provide the Directus email. Alternatively, set the `DIRECTUS_ADMIN_EMAIL` environment variable.

- `-p, --directus-password <directusPassword>`
- `-p, --directus-password <directusPassword>`
Provide the Directus password. Alternatively, set the `DIRECTUS_ADMIN_PASSWORD` environment variable.

- `--dump-path <dumpPath>`
Expand All @@ -151,17 +149,23 @@ These options can be used with any command to configure the operation of `direct
- `--collections-path <collectionPath>`
Specify the path for the collections dump, relative to the dump path. The default is `"collections"`.

- `-o, --only-collections <onlyCollections>`
- `-o, --only-collections <onlyCollections>`
Comma-separated list of directus collections to include during `pull` `push` or `diff` process.

- `-x, --exclude-collections <excludeCollections>`
Comma-separated list of directus collections to exclude during `pull` `push` or `diff`. Can be used along
with `only-collections`.

- `--preserve-ids <preserveIds>`
Comma-separated list of directus collections to preserve the original ids during the `pull` or `push` process.
Possible collections are: `dashboards`, `operations`, `panels`, `roles` and `translations`.
`flows` and `folders` ids are always preserved.
The value can be `*` or `all` to preserve ids of all collections, when applicable.

- `--snapshot-path <snapshotPath>`
Specify the path for the schema snapshot dump, relative to the dump path. The default is `"snapshot"`.

- `--no-snapshot`
- `--no-snapshot`
Do not pull and push the Directus schema. By default, the schema is pulled and pushed.

- `--no-split`
Expand Down Expand Up @@ -205,6 +209,7 @@ module.exports = {
collectionsPath: 'collections',
onlyCollections: ['roles', 'permissions', 'settings'],
excludeCollections: ['settings'],
preserveIds: ['roles', 'panels'], // can be '*' or 'all' to preserve all ids, or an array of collections
snapshotPath: 'snapshot',
snapshot: true,
split: true,
Expand Down Expand Up @@ -539,6 +544,12 @@ maintaining the integrity and links between different entities.
> The original IDs of the folders are preserved to maintain the associations with fields of the `file` and `image`
> types.

> [!TIP]
> You can use the `--preserve-ids` option to preserve the original ids of some collections.
> Eligible collections are collections using UUID: `dashboards`, `operations`, `panels`, `roles` and `translations`.
> If you have already used the `pull` command, you may use the `untrack` helper to remove the id tracking of an element
> before using this option.

### Mapping Table

Since it's not possible to add tags directly to entities within Directus, `directus-sync` uses a mapping table that
Expand Down
17 changes: 17 additions & 0 deletions packages/cli/src/lib/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ function commaSeparatedList(value: string) {
return value.split(',').map((v) => v.trim());
}

/**
* Split a comma separated list unless the value is "all" or "*"
*/
function commaSeparatedListOrAll(value: string) {
const v = value.trim();
if (v === '*' || v === 'all') {
return v;
}
return commaSeparatedList(value);
}

export function createProgram() {
const program = createCommand();
// Global options
Expand Down Expand Up @@ -113,6 +124,10 @@ export function createProgram() {
'-o, --only-collections <onlyCollections>',
`comma separated list of collections to include in the process (default to all)`,
).argParser(commaSeparatedList);
const preserveIdsOption = new Option(
'--preserve-ids <preserveIds>',
`comma separated list of collections that preserve their original ids (default to none). Use "*" or "all" to preserve all ids, if applicable.`,
).argParser(commaSeparatedListOrAll);

const snapshotPathOption = new Option(
'--snapshot-path <snapshotPath>',
Expand Down Expand Up @@ -157,6 +172,7 @@ export function createProgram() {
.addOption(collectionsPathOption)
.addOption(excludeCollectionsOption)
.addOption(onlyCollectionsOption)
.addOption(preserveIdsOption)
.addOption(snapshotPathOption)
.addOption(noSnapshotOption)
.addOption(noSplitOption)
Expand Down Expand Up @@ -186,6 +202,7 @@ export function createProgram() {
.addOption(collectionsPathOption)
.addOption(excludeCollectionsOption)
.addOption(onlyCollectionsOption)
.addOption(preserveIdsOption)
.addOption(snapshotPathOption)
.addOption(noSnapshotOption)
.addOption(noSplitOption)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IdMap, IdMapperClient } from './id-mapper-client';
import {
DirectusBaseType,
DirectusCollectionExtraConfig,
DirectusId,
Query,
UpdateItem,
Expand Down Expand Up @@ -28,6 +29,8 @@ export abstract class DirectusCollection<
protected abstract readonly enableUpdate: boolean;
protected abstract readonly enableDelete: boolean;

protected readonly hooks: CollectionHooks;

/**
* If true, the ids of the items will be used as sync ids.
* This allows to restore the same ids as the original table.
Expand All @@ -47,8 +50,12 @@ export abstract class DirectusCollection<
protected readonly dataMapper: DataMapper<DirectusType>,
protected readonly idMapper: IdMapperClient,
protected readonly migrationClient: MigrationClient,
protected readonly hooks: CollectionHooks,
) {}
extraConfig: DirectusCollectionExtraConfig,
) {
this.hooks = extraConfig.hooks;
// Override preserveIds if it is set to true in the extra config
this.preserveIds = extraConfig.preserveIds ? true : this.preserveIds;
}

/**
* Pull data from a table to a JSON file
Expand Down
6 changes: 6 additions & 0 deletions packages/cli/src/lib/services/collections/base/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IdMapperClient } from './id-mapper-client';
import { Query as DirectusQuery, RestCommand } from '@directus/sdk';
import { CollectionHooks } from '../../config';

export type DirectusId = number | string;

Expand Down Expand Up @@ -42,3 +43,8 @@ export type MultipleRestCommand<T> =
| Command<T>
| [...Command<object>[], Command<T>]
| Promise<Command<T> | [...Command<object>[], Command<T>]>;

export interface DirectusCollectionExtraConfig {
hooks: CollectionHooks;
preserveIds?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ export class DashboardsCollection extends DirectusCollection<DirectusDashboard>
dataMapper,
idMapper,
migrationClient,
config.getCollectionHooksConfig(DASHBOARDS_COLLECTION),
{
hooks: config.getCollectionHooksConfig(DASHBOARDS_COLLECTION),
preserveIds: config.shouldPreserveIds(DASHBOARDS_COLLECTION),
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ export class FlowsCollection extends DirectusCollection<DirectusFlow> {
dataMapper,
idMapper,
migrationClient,
config.getCollectionHooksConfig(FLOWS_COLLECTION),
{
hooks: config.getCollectionHooksConfig(FLOWS_COLLECTION),
},
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ export class FoldersCollection extends DirectusCollection<DirectusFolder> {
dataMapper,
idMapper,
migrationClient,
config.getCollectionHooksConfig(FOLDERS_COLLECTION),
{
hooks: config.getCollectionHooksConfig(FOLDERS_COLLECTION),
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ export class OperationsCollection extends DirectusCollection<DirectusOperation>
dataMapper,
idMapper,
migrationClient,
config.getCollectionHooksConfig(OPERATIONS_COLLECTION),
{
hooks: config.getCollectionHooksConfig(OPERATIONS_COLLECTION),
preserveIds: config.shouldPreserveIds(OPERATIONS_COLLECTION),
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ export class PanelsCollection extends DirectusCollection<DirectusPanel> {
dataMapper,
idMapper,
migrationClient,
config.getCollectionHooksConfig(PANELS_COLLECTION),
{
hooks: config.getCollectionHooksConfig(PANELS_COLLECTION),
preserveIds: config.shouldPreserveIds(PANELS_COLLECTION),
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ export class PermissionsCollection extends DirectusCollection<DirectusPermission
dataMapper,
idMapper,
migrationClient,
config.getCollectionHooksConfig(PERMISSIONS_COLLECTION),
{
hooks: config.getCollectionHooksConfig(PERMISSIONS_COLLECTION),
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ export class PresetsCollection extends DirectusCollection<DirectusPreset> {
dataMapper,
idMapper,
migrationClient,
config.getCollectionHooksConfig(PRESETS_COLLECTION),
{
hooks: config.getCollectionHooksConfig(PRESETS_COLLECTION),
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ export class RolesCollection extends DirectusCollection<DirectusRole> {
dataMapper,
idMapper,
migrationClient,
config.getCollectionHooksConfig(ROLES_COLLECTION),
{
hooks: config.getCollectionHooksConfig(ROLES_COLLECTION),
preserveIds: config.shouldPreserveIds(ROLES_COLLECTION),
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ export class SettingsCollection extends DirectusCollection<DirectusSettings> {
dataMapper,
idMapper,
migrationClient,
config.getCollectionHooksConfig(SETTINGS_COLLECTION),
{
hooks: config.getCollectionHooksConfig(SETTINGS_COLLECTION),
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ export class TranslationsCollection extends DirectusCollection<DirectusTranslati
dataMapper,
idMapper,
migrationClient,
config.getCollectionHooksConfig(TRANSLATIONS_COLLECTION),
{
hooks: config.getCollectionHooksConfig(TRANSLATIONS_COLLECTION),
preserveIds: config.shouldPreserveIds(TRANSLATIONS_COLLECTION),
},
);
}
}
11 changes: 11 additions & 0 deletions packages/cli/src/lib/services/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
SnapshotHooks,
OptionName,
Options,
CollectionPreservableIdName,
} from './interfaces';
import Path from 'path';
import { Cacheable } from 'typescript-cacheable';
Expand Down Expand Up @@ -136,6 +137,16 @@ export class ConfigService {
return list.filter((collection) => !exclude.includes(collection));
}

@Cacheable()
shouldPreserveIds(collection: CollectionPreservableIdName) {
const preserveIds = this.requireOptions('preserveIds');
return (
preserveIds === '*' ||
preserveIds === 'all' ||
preserveIds.includes(collection)
);
}

protected getOptions<T extends OptionName>(name: T): Options[T] | undefined {
const options = this.flattenOptions();
return options[name];
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/lib/services/config/default-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const DefaultConfig: Pick<
| 'collectionsPath'
| 'excludeCollections'
| 'onlyCollections'
| 'preserveIds'
| 'snapshotPath'
| 'snapshot'
| 'split'
Expand All @@ -29,6 +30,7 @@ export const DefaultConfig: Pick<
collectionsPath: 'collections',
excludeCollections: [],
onlyCollections: [],
preserveIds: [],
// Snapshot
snapshotPath: 'snapshot',
snapshot: true,
Expand Down
Loading
Loading