aberlaas 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -161,24 +161,6 @@ what most free CI tier offer). If you have access to higher end machines, you
161
161
  can update this value by passing the `--cpu-count=X` flag to your `aberlaas ci`
162
162
  call.
163
163
 
164
- ### Auto-Releasing
165
-
166
- As an optional feature, you can have aberlaas automatically release a new
167
- version of your module from the CI environment when relevant.
168
-
169
- The CI will then check all the commits since the last release. If any commit is
170
- a `feat()` it will release a new minor version; it any commit is a `fix()` it
171
- will release a new patch version. For major release, you'll have to do it
172
- manually.
173
-
174
- This option is not enabled by default. If you need it, you need to follow those
175
- steps:
176
-
177
- - Run `aberlaas setup --auto-release`. It will setup the required `ENV` variables
178
- and ssh keys
179
- - Update your `aberlaas ci` script to `aberlaas ci --auto-release`
180
- - Uncomment the `add_ssh_keys` in your `.circleci.yml` file
181
-
182
164
  ## File structure
183
165
 
184
166
  `./lib/configs` contain the default configuration for all the tools. They are
@@ -188,7 +170,7 @@ exported by the package and thus can be `require`d in userland.
188
170
  extends the configuration exported in the previous files. Copying files to
189
171
  userland allows user to change the files if they want to change the behavior.
190
172
 
191
- `.eslintrc.js`, `.stylelintrc.js` and `jest.config.js` are local
173
+ `.eslintrc.js`, `stylelint.config.js` and `vite.config.js` are local
192
174
  configuration files for `aberlaas` itself. They eat their own dog food by
193
175
  referencing the same configs as above.
194
176
 
@@ -1,21 +1,10 @@
1
- import helper from '../../helper.js';
2
1
  import ciInfo from 'ci-info';
3
- import _ from 'golgoth/lodash.js';
4
- import pMap from 'golgoth/pMap.js';
5
- import readJson from 'firost/readJson.js';
6
2
  import run from 'firost/run.js';
3
+ import commandTest from '../test/index.js';
4
+ import commandLint from '../lint/index.js';
7
5
  import consoleInfo from 'firost/consoleInfo.js';
8
- import autoRelease from './autoRelease.js';
9
6
 
