{"id":13630277,"url":"https://github.com/atlassian/conartist","last_synced_at":"2025-04-17T13:31:55.122Z","repository":{"id":44177778,"uuid":"102063595","full_name":"atlassian/conartist","owner":"atlassian","description":"Scaffold out and keep all your files in sync over time. Code-shifts for your file system.","archived":false,"fork":false,"pushed_at":"2023-12-15T05:26:15.000Z","size":1333,"stargazers_count":34,"open_issues_count":20,"forks_count":7,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-08T21:38:38.730Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/atlassian.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-09-01T02:08:39.000Z","updated_at":"2023-10-08T11:37:54.000Z","dependencies_parsed_at":"2024-01-14T08:48:11.392Z","dependency_job_id":"12c4a308-3852-4681-adbe-eb62eb6e8af1","html_url":"https://github.com/atlassian/conartist","commit_stats":null,"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atlassian%2Fconartist","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atlassian%2Fconartist/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atlassian%2Fconartist/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atlassian%2Fconartist/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/atlassian","download_url":"https://codeload.github.com/atlassian/conartist/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249344829,"owners_count":21254746,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T22:01:36.888Z","updated_at":"2025-04-17T13:31:54.834Z","avatar_url":"https://github.com/atlassian.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","📦 Legacy \u0026 Inactive Projects"],"sub_categories":[],"readme":"# Conartist\n\n\u003e Scaffold out and keep all your files in sync over time. Code-shifts for your\n\u003e file system.\n\nConartist is a tool that allows you to scaffold out and maintain your project\nconfigurations over time.\n\n- ✋ Keeping separate repos in sync.\n- 📦 Keeping monorepo packages in sync.\n- 🏗 Scaffolding out new projects.\n- 📐 Works well with [`workspaces`](https://github.com/treshugart/jobsite).\n\n## Install\n\n```sh\nnpm i -D conartist\n```\n\nConartist can be configured by any one of the following:\n\n- `conartist` field in the `package.json`\n- `.conartistrc`\n- `.conartistrc.json`\n- `.conartistrc.yaml`\n- `.conartistrc.yml`\n- `.conartistrc.js`\n- `.conartist.config.js`\n\n_If you use a `.js` file, you will be able to have finer-grained control over\nyour configuration. More on this later._\n\n## CLI\n\n```sh\n$ conartist --help\n\n  Description\n    Declarative project scaffolding and synchronisation.\n\n  Usage\n    $ conartist \u003ccommand\u003e [options]\n\n  Available Commands\n    default    Run the default configuration.\n    init       Creates a basic configuration file.\n\n  For more info, run any command with the `--help` flag\n    $ conartist default --help\n    $ conartist init --help\n\n  Options\n    -v, --version    Displays current version\n    -d, --dry        Perform a dry run.\n    -h, --help       Displays this message\n\n```\n\n### Getting started\n\nYou can run:\n\n```sh\n$ conartist init .\n```\n\nIt will output:\n\n```sh\n/path/to/cwd\n  A conartist.config.js\n```\n\nWhich tells you that it added a `conartist.config.js` file to your current\nworking directory.\n\nIf you open the new `conartist.config.js` you should see something like:\n\n```js\nmodule.exports = { files: [] };\n```\n\n### Simple example\n\nIf you put the following in a `package.json`.\n\n```json\n{\n  \"conartist\": {\n    \"files\": {\n      \".gitignore\": \"node_modules\",\n      \".nvmrc\": \"10.16.0\",\n      \".travis.yml\": \"language: node_js\",\n      \"src/index.js\": \"module.exports = {};\"\n    }\n  }\n}\n```\n\nNow run `conartist` on the current working directory:\n\n```sh\n$ conartist .\n/path/to/cwd\n  A .gitignore\n  A .nvmrc\n  A .travis.yml\n  A src/index.js\n```\n\nResulting in the following file structure:\n\n```\n├─ src\n│ └─ index.js\n├─ .gitignore\n├─ .nvmrc\n└─ .travis.yml\n```\n\nThe key from each entry is the file path relative to the `cwd` and the value\nbecomes the file contents.\n\n## Configuration\n\nThe `conartist` configuration is a config `object` or a `function` that returns\na config `object`.\n\n_All options are optional._\n\nA `files` object is the simpler form of configuration when you don't need to\nspecify any other options.\n\n```js\nmodule.exports = {\n  files: {\n    \"src/index.js\": \"module.exports = {};\"\n  }\n};\n```\n\nA `files` array allows you to specify more options.\n\n```js\nmodule.exports = {\n  // The these are merged with each entry in `files` but do not\n  // override them.\n  fileDefaults: {\n    merge: false,\n    overwrite: false,\n    remove: false\n  },\n  files: [\n    {\n      // The name of the file relative to the directory it is run in.\n      // In the `files` object, this is the key.\n      name: \"src/index.js\",\n\n      // The contents of the file. In the `files` object this is the\n      // value.\n      data: \"module.exports = {};\",\n\n      // Whether or not to attempt merging with any existing file if\n      // supported by the data type.\n      merge: false,\n\n      // Whether or not to override the existing file.\n      overwrite: false,\n\n      // Whether or not the file should be removed. This superseces\n      // any other option because the file is deleted.\n      remove: false,\n\n      // The data type to handle the file as. Built-in data types are\n      // listed below. By default this is inferred from the file\n      // extension. If a data type for the file extension cannot be\n      // found, the typeof the value is used. If it still can't find\n      // a data type, it coerces it to a string. To specify your own\n      // data type, use a function.\n      type: \"js\"\n    }\n  ]\n};\n```\n\nIncludes is just an array of configurations that also allow you to use\nmodule-specifier strings for loading external configurations.\n\n```js\nmodule.exports = {\n  // These only act as defaults for `files` in the config in which they\n  // are specified and do not affect anything in `includes`.\n  fileDefaults: {},\n  includes: [\n    [\n      // This is just a standard config as specified for module.exports.\n      {\n        files: [\n          {\n            name: \"src/index.js\",\n            data: \"module.exports = {};\"\n          }\n        ]\n      }\n    ]\n  ]\n};\n```\n\nAs noted above, you can also specify includes using module-specifiers.\n\n```js\nmodule.exports = {\n  includes: [\n    // Loaded via node_modules.\n    \"some-module-config\",\n\n    // Loaded relative to the CWD.\n    \"./path/to/config\",\n\n    // Use this form if your config will be used as an include because\n    // paths are resolved relative to where the config is run from.\n    require(\"some-module-config\"),\n    require(\"./path/to/config\")\n  ]\n};\n```\n\nMaking `includes` just standard configurations means that an include can just be\nany old configuration and they're resolved recursively down the tree. The outer\nconfigurations are applied _after_ the inner configurations, but they do _not_\noverride them, allowing them to be composed.\n\n### Built-in data types\n\nThese types correspond to the `extname` of the `name` option, or can be\nexplicitly specified as a `type`.\n\n- `js` takes `data` as a `string` and formats it using `prettier`.\n  - `overwrite: false` Existing file is preserved.\n  - `overwrite: true` New data overwrites existing file.\n- `jsx` alias for `js`.\n- `json` takes `data` as JSON and stringifies it.\n  - `merge: false, overwrite: false` prefers existing values.\n  - `merge: false, overwrite: true` prefers new values.\n  - `merge: true, overwrite: false` merges values, preferring existing values.\n  - `merge: true, overwrite: true` merge values, preferring new values.\n- `md` takes `data` as a string and formats it using `prettier`.\n  - `overwrite: false` Existing file is preserved.\n  - `overwrite: true` New data overwrites existing file.\n- `mdx` alais for `md`.\n\n## API\n\nAll exported API points are documented below.\n\n### `async bin(opt)` - automated CLI\n\nThe `bin` function automates a lot of the boilerplate in creating a CLI tool.\nIt's intended to jump-start your ability for you to create a Conartist config\nthat can be run by simply typing `npx your-command`. This idea was borrowed from\nhttps://www.npmjs.com/package/travis.yml.\n\nA big bonus of doing things this way is that your consumers don't need\n`conartist` to be installed and serveral commands can work in harmony even if\nthey depend on different versions of `conartist`.\n\nThe available options are:\n\n- `name` the name of your CLI. Defaults to `\"\"`.\n- `description` the description of your CLI. Defaults to `\"\"`.\n- `version` the version of your CLI. Defaults to `\"0.0.0\"`.\n- `conartist` the `conartist` configuration as normally specified in a config\n  file. Defaults to `{}`.\n- `options` custom CLI options. Each key is the option name and each value can\n  either be a `string` and will be the description, or it allows an object that\n  may contain:\n  - `alias` the option alias (i.e. `-a`).\n  - `default` the default value.\n  - `description` the option description.\n  - `question` an\n    [`inquirer` question object](https://github.com/SBoudrias/Inquirer.js/#question).\n- `commands` custom CLI sub-commands. Each key is the command name and each\n  value can either be a `string` and will be the description, or it allows:\n  - `description` the command description.\n  - `options` an object of options as described above for global options.\n\nThe following example creates a `npx license-mit` command.\n\n#### `package.json`\n\n```json\n{\n  \"name\": \"license-mit\",\n  \"description\": \"Creates and maintains an MIT license in your projects.\",\n  \"author\": \"Your Name \u003cyou@yourdomain.com\u003e\",\n  \"version\": \"1.0.0\",\n  \"bin\": \".\"\n}\n```\n\n#### `bin.js`\n\nThe following `bin.js` uses information from your `package.json` to define\nmetadata, and then specifies the `conartist` option to specify the `conartist`\nconfiguration. You could have specified `conartist` in your `package.json`, but\nwe wanted the ability to use template literals, thus opted to specify it as a\nJavaScript object instead.\n\n```js\n#! /usr/bin/env node\n\nconst { bin } = require(\"conartist\");\nconst pkg = require(\"./package.json\");\n\nbin({\n  ...pkg,\n  conartist: {\n    files: {\n      LICENSE: `\n        Copyright 2019 ${pkg.author}\n\n        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n      `\n    }\n  }\n});\n```\n\n#### Resulting `LICENSE`\n\n```\nCopyright 2019 Your Name \u003cyou@yourdomain.com\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n\n#### Testing\n\nYou can now test to see if your command works by running `npx .`:\n\n```sh\n$ npx . .\n/path/to/cwd\n  A LICENSE\n```\n\n#### Customize using CLI arguments\n\nIn the above example, the configuration is specified using an `object`. However,\nyou could also specify a function returning an `object` that gets the following\noptions passed in:\n\n- `cli` the arguments parsed from the CLI. This allows you to add custom options\n  and use them to generate your config.\n- `cmd` the sub-command that was run. Defaults to `\"default\"`.\n- `cwd` the current working directory that the config is running in.\n- `opt` the options that you originally passed in to `bin(opt)`.\n\nIf you wanted to accept a custom `author`, you could set it up as an option and\ndefault it to what's in the `package.json`.\n\n```js\n#! /usr/bin/env node\n\nconst { bin } = require(\"conartist\");\nconst pkg = require(\"./package.json\");\n\nbin({\n  ...pkg,\n  options: {\n    author: {\n      alias: \"a\",\n      default: pkg.author,\n      description: \"The package author.\"\n    }\n  },\n  conartist: ({ cli }) =\u003e ({\n    files: {\n      LICENSE: `\n        Copyright 2019 ${cli.author}\n\n        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n      `\n    }\n  })\n});\n```\n\nNow you can run:\n\n```sh\n$ npx . . -a \"Custom Author\"\n/path/to/cwd\n  A LICENSE\n```\n\n#### Accepting input via prompts\n\nYou could take this a step further and prompt the user for input if an option\nisn't provided. It won't prompt the user for input if a `default` is provided,\nso you must remove the default from the `option`. If you want to provide a\ndefault for the question, then just add it as the `default` for the question, as\nseen below.\n\n```js\n#! /usr/bin/env node\n\nconst { bin } = require(\"conartist\");\nconst pkg = require(\"./package.json\");\n\nbin({\n  ...pkg,\n  options: {\n    author: {\n      alias: \"a\",\n      description: \"The package author.\",\n      question: {\n        default: pkg.author,\n        message: \"What author should we use?\"\n      }\n    }\n  },\n  conartist: ({ cli }) =\u003e ({\n    files: {\n      LICENSE: `\n        Copyright 2019 ${cli.author}\n\n        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n      `\n    }\n  })\n});\n```\n\nNow when you run the command without the `--author` option, it will prompt you\nto fill it in.\n\n```sh\n$ npx . .\n? What author should we use? Your Name \u003cyou@yourdomain.com\u003e\n/path/to/cwd\n  O LICENSE\n```\n\n#### Built-in features\n\nThe `bin` function automates quite a bit for you.\n\nRunning in specific directories:\n\n```sh\n$ npx . path/to/new path/to/existing\nA path/to/new/LICENSE\nU path/to/existing/LICENSE\n```\n\nHelp:\n\n```sh\n$ npx . --help\n\n  Description\n    Creates and maintains an MIT license in your projects.\n\n  Usage\n    $ mit-license \u003ccommand\u003e [options]\n\n  Available Commands\n    default    Run the default configuration.\n\n  For more info, run any command with the `--help` flag\n    $ mit-license default --help\n\n  Options\n    -v, --version    Displays current version\n    -h, --help       Displays this message\n\n```\n\nVersion:\n\n```sh\n$ npx . --version\n1.0.0\n```\n\n#### Publishing and running\n\nYou can now run [`np`](https://github.com/sindresorhus/np) and your command is\nrunnable via `npx license-mit` anywhere.\n\n### `async sync(cfg, opt)` - programmatic config application\n\nThe `sync` function takes a configuration as `cfg`, normalizes it with `opt` and\napplies it to your `cwd`.\n\nThe available options are:\n\n- `cwd` a custom current working directory to apply the configuration to.\n  Defaults to `\".\"`.\n- `dry` perform a dry run (does not modify any files, just outputs what would\n  happen to them).\n- `events` an instance of an `EventEmitter` (use via the built-in module:\n  `require(\"events\")`). Supported events are:\n  - `file, { action, file }` when a file is affected. The `file` argument is the\n    file, relative to the `cwd` and `action` is the action that was taken on the\n    file.\n  - `info, message` when `info` is logged. The `message` argument is the info\n    message.\n  - `warn, message` when `warn` is logged. The `message` is the warning.\n\n```js\nconst { sync } = require(\"conartist\");\n\nsync(\n  {\n    files: {\n      \".travis.yml\": \"language: node_js\"\n    }\n  },\n  {\n    cwd: \"packages/sub-package\"\n  }\n);\n```\n\nJust like with `bin`, if you specify a function as `cfg`, the options you pass\nin are passed to it:\n\n```js\nconst { sync } = require(\"conartist\");\n\nsync(\n  ({ language }) =\u003e ({\n    files: {\n      \".travis.yml\": \"language: node_js\"\n    }\n  }),\n  {\n    language: \"node_js\"\n  }\n);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatlassian%2Fconartist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fatlassian%2Fconartist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatlassian%2Fconartist/lists"}