10
7
  export default {
11
- /**
12
- * Return the value of an environment variable
13
- * @param {string} key Name of the variable
14
- * @returns {*} Key value
15
- **/
16
- getEnv(key) {
17
- return _.get(process, `env.${key}`);
18
- },
19
8
  /**
20
9
  * Checks if currently running on a CI server
21
10
  * @returns {boolean} True if on a CI server
@@ -23,111 +12,37 @@ export default {
23
12
  isCI() {
24
13
  return ciInfo.isCI;
25
14
  },
26
- /**
27
- * Checks if currently running on CircleCI
28
- * @returns {boolean} True if on CircleCI
29
- **/
30
- isCircleCI() {
31
- return ciInfo.CIRCLE;
32
- },
33
- /**
34
- * Checks if currently on a PR
35
- * @returns {boolean} True if on a PR
36
- **/
37
- isPR() {
38
- return ciInfo.isPR;
39
- },
40
- /**
41
- * Return the name of the originating branch of the PR
42
- * @returns {string} Name of the PR branch
43
- **/
44
- prBranch() {
45
- if (!this.isPR()) {
46
- return false;
47
- }
48
- if (this.isCircleCI()) {
49
- return this.getEnv('CIRCLE_BRANCH');
50
- }
51
- return false;
52
- },
53
- /**
54
- * Returns the list of scripts defined in the package.json
55
- * @returns {Array} List of scripts defined
56
- **/
57
- async availableScripts() {
58
- // Get scripts in package.json
59
- const currentPackage = await readJson(helper.hostPath('package.json'));
60
- return _.chain(currentPackage).get('scripts').keys().value();
61
- },
62
- /**
63
- * Returns a list of available scripts to run
64
- * @returns {Array} List of scripts to run
65
- **/
66
- async scriptsToRun() {
67
- const availableScripts = await this.availableScripts();
68
-
69
- // Get potential scripts to run
70
- const potentialScripts = ['test', 'lint', 'build:prod'];
71
-
72
- return _.intersection(potentialScripts, availableScripts);
73
- },
74
- /**
75
- * Display the current node and yarn versions
76
- **/
77
- async displayVersion() {
78
- const { stdout: nodeVersion } = await this.__run('node --version', {
79
- stdout: false,
80
- });
81
- const { stdout: yarnVersion } = await this.__run('yarn --version', {
82
- stdout: false,
83
- });
84
- this.__consoleInfo(`node ${nodeVersion}, yarn v${yarnVersion}`);
85
- },
86
15
  /**
87
16
  * Run CI scripts and fail the job if any fails
17
+ * Runs lint and test by default, but can be changed with --no-test and
18
+ * --no-lint
88
19
  * @param {object} cliArgs CLI Argument object, as created by minimist
89
20
  * @returns {boolean} True on success, throws on error
90
21
  **/
91
22
  async run(cliArgs = {}) {
92
23
  const args = {
93
- 'auto-release': false,
94
- 'cpu-count': 2,
24
+ test: true,
25
+ lint: true,
95
26
  ...cliArgs,
96
27
  };
97
28
 
98
29
  if (!this.isCI()) {
30
+ this.__consoleInfo('Current system is not a CI, skipping');
99
31
  return true;
100
32
  }
101
33
 
102
- await this.displayVersion();
103
-
104
- const scripts = await this.scriptsToRun();
105
- await pMap(
106
- scripts,
107
- async (scriptName) => {
108
- let command = scriptName;
109
- if (command === 'test') {
110
- command = `test --maxWorkers=${args['cpu-count']}`;
111
- }
112
-
113
- await helper.yarnRun(command);
114
- },
115
- { concurrency: 1 },
116
- );
34
+ if (args.test) {
35
+ await this.__runTest();
36
+ }
117
37
 
118
- // Attempt to release the package if --auto-release is set
119
- if (args['auto-release']) {
120
- await this.autoRelease();
38
+ if (args.lint) {
39
+ await this.__runLint();
121
40
  }
122
41
 
123
42
  return true;
124
43
  },
125
- /**
126
- * Attempt to perform an auto-release
127
- **/
128
- async autoRelease() {
129
- await autoRelease.run();
130
- },
44
+ __runTest: commandTest.run.bind(commandTest),
45
+ __runLint: commandLint.run.bind(commandLint),
131
46
  __run: run,
132
47
  __consoleInfo: consoleInfo,
133
48
  };
@@ -45,6 +45,10 @@ export default {
45
45
  * default rules and overwrite them as they see fit
46
46
  **/
47
47
  async addConfigFiles() {
48
+ // Git
49
+ await this.copyToHost('./templates/_gitignore', './.gitignore');
50
+ await this.copyToHost('./templates/_gitattributes', './.gitattributes');
51
+
48
52
  // Yarn
49
53
  await this.copyToHost('templates/_yarnrc.yml', '.yarnrc.yml');
50
54
 
@@ -53,16 +57,22 @@ export default {
53
57
  await this.copyToHost('templates/_eslintignore.conf', '.eslintignore');
54
58
 
55
59
  // Lint-staged
56
- await this.copyToHost('templates/_lintstagedrc.cjs', '.lintstagedrc.cjs');
60
+ await this.copyToHost(
61
+ 'templates/lintstaged.config.js',
62
+ 'lintstaged.config.js',
63
+ );
57
64
 
58
65
  // Vite
59
66
  await this.copyToHost('templates/vite.config.js', 'vite.config.js');
60
67
 
61
68
  // Prettier
62
- await this.copyToHost('templates/_prettierrc.cjs', '.prettierrc.cjs');
69
+ await this.copyToHost('templates/prettier.config.js', 'prettier.config.js');
63
70
 
64
71
  // Stylelint
65
- await this.copyToHost('templates/_stylelintrc.cjs', '.stylelintrc.cjs');
72
+ await this.copyToHost(
73
+ 'templates/stylelint.config.js',
74
+ 'stylelint.config.js',
75
+ );
66
76
 
67
77
  // Renovate
68
78
  await this.copyToHost(
@@ -252,7 +262,9 @@ export default {
252
262
  await write(nodeConfig.nodeVersion, nvmrcPath);
253
263
 
254
264
  // Download latest yarn version
255
- await this.__run('yarn set version', { stdout: false });
265
+ await this.__run(`yarn set version ${nodeConfig.yarnVersion}`, {
266
+ stdout: false,
267
+ });
256
268
  },
257
269
  /**
258
270
  * Configure git hooks to use scripts/hooks instead of .git/hooks
@@ -274,6 +286,9 @@ export default {
274
286
  async run() {
275
287
  const progress = spinner();
276
288
 
289
+ progress.tick('Configuring Git');
290
+ await this.configureGit();
291
+
277
292
  progress.tick('Pinning node and yarn versions');
278
293
  await this.pinNodeAndYarn();
279
294
  await this.addEngineNodeVersion();
@@ -284,9 +299,6 @@ export default {
284
299
  progress.tick('Adding yarn scripts');
285
300
  await this.addScripts();
286
301
 
287
- progress.tick('Configuring git hooks');
288
- await this.configureGitHooks();
289
-
290
302
  progress.tick('Updating LICENSE');
291
303
  await this.addLicenseFile();
292
304
  await this.addLicenseField();
@@ -36,8 +36,8 @@ export default {
36
36
  // Config
37
37
  const configFile = await helper.configFile(
38
38
  userConfigFile,
39
- '.stylelintrc.cjs',
40
- 'configs/stylelint.cjs',
39
+ 'stylelint.config.js',
40
+ 'configs/stylelint.js',
41
41
  );
42
42
  const config = await helper.import(configFile);
43
43
 
@@ -14,8 +14,8 @@ export async function fix(inputFiles) {
14
14
  // Config file
15
15
  const configFile = await helper.configFile(
16
16
  null,
17
- '.prettierrc.cjs',
18
- 'lib/configs/prettier.cjs',
17
+ 'prettier.config.js',
18
+ 'configs/prettier.js',
19
19
  );
20
20
  const config = await prettier.resolveConfig(configFile);
21
21
 
@@ -21,7 +21,7 @@ export default {
21
21
  * @param {object} cliArgs CLI Argument object, as created by minimist
22
22
  * @returns {boolean} True on success
23
23
  **/
24
- async run(cliArgs) {
24
+ async run(cliArgs = {}) {
25
25
  const allTypesKeys = _.keys(this.linters);
26
26
  const userTypes = _.intersection(_.keys(cliArgs), allTypesKeys);
27
27
  const typesToLint = _.isEmpty(userTypes) ? allTypesKeys : userTypes;
@@ -34,7 +34,7 @@ export default {
34
34
  const configFile = await helper.configFile(
35
35
  userConfigFile,
36
36
  '.eslintrc.cjs',
37
- 'lib/configs/eslint.cjs',
37
+ 'configs/eslint.cjs',
38
38
  );
39
39
 
40
40
  // Run the actual lint
@@ -7,13 +7,14 @@ export default {
7
7
  // Config
8
8
  const configPath = await helper.configFile(
9
9
  cliArgs.config,
10
- '.lintstagedrc.cjs',
11
- 'lib/configs/lintstaged.cjs',
10
+ 'lintstaged.config.js',
11
+ 'configs/lintstaged.js',
12
12
  );
13
+ const config = await helper.import(configPath);
13
14
 
14
15
  try {
15
16
  const result = await lintStaged({
16
- configPath,
17
+ config,
17
18
  });
18
19
  // Linting failed
19
20
  if (!result) {
@@ -1,14 +1,12 @@
1
1
  import github from './github.js';
2
2
  import circleci from './circleci.js';
3
3
  import renovate from './renovate.js';
4
- import autoRelease from './autoRelease/index.js';
5
4
  import _ from 'golgoth/lodash.js';
6
5
 
7
6
  export default {
8
7
  /**
9
8
  * Enable external services.
10
9
  * Will enable CircleCI, GitHub and Renovate by default.
11
- * If --auto-release is passed, will configure CircleCI
12
10
  * @param {object} cliArgs CLI Argument object, as created by minimist
13
11
  **/
14
12
  async run(cliArgs = {}) {
@@ -16,7 +14,6 @@ export default {
16
14
  circleci: true,
17
15
  renovate: true,
18
16
  github: true,
19
- 'auto-release': false,
20
17
  };
21
18
  const cliServices = _.omit(cliArgs, ['_']);
22
19
  const servicesToEnable = {
@@ -33,9 +30,6 @@ export default {
33
30
  if (servicesToEnable.renovate) {
34
31
  await this.renovate();
35
32
  }
36
- if (servicesToEnable['auto-release']) {
37
- await this.autoRelease();
38
- }
39
33
  },
40
34
  /**
41
35
  * Configure GitHub
@@ -55,10 +49,4 @@ export default {
55
49
  async renovate() {
56
50
  await renovate.enable();
57
51
  },
58
- /**
59
- * Enable autoRelease on CircleCI
60
- **/
61
- async autoRelease() {
62
- await autoRelease.enable();
63
- },
64
52
  };
@@ -1,5 +1,6 @@
1
+ import { createVitest } from 'vitest/node';
1
2
  import helper from '../../helper.js';
2
- import run from 'firost/run.js';
3
+ import firostError from 'firost/error.js';
3
4
  import _ from 'golgoth/lodash.js';
4
5
 
5
6
  export default {
@@ -15,69 +16,70 @@ export default {
15
16
  * @param {object} cliArgs CLI Argument object, as created by minimist
16
17
  * @returns {boolean} true on success
17
18
  **/
18
- async run(cliArgs) {
19
- const options = await this.vitestCliOptions(cliArgs);
19
+ async run(cliArgs = {}) {
20
+ const options = await this.vitestOptions(cliArgs);
21
+ const files = _.isEmpty(cliArgs._) ? [helper.hostPath()] : cliArgs._;
22
+
23
+ const vitest = await createVitest('test', options);
24
+
25
+ // Note: vitest sets process.exitCode to 1 if tests fail
26
+ const initialExitCode = process.exitCode;
27
+ await vitest.start(files);
28
+
29
+ if (!options.watch) {
30
+ await vitest.close();
31
+ }
32
+
33
+ if (process.exitCode == 1) {
34
+ process.exitCode = initialExitCode;
35
+ throw firostError('ERROR_TEST', 'Error while testing files');
36
+ }
20
37
 
21
- await run(`yarn run vitest ${options.join(' ')}`, { stdin: true });
22
38
  return true;
23
39
  },
24
40
 
25
41
  /**
26
- * Transform all aberlaas test cli options into suitable vitest CLI options
42
+ * Transform all aberlaas test cli options into suitable vitest options
27
43
  * @param {object} cliArgs CLI Argument object, as created by minimist
28
- * @returns {Array} Array of cli arguments and values
44
+ * @returns {Array} Array of options for vitest
29
45
  **/
30
- async vitestCliOptions(cliArgs = {}) {
46
+ async vitestOptions(cliArgs = {}) {
31
47
  // Options that have special meaning in aberlaas and shouldn't be passed
32
48
  // as-is to vitest
33
- const aberlaasOptions = ['_', 'watch', 'config', 'failFast', 'related'];
49
+ const specialMeaningCliArgs = ['_', 'config', 'failFast', 'related'];
34
50
 
35
- // Input files
36
- const inputFiles = _.isEmpty(cliArgs._) ? [helper.hostPath()] : cliArgs._;
37
- const vitestOptions = [...inputFiles];
38
-
39
- // Run "vitest related" when --related is passed
40
- if (cliArgs.related) {
41
- vitestOptions.unshift('related');
42
- }
43
-
44
- // Stop early as soon as one test fails
45
- if (cliArgs.failFast) {
46
- vitestOptions.push('--bail=1');
47
- }
48
-
49
- // Disable watch by default
50
- vitestOptions.push(cliArgs.watch ? '--watch=true' : '--watch=false');
51
-
52
- // Allow a success, even if no files are passed
53
- vitestOptions.push('--passWithNoTests');
54
-
55
- // Hide skipped tests, allowing less noisy debug with fit/fdescribe
56
- vitestOptions.push('--hideSkippedTests');
57
-
58
- // Config file
51
+ // Reading base options from the config file
59
52
  const configFile = await helper.configFile(
60
53
  cliArgs.config,
61
54
  'vite.config.js',
62
- 'lib/configs/vite.js',
55
+ 'configs/vite.js',
63
56
  );
64
- vitestOptions.push(`--config=${configFile}`);
57
+ const optionsFromConfig = (await helper.import(configFile)).test;
65
58
 
66
- // Pass any unknown options to vitest
67
- _.each(cliArgs, (argValue, argKey) => {
68
- // Skip keys that we already handled
69
- if (_.includes(aberlaasOptions, argKey)) {
70
- return;
71
- }
72
-
73
- if (argValue === true) {
74
- vitestOptions.push(`--${argKey}`);
75
- return;
76
- }
59
+ // Enhancing options with custom CLI arguments
60
+ const optionsFromAberlaas = {
61
+ // We always allow fit/fdescribe, even in CI. Those errors will be caught
62
+ // by the lint command instead
63
+ allowOnly: true,
64
+ };
65
+ // --failFast stops early as soon as one test fails
66
+ if (cliArgs.failFast) {
67
+ optionsFromAberlaas.bail = 1;
68
+ }
69
+ // --related runs also related files
70
+ // Note (2024-01-19): The related option is not documented, but should
71
+ // contain the list of files
72
+ if (cliArgs.related) {
73
+ optionsFromAberlaas.related = cliArgs._;
74
+ }
77
75
 
78
- vitestOptions.push(`--${argKey}=${argValue}`);
79
- });
76
+ // Passing other CLI options directly to vitest
77
+ const optionsFromCli = _.omit(cliArgs, specialMeaningCliArgs);
80
78
 
81
- return vitestOptions;
79
+ return {
80
+ ...optionsFromConfig,
81
+ ...optionsFromAberlaas,
82
+ ...optionsFromCli,
83
+ };
82
84
  },
83
85
  };
@@ -1,3 +1,5 @@
1
+ // Note: ESLint doesn't support ESM configuration as of 2024-02-19. This file
2
+ // needs to stay as a CommonJS file
1
3
  const nodeConfig = require('./node.cjs');
2
4
  module.exports = {
3
5
  env: {
@@ -0,0 +1,25 @@
1
+ const readmeCommands = [
2
+ 'yarn run aberlaas readme',
3
+ 'git add ./README.md ./lib/README.md',
4
+ ];
5
+
6
+ export default {
7
+ // Lint
8
+ '*.css': ['yarn run lint:fix --css'],
9
+ '*.{yml,yaml}': ['yarn run lint:fix --yml'],
10
+ '.circleci/config.yml': ['yarn run lint --circleci'],
11
+ '*.json': ['yarn run lint:fix --json'],
12
+ '*.js': ['yarn run lint:fix --js'],
13
+
14
+ // Test
15
+ './lib/**/*.js': ['yarn run test --failFast --related'],
16
+
17
+ // Compress
18
+ '*.png': ['yarn run compress --png'],
19
+
20
+ // Documentation
21
+ // Update the README whenever the documentation, or the README template
22
+ // changes
23
+ 'docs/src/**/*.md': readmeCommands,
24
+ '.github/README.template.md': readmeCommands,
25
+ };
package/configs/node.cjs CHANGED
@@ -2,4 +2,5 @@
2
2
  // which we also have to keep in cjs format
3
3
  module.exports = {
4
4
  nodeVersion: '18.18.0', // Also see templates/_circleci/config.yml
5
+ yarnVersion: '4.0.2',
5
6
  };
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  singleQuote: true,
3
3
  printWidth: 80,
4
4
  };
@@ -1,6 +1,6 @@
1
1
  // Initially exported from
2
2
  // https://github.com/stylelint/stylelint-config-recommended/blob/master/index.js
3
- module.exports = {
3
+ export default {
4
4
  rules: {
5
5
  'at-rule-no-unknown': [
6
6
  true,
package/configs/vite.js CHANGED
@@ -3,8 +3,13 @@ const configDir = new URL('./vite/', import.meta.url).pathname;
3
3
 
4
4
  export default defineConfig({
5
5
  test: {
6
- // Make describe, it, beforeEach and other globally available
7
- globals: true,
6
+ // vitest default is to run in watch mode, we revert that
7
+ watch: false,
8
+ // Allow a success, even if no files are passed
9
+ passWithNoTests: true,
10
+ // Hide skipped tests, allowing less noisy debug with fit/fdescribe
11
+ hideSkippedTests: true,
12
+
8
13
  // Tests should be in a __tests__ folder next to their code
9
14
  include: ['**/__tests__/**/*.js?(x)'],
10
15
  // We ignore temporary folders from the tests
@@ -13,6 +18,8 @@ export default defineConfig({
13
18
  // Restore mocks after each tests
14
19
  restoreMocks: true,
15
20
 
21
+ // Make describe, it, beforeEach and other globally available
22
+ globals: true,
16
23
  // Run before each test file
17
24
  setupFiles: [
18
25
  `${configDir}/test/setupFiles/dedent.js`,
package/main.js CHANGED
@@ -6,7 +6,6 @@ import commandCi from './commands/ci/index.js';
6
6
  import commandCompress from './commands/compress/index.js';
7
7
  import commandInit from './commands/init/index.js';
8
8
  import commandPrecommit from './commands/precommit/index.js';
9
- import commandRelease from './commands/release/index.js';
10
9
  import commandTest from './commands/test/index.js';
11
10
  import commandLint from './commands/lint/index.js';
12
11
  import commandReadme from './commands/readme/index.js';
@@ -25,7 +24,6 @@ export default {
25
24
  lint: commandLint,
26
25
  precommit: commandPrecommit,
27
26
  readme: commandReadme,
28
- release: commandRelease,
29
27
  setup: commandSetup,
30
28
  test: commandTest,
31
29
  };
package/package.json CHANGED
@@ -2,17 +2,11 @@
2
2
  "name": "aberlaas",
3
3
  "type": "module",
4
4
  "description": "Scaffold your JavaScript projects with tests, lint and release scripts",
5
- "version": "2.2.0",
5
+ "version": "2.3.0",
6
6
  "repository": "pixelastic/aberlaas",
7
7
  "homepage": "https://projects.pixelastic.com/aberlaas/",
8
8
  "author": "Tim Carry (@pixelastic)",
9
9
  "license": "MIT",
10
- "exports": {
11
- ".": "./main.js",
12
- "./configs/lintstaged.cjs": "./configs/lintstaged.cjs",
13
- "./configs/prettier.cjs": "./configs/prettier.cjs",
14
- "./configs/styleling.cjs": "./configs/styleling.cjs"
15
- },
16
10
  "files": [
17
11
  "bin/",
18
12
  "lib/",
@@ -27,18 +21,23 @@
27
21
  "commands/readme/*.js",
28
22
  "commands/release/*.js",
29
23
  "commands/setup/*.js",
30
- "commands/setup/autoRelease/*.js",
31
24
  "commands/setup/helpers/*.js",
32
25
  "commands/test/*.js",
33
26
  "configs/",
34
27
  "templates/"
35
28
  ],
29
+ "exports": {
30
+ ".": "./main.js",
31
+ "./configs/lintstaged": "./configs/lintstaged.js",
32
+ "./configs/prettier": "./configs/prettier.js",
33
+ "./configs/stylelint": "./configs/stylelint.js"
34
+ },
36
35
  "bin": "bin/aberlaas.js",
37
36
  "dependencies": {
38
37
  "@octokit/rest": "18.12.0",
39
38
  "ci-info": "3.9.0",
40
39
  "dedent": "1.5.1",
41
- "eslint": "8.54.0",
40
+ "eslint": "8.56.0",
42
41
  "eslint-config-prettier": "9.0.0",
43
42
  "eslint-plugin-import": "2.29.0",
44
43
  "eslint-plugin-jsdoc": "46.9.0",
@@ -76,5 +75,5 @@
76
75
  "test:watch": "../scripts/lib/test-watch",
77
76
  "postinstall": "./scripts/postinstall"
78
77
  },
79
- "gitHead": "bbf9f5024d007deca00abf451ddf879c876d80aa"
78
+ "gitHead": "cca93623a1219558bd311aefde796d75d6790009"
80
79
  }
@@ -20,7 +20,6 @@ jobs:
20
20
  <<: *defaults
21
21
  steps:
22
22
  - checkout
23
- # - add_ssh_keys # Uncomment to enable --autoRelease
24
23
  - *restore_cache
25
24
  - *yarn_install
26
25
  - *save_cache
@@ -1,4 +1,4 @@
1
- # Hidden files (.prettierrc.js, etc) are ignored by default by ESLint
1
+ # Hidden files are ignored by default by ESLint
2
2
  # The following line will unignore them
3
3
  !.*
4
4
 
@@ -7,3 +7,6 @@ node_modules/
7
7
 
8
8
  # .yarn contains the yarn source code, we don't need to lint it
9
9
  .yarn/
10
+
11
+ # Ignore the documentation for now, I haven't migrated it to ESM yet
12
+ docs/
@@ -0,0 +1,3 @@
1
+ # Yarn
2
+ /.yarn/releases/** binary
3
+ /.yarn/plugins/** binary
@@ -0,0 +1,28 @@
1
+ # Hidden files
2
+ .DS_Store
3
+ .envrc
4
+
5
+ # Directories
6
+ build/
7
+ dist/
8
+ node_modules/
9
+ tmp/
10
+
11
+ # Files
12
+ Thumbs.db
13
+ npm-debug.log
14
+ yarn-error.log
15
+ *~
16
+
17
+ # Yarn
18
+ # https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored
19
+ .yarn/*
20
+ !.yarn/patches
21
+ !.yarn/plugins
22
+ !.yarn/releases
23
+ !.yarn/sdks
24
+ !.yarn/versions
25
+
26
+
27
+ # Netlify
28
+ .netlify
@@ -0,0 +1,4 @@
1
+ import config from 'aberlaas/configs/lintstaged';
2
+ export default {
3
+ ...config,
4
+ };
@@ -0,0 +1,4 @@
1
+ import config from 'aberlaas/configs/prettier';
2
+ export default {
3
+ ...config,
4
+ };
@@ -8,4 +8,4 @@
8
8
  # $ git config core.hooksPath scripts/hooks
9
9
  set -e
10
10
 
11
- aberlaas precommit "$@"
11
+ yarn run aberlaas precommit
@@ -0,0 +1,4 @@
1
+ import config from 'aberlaas/configs/stylelint';
2
+ export default {
3
+ ...config,
4
+ };
@@ -1,143 +0,0 @@
1
- import release from '../release/index.js';
2
- import consoleInfo from 'firost/consoleInfo.js';
3
- import _ from 'golgoth/lodash.js';
4
- import run from 'firost/run.js';
5
- import write from 'firost/write.js';
6
- import exists from 'firost/exists.js';
7
- import helper from '../../helper.js';
8
-
9
- export default {
10
- /**
11
- * Run a git command in the repo
12
- *
13
- * @param {string} gitCommand Git command to run
14
- * @returns {string} Command output
15
- */
16
- async gitRun(gitCommand) {
17
- const repoPath = helper.hostPath();
18
- const result = await run(`cd ${repoPath} && ${gitCommand}`, {
19
- shell: true,
20
- stdout: false,
21
- });
22
- return result.stdout;
23
- },
24
- /**
25
- * Set a git config value only if wasn't set before
26
- * @param {string} name Name of the config
27
- * @param {string} value Value of the config
28
- **/
29
- async gitConfigSet(name, value) {
30
- // We test to see if there is already a value. If no, we write it
31
- try {
32
- await this.gitRun(`git config ${name}`);
33
- } catch (err) {
34
- await this.gitRun(`git config ${name} ${value}`);
35
- }
36
- },
37
- /**
38
- * Returns the latest tag of the repo
39
- *
40
- * @returns {string} Latest tag
41
- **/
42
- async gitGetLatestTag() {
43
- const allTags = await this.gitRun('git tag -l --sort=creatordate');
44
- return _.chain(allTags).split('\n').last().value();
45
- },
46
- /**
47
- * Returns an array of all commit description since last release
48
- *
49
- * @returns {Array} List of all commit description
50
- **/
51
- async getCommitsSinceLastRelease() {
52
- const latestTag = await this.gitGetLatestTag();
53
- const range = latestTag ? `${latestTag}..HEAD` : 'HEAD';
54
- const commitList = await this.gitRun(`git log ${range} --format=%B`);
55
- return _.chain(commitList).split('\n').compact().reverse().value();
56
- },
57
- /**
58
- * Determines what version should be released based on the commits since the
59
- * last release
60
- * @returns {string|boolean} False if no release, otherwise minor or patch
61
- **/
62
- async getReleaseVersion() {
63
- const commits = await this.getCommitsSinceLastRelease();
64
- const status = {
65
- isMinor: false,
66
- isPatch: false,
67
- };
68
- _.each(commits, (commit) => {
69
- const isMinor = _.startsWith(commit, 'feat(');
70
- const isPatch = _.startsWith(commit, 'fix(');
71
- status.isMinor = status.isMinor || isMinor;
72
- status.isPatch = status.isPatch || isPatch;
73
- });
74
-
75
- if (status.isMinor) {
76
- return 'minor';
77
- }
78
- if (status.isPatch) {
79
- return 'patch';
80
- }
81
- return false;
82
- },
83
- /**
84
- * Run the auto-release script.
85
- * If there had been any feat() of fix() commits since last release,
86
- * automatically release a new one
87
- **/
88
- async run() {
89
- this.__consoleInfo('Attempt to auto-release...');
90
-
91
- const releaseVersion = await this.getReleaseVersion();
92
- // Don't release if no relevant changes
93
- if (!releaseVersion) {
94
- this.__consoleInfo('No relevant commits since last release.');
95
- return;
96
- }
97
-
98
- this.__consoleInfo(`Releasing a ${releaseVersion} version`);
99
- await this.configureGit();
100
- await this.configureNpm();
101
-
102
- const releaseArguments = {
103
- _: [releaseVersion],
104
- test: false,
105
- };
106
- await this.__releaseRun(releaseArguments);
107
- },
108
- /**
109
- * Set git user name and email
110
- * */
111
- async configureGit() {
112
- const email = this.getEnvVar('GIT_USER_EMAIL');
113
- const name = this.getEnvVar('GIT_USER_NAME');
114
- await this.gitConfigSet('user.email', email);
115
- await this.gitConfigSet('user.name', name);
116
- },
117
- /**
118
- * Write a ~/.npmrc with the token
119
- * @returns {boolean} true on success, false if already a .npmrc
120
- **/
121
- async configureNpm() {
122
- const npmRcPath = '~/.npmrc';
123
- if (await this.__exists(npmRcPath)) {
124
- return false;
125
- }
126
- const token = this.getEnvVar('NPM_TOKEN');
127
- const content = `//registry.npmjs.org/:_authToken=${token}`;
128
- await this.__write(content, npmRcPath);
129
- return true;
130
- },
131
- /**
132
- * Return an ENV var value
133
- * @param {string} key ENV var key
134
- * @returns {string} ENV var value
135
- **/
136
- getEnvVar(key) {
137
- return _.get(process, `env.${key}`);
138
- },
139
- __releaseRun: release.run.bind(release),
140
- __consoleInfo: consoleInfo,
141
- __write: write,
142
- __exists: exists,
143
- };
@@ -1,76 +0,0 @@
1
- import _ from 'golgoth/lodash.js';
2
- import run from 'firost/run.js';
3
- import readJson from 'firost/readJson.js';
4
- import helper from '../../helper.js';
5
-
6
- export default {
7
- /**
8
- * Release the host package.
9
- * @param {object} cliArgs CLI Argument object, as created by minimist
10
- * @returns {boolean} True on success, false otherwise
11
- **/
12
- async run(cliArgs = {}) {
13
- this.fixNpmRegistry();
14
- await this.fetchOrigin();
15
-
16
- const binary = await helper.which('np');
17
- const npOptions = await this.getNpArguments(cliArgs);
18
- const command = `FORCE_COLOR=1 ${binary} ${npOptions}`;
19
- await this.__run(command, {
20
- stdin: true,
21
- shell: true,
22
- });
23
- },
24
- /**
25
- * Returns the CLI options to pass to np
26
- * @param {object} cliArgs CLI Argument object, as created by minimist
27
- * @returns {string} Arguments to pass to np
28
- **/
29
- async getNpArguments(cliArgs = {}) {
30
- const options = [
31
- cliArgs._,
32
- '--no-release-draft',
33
- '--no-2fa',
34
- '--any-branch',
35
- ];
36
- const packageJson = await this.getHostPackageJson();
37
-
38
- // Skip tests if called with --no-test or if no scripts.test entry
39
- const cliTestStatus = _.get(cliArgs, 'test', true);
40
- const cliPackageStatus = _.get(packageJson, 'scripts.test', false);
41
- if (!cliTestStatus || !cliPackageStatus) {
42
- options.push('--no-tests');
43
- }
44
-
45
- // Run in preview mode if --dry-run is set
46
- const isDryRun = _.get(cliArgs, 'dry-run', false);
47
- if (isDryRun) {
48
- options.push('--preview');
49
- }
50
-
51
- return _.chain(options).compact().join(' ').value();
52
- },
53
- /**
54
- * Yarn changes the npm_config_registry value, preventing npm publish to
55
- * actually work. We revert it to its default value for publishing to work
56
- **/
57
- fixNpmRegistry() {
58
- // eslint-disable-next-line camelcase
59
- process.env.npm_config_registry = 'https://registry.npmjs.org/';
60
- },
61
- /**
62
- * Fetches origin information, so np can correctly keep the branch up to date
63
- **/
64
- async fetchOrigin() {
65
- await this.__run('git fetch --all', { stdout: false });
66
- },
67
- /**
68
- * Returns the content of the host package.json
69
- * @returns {object} The content of the host package.json
70
- **/
71
- async getHostPackageJson() {
72
- return await this.__readJson(helper.hostPath('package.json'));
73
- },
74
- __run: run,
75
- __readJson: readJson,
76
- };
@@ -1,56 +0,0 @@
1
- import circleciHelper from '../helpers/circleci.js';
2
- import githubHelper from '../helpers/github.js';
3
- import npmHelper from '../helpers/npm.js';
4
- import consoleInfo from 'firost/consoleInfo.js';
5
- import consoleSuccess from 'firost/consoleSuccess.js';
6
- import pMap from 'golgoth/pMap.js';
7
-
8
- export default {
9
- /**
10
- * Save an ENV variable to CircleCI
11
- * @param {string} name Name of the ENV variable
12
- * @param {string} value Value of the ENV variable
13
- **/
14
- async saveEnvVar(name, value) {
15
- const { username, repo } = await githubHelper.repoData();
16
- try {
17
- await circleciHelper.api(
18
- `project/github/${username}/${repo}/envvar/${name}`,
19
- {
20
- method: 'delete',
21
- },
22
- );
23
- } catch (err) {
24
- // Ignoring the error, it means the ENV var wasn't set in the first place
25
- }
26
- await circleciHelper.api(`project/github/${username}/${repo}/envvar`, {
27
- method: 'post',
28
- json: {
29
- name,
30
- value,
31
- },
32
- });
33
- this.__consoleSuccess(`${name} saved on CircleCI`);
34
- },
35
- /**
36
- * Save ENV Variables to CircleCI
37
- **/
38
- async enable() {
39
- // Vars to save
40
- const npmToken = npmHelper.token();
41
- const gitUserEmail = await githubHelper.config('user.email');
42
- const gitUserName = await githubHelper.config('user.name');
43
- const vars = [
44
- { name: 'NPM_TOKEN', value: npmToken },
45
- { name: 'GIT_USER_EMAIL', value: gitUserEmail },
46
- { name: 'GIT_USER_NAME', value: gitUserName },
47
- ];
48
-
49
- // Saving them in parallel
50
- await pMap(vars, async ({ name, value }) => {
51
- await this.saveEnvVar(name, value);
52
- });
53
- },
54
- __consoleInfo: consoleInfo,
55
- __consoleSuccess: consoleSuccess,
56
- };
@@ -1,59 +0,0 @@
1
- import envVars from './envVars.js';
2
- import privateKey from './privateKey.js';
3
- import publicKey from './publicKey.js';
4
- import sshHelper from '../helpers/ssh.js';
5
- import npmHelper from '../helpers/npm.js';
6
- import githubHelper from '../helpers/github.js';
7
- import circleciHelper from '../helpers/circleci.js';
8
- import _ from 'golgoth/lodash.js';
9
- import consoleError from 'firost/consoleError.js';
10
-
11
- export default {
12
- /**
13
- * Enable autoRelease by configuring CircleCI and GitHub
14
- * @returns {boolean} True if enabled, false otherwise
15
- **/
16
- async enable() {
17
- // Fail early if we're missing the required tokens
18
- const validationErrors = await this.validationErrors();
19
- if (!_.isEmpty(validationErrors)) {
20
- this.__consoleError(
21
- '[autoRelease] Please fix the following errors and try again:',
22
- );
23
- _.each(validationErrors, (error) => {
24
- this.__consoleError(error);
25
- });
26
- return false;
27
- }
28
-
29
- await this.__envVarsEnable();
30
- await this.__privateKeyEnable();
31
- await this.__publicKeyEnable();
32
- },
33
- /**
34
- * Returns an array of error messages for every token/binary missing
35
- * @returns {Array} List of error messages
36
- **/
37
- async validationErrors() {
38
- const validationErrors = [];
39
- if (!circleciHelper.hasToken()) {
40
- validationErrors.push('You need a CIRCLECI_TOKEN');
41
- }
42
- if (!npmHelper.hasToken()) {
43
- validationErrors.push('You need a NPM_TOKEN');
44
- }
45
- if (!githubHelper.hasToken()) {
46
- validationErrors.push('You need a GITHUB_TOKEN');
47
- }
48
- if (!sshHelper.hasBinary()) {
49
- validationErrors.push('You need ssh-keygen available in your $PATH');
50
- }
51
-
52
- return validationErrors;
53
- },
54
- __consoleError: consoleError,
55
- __envVarsEnable: envVars.enable.bind(envVars),
56
- __privateKeyEnable: privateKey.enable.bind(privateKey),
57
- __publicKeyEnable: publicKey.enable.bind(publicKey),
58
- __cache: {},
59
- };
@@ -1,41 +0,0 @@
1
- import circleciHelper from '../helpers/circleci.js';
2
- import githubHelper from '../helpers/github.js';
3
- import sshHelper from '../helpers/ssh.js';
4
- import consoleSuccess from 'firost/consoleSuccess.js';
5
-
6
- export default {
7
- /**
8
- * Save a private SSH key on CircleCI.
9
- * The CircleCI API does not allow checking if a SSH key has been defined,
10
- * so we will need to re-add it each time. But to avoid creating duplicates,
11
- * we will delete any key with the same fingerprint first
12
- **/
13
- async enable() {
14
- const keys = await sshHelper.getKeys();
15
- const privateKey = keys.private;
16
- const privateFingerprint = keys.privateFingerprint;
17
- const { username, repo } = await githubHelper.repoData();
18
- const hostname = 'github.com';
19
-
20
- // Delete it first
21
- await circleciHelper.api(`project/github/${username}/${repo}/ssh-key`, {
22
- method: 'delete',
23
- json: {
24
- fingerprint: privateFingerprint,
25
- hostname,
26
- },
27
- });
28
-
29
- // Then, add it
30
- await circleciHelper.api(`project/github/${username}/${repo}/ssh-key`, {
31
- method: 'post',
32
- json: {
33
- hostname,
34
- private_key: privateKey,
35
- },
36
- });
37
-
38
- this.__consoleSuccess('SSH private key force saved on CircleCI');
39
- },
40
- __consoleSuccess: consoleSuccess,
41
- };
@@ -1,55 +0,0 @@
1
- import githubHelper from '../helpers/github.js';
2
- import sshHelper from '../helpers/ssh.js';
3
- import _ from 'golgoth/lodash.js';
4
- import consoleInfo from 'firost/consoleInfo.js';
5
- import consoleSuccess from 'firost/consoleSuccess.js';
6
- import consoleError from 'firost/consoleError.js';
7
-
8
- export default {
9
- /**
10
- * Check if SSH public key is already added to GitHub
11
- * @returns {boolean} True if already enabled, false otherwise
12
- **/
13
- async isEnabled() {
14
- const { username: owner, repo } = await githubHelper.repoData();
15
- const keys = await githubHelper.octokit('repos.listDeployKeys', {
16
- owner,
17
- repo,
18
- });
19
- const { public: publicKey } = await sshHelper.getKeys();
20
- // GitHub does not save the email as part of the key, so we shave it off our
21
- // key
22
- const truncatedKey = _.chain(publicKey)
23
- .split(' ')
24
- .slice(0, 2)
25
- .join(' ')
26
- .value();
27
-
28
- const foundKey = _.find(keys, { key: truncatedKey });
29
- return !!foundKey;
30
- },
31
- /**
32
- * Add the SSH public key to GitHub
33
- * @returns {boolean} True on success
34
- **/
35
- async enable() {
36
- if (await this.isEnabled()) {
37
- this.__consoleInfo('SSH public key already saved on GitHub');
38
- return true;
39
- }
40
- const { public: key } = await sshHelper.getKeys();
41
- const { username: owner, repo } = await githubHelper.repoData();
42
- await githubHelper.octokit('repos.createDeployKey', {
43
- owner,
44
- repo,
45
- key,
46
- title: 'aberlaas - Push from CircleCI',
47
- read_only: false,
48
- });
49
- this.__consoleSuccess('SSH public key saved on GitHub');
50
- return true;
51
- },
52
- __consoleInfo: consoleInfo,
53
- __consoleSuccess: consoleSuccess,
54
- __consoleError: consoleError,
55
- };
@@ -1,31 +0,0 @@
1
- const pkg = require(`${process.cwd()}/package.json`);
2
-
3
- // We update the README.md and ./lib/README.md whenever documentation changes
4
- const aberlaasRunCommands = [
5
- 'yarn run aberlaas readme',
6
- 'git add ./README.md ./lib/README.md',
7
- ];
8
- const result = {
9
- '.github/README.template.md': aberlaasRunCommands,
10
- 'docs/src/**/*.md': aberlaasRunCommands,
11
- };
12
-
13
- // Linting and autofixing supported files
14
- if (pkg.scripts && pkg.scripts.lint) {
15
- result['*.css'] = ['yarn run lint:fix --css'];
16
- result['*.{yml,yaml}'] = ['yarn run lint:fix --yml'];
17
- result['.circleci/config.yml'] = ['yarn run lint --circleci'];
18
- result['*.json'] = ['yarn run lint:fix --json'];
19
- result['*.js'] = ['yarn run lint:fix --js'];
20
- }
21
-
22
- // Compressing images
23
- if (pkg.scripts && pkg.scripts.compress) {
24
- result['*.png'] = ['yarn run compress --png'];
25
- }
26
-
27
- // Testing changed js files
28
- if (pkg.scripts && pkg.scripts.test) {
29
- result['./lib/**/*.js'] = ['yarn run test --failFast --related'];
30
- }
31
- module.exports = result;
@@ -1,4 +0,0 @@
1
- const config = require('aberlaas/configs/lintstaged.cjs');
2
- module.exports = {
3
- ...config,
4
- };
@@ -1,4 +0,0 @@
1
- const config = require('aberlaas/configs/prettier.cjs');
2
- module.exports = {
3
- ...config,
4
- };
@@ -1,4 +0,0 @@
1
- const config = require('aberlaas/configs/stylelint.cjs');
2
- module.exports = {
3
- ...config,
4
- };