Husky pre-commit hook finishes after commit - node.js

The following script was written in order to sort JSON files by key on pre-commit hook:
/*
* Will reorder all files in given path.
*/
const sortJson = require("sort-json");
const fs = require("fs");
const chalk = require("chalk");
const log = console.log;
const translationsPath = process.argv.slice(2).join(" ");
function readFiles(dirname) {
try {
return fs.readdirSync(dirname);
} catch (e) {
log(chalk.red(`Failed reading files from path; ${e}`));
}
}
log(
chalk.bgGreen(
`Running json sort pre-commit hook on path: ${translationsPath}`
)
);
const files = readFiles(translationsPath);
files.forEach((file) => {
log(chalk.yellow(`Sorting ${file}...`));
try {
sortJson.overwrite(`${translationsPath}\\${file}`);
log(chalk.green(`Finished sorting ${file}`));
} catch (e) {
log(chalk.red(`Failed sorting file ${file}; ${e}`));
}
});
log(
chalk.bgGreen(
`Finished sorting files`
)
);
I'm attaching the script to my package.json with husky precommit hook:
"scripts": {
"sort-translations": "node ./scripts/husky/json-sort src/assets/translations",
...
},
"husky": {
"hooks": {
"pre-commit": "npm run sort-translations"
}
},
The result is that the commit is finished, and only then the script finishes with the created unstage changes.
The script itself runs synchronously with the Finished sorting files message printed last.
My question is, how can I make it synchronous; first finish running node ./scripts/husky/json-sort src/assets/translations, then git commit.
Thanks!

Thanks to #adelriosantiago comment, I figured it out.
First of all, I started using readdirSync() instead of readdir(). Then I was able to verify (through logging) that the script indeed ends only when the files are edited. Unfortunately that wasn't enough - the hook still ended with uncommitted files.
At this point I realized - it's not about the hook, it's about the git staging! The script ends it time, but the modified changes remain unstaged so they're not commited. So I've added && git add src/assets/translations to pre-commit hook.
Now everything works as desired.

Related

Slash command registers command from wrong folder discord.js14

I'm tired of trying to solve this. First off, here is my deployment code
const { REST, Routes } = require('discord.js');
const fs = require('node:fs');
const { client_id } = require('./config.json')
const commands = [];
// Grab all the command files from the commands directory you created earlier
const commandFiles = fs.readdirSync('./slashCommands').filter(file => file.endsWith('.js'));
// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
for (const file of commandFiles) {
const command = require(`./slashCommands/${file}`);
commands.push(command.data.toJSON());
}
// Construct and prepare an instance of the REST module
const rest = new REST({ version: '10' }).setToken(process.env.TOKEN);
// and deploy your commands!
(async () => {
try {
console.log(`Started refreshing ${commands.length} application (/) commands.`);
// The put method is used to fully refresh all commands in the guild with the current set
const data = await rest.put(
Routes.applicationCommands(client_id),
{ body: commands },
);
console.log(`Successfully reloaded ${data.length} application (/) commands.`);
} catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error);
}
})();
It is supposed to get the command from the "slashCommand" folder. So I run 'node deploy-commands.js' and it works.
The problem is when I do the slash command '/ping', I get this error:
/home/runner/Nocinel/commands/ping.js:8
message.reply('🏓 **Ball is going over the net...**').then(m => { m.edit(`**🏓 Pong!\n:stopwatch: Uptime: ${Math.round(message.client.uptime / 60000)} minutes\n:sparkling_heart: Websocket Heartbeat: ${message.client.ws.ping}ms\n:round_pushpin: Rountrip Latency: ${m.createdTimestamp - message.createdTimestamp}ms**`) });
^
TypeError: m.edit is not a function
at /home/runner/Nocinel/commands/ping.js:8:73
repl process died unexpectedly: exit status 1
Now this error indicates that I am running a command from my "command" folder rather than my "slashCommand" folder. Which doesnt make sense because I explicitly coded it to only get commands from the "slash command folder"
I have restarted, deleted, waited for an hour, and tested it multiple times, it always gives the same disappointing result. I see absolutely nothing wrong with my code.
There is no problem with registring comannd (deploy-comannds.js is only registring comannds not using making them work). Problem have to be in your index.js you have to handle interaction comannds to your folder slashComannds. Registring comannds was sucessfull.
Documentation:
https://discordjs.guide/creating-your-bot/command-handling.html#loading-command-files

Evaluate a Cypress configuration file

In my build scripts I need to evaluate a Cypress configuration file. I'm using the following script:
let appdata = process.env.LOCALAPPDATA;
let version = `11.0.1`;
let src = `${appdata}/Cypress/Cache/${version}/Cypress/resources/app/node_modules/#packages/data-context/src`;
const DataContext = require(`${src}/DataContext.js`).DataContext;
const ProjectConfigManager = require(`${src}/data/ProjectConfigManager.js`).ProjectConfigManager;
(async() => {
const ctx = new DataContext({
schema: null,
schemaCloud: null,
modeOptions: "run",
appApi: {},
localSettingsApi: {},
authApi: {
} ,
configApi: {
},
projectApi: {
} ,
electronApi: {
} ,
browserApi: {
},
})
let configManager = new ProjectConfigManager({
ctx,
configFile: 'C:\\work\\sample\\sample.config.ts',
projectRoot: 'C:\\work\\sample',
handlers: [],
hasCypressEnvFile: false,
eventRegistrar: null/*new EventRegistrar()*/,
onError: (error) => {},
onInitialConfigLoaded: () => {},
onFinalConfigLoaded: () => Promise.resolve(),
refreshLifecycle: () => Promise.resolve(),
})
configManager.configFilePath = "sample.config.ts"
configManager.setTestingType('e2e')
let cfg = await configManager.getConfigFileContents()
console.log(JSON.stringify(cfg));
})();
It works well for Cypress 10 version.
However, Cypress 11 has introduced some changes that break this script. Though I adjusted the paths, I'm still unable to make it work again.
It currently fails with this error:
Error: Cannot find module 'C:\Users\mbolotov\AppData\Local\Cypress\Cache\11.0.1\Cypress\resources\app\node_modules\graphql\index'. Please verify that the package.json has a valid "main" entry
How can I fix this problem (without making changes to the Cypress installation)?
OR
Is there any other way to evaluate a Cypress configuration file (say from the command line) and obtain its values?
The exact usage is unclear to me, but making some assumptions - a nodejs script in the /scripts folder of the project can compile and resolve the config using the Cypress module API.
It would need a test to run, a "null-test" can be generated from inside the script.
Note, the null-test must conform to the spec pattern of the project (below it's the std .cy.js)
const cypress = require('cypress')
const fs = require('fs')
fs.writeFileSync('../cypress/e2e/null-test.cy.js', 'it("", ()=>{})')
cypress.run({
project: '..',
spec: '../cypress/e2e/null-test.cy.js',
quiet: true
}).then(results => {
if (results.status === 'failed') {
console.log(results)
} else {
console.log(results.config.resolved) // output resolved config
}
})
I haven't attempted to duplicate everything you have in your code, as it's using Cypress internals and not publicly documented.
This may be because of Changelog 11.0.0
We have also massively improved our startup performance by shipping a snapshot of our binary instead of the source files.
Looking inside the cache folder for v10.11.0 (${process.env.CYPRESS_CACHE_FOLDER}/10.11.0/Cypress/resources/app), the /node_modules is fully populated and /node_modules/graphql/index.js exists.
But in v11.0.1 /node_modules/graphql is not fully populated.

Never ending shell command with execSync()

I build VS Code extension
I have wrapper in a class like this
public exec(cmd: string): string {
try {
return execSync(cmd, { cwd: this.workspaceRoot }).toString();
}
catch (e) {
return '' + e;
}
}
If in the code I run
let tags = this.exec('git tag --sort=-v:refname')
I do get a list of tags. Actually, all other commands run also correctly like git status, git config and other. But as soon as I run this.
let res = this.exec(`git push origin ${name}`);
It hangs forever. If I pass wrong tag it stops with error, but if I put correct tag, it suspends. I try to console.log('git push origin ${name}') and then copy result and run that command in a terminal, it runs correctly.
What can be the reason of a such behavior?

Does the pre-merge commit hook get executed when I click merge request button in github?

I want to update the package version automatically when I create a pull request from release branch to master and after that I want whenever I merge it, the pre-merge git hook will be executed to launch another script.
pre-merge-commit:
cd my_app
node ./hooks/post-commit-version
RETVAL=$?
if [ $RETVAL -ne 0 ]
then
exit 1
fi
hooks/post-commit-version:
#!/usr/bin/env node
const exec = require('child_process').exec;
const path = require('path');
const moment = require('moment');
const fs = require('fs');
function getBranch(){
return new Promise((resolve, reject) =>{
exec(
"git branch | grep '*'",
function (err, stdout, stderr) {
if(err)reject(err)
const name = stdout.replace('* ','').replace('\n','');
resolve(name)
}
)
});
}
getBranch()
.then((branch) => {
if(branch === 'release') {
const currentDate = moment().format('YY.MM.DD')
var pathToFile = path.join(__dirname, "../package.json");
if (fs.existsSync(pathToFile)) {
const data = fs.readFileSync(pathToFile, 'utf-8')
const content = JSON.parse(data);
content.version = currentDate;
fs.writeFileSync(pathToFile, JSON.stringify(content, null, 2), 'utf8');
exec(`git add ${pathToFile}`, (err, stdout, stderr) => {
if(err) console.log(err)
console.log(stdout)
})
} else {
console.log("Cannot find file : " + pathToFile);
return;
}
}
return;
})
.catch(error => {
console.log(error)
})
When I try this locally, with pre-commit hook and execute the git commands manually, it works successfully and update the repository in github as the one I want it to be. But I'm not sure that git hooks are executed in Github server when I click the merge request button.
The short answer is no.
Hooks are tied to one specific repository and are not transferred by Git operations.1 Any hooks you set up in your repository are not set up in some other repository. So the hook you have in your repository acts in and on your repository, but if you have a second clone elsewhere, it does not act in and on that second clone.
Besides this, GitHub use a different mechanism ("GitHub Actions") and just don't let you put any hooks into their repositories in the first place.
1If your OS provides symbolic links, you can (manually, once per clone) install a symlink as a Git hook, with the symlink pointing to a file in the work-tree for your repository. In this way, you can get a hook that is affected by various operations: since the hook's actual executable code lives in your work-tree, things that affect that file in your work-tree affect the hook.
Similarly, on OSes that don't provide symbolic links, you can (manually, once per clone) install a hook script-or-binary that works by running a script-or-binary out of your work-tree. That is, rather than relying on the OS's symbolic link mechanism to run the file directly from your work-tree, you write a hook whose "run" operation consists of "run file from work-tree and use its exit status as the hook's exit status".

Run ava test.before() just once for all tests

I would like to use test.before() to bootstrap my tests. The setup I have tried does not work:
// bootstrap.js
const test = require('ava')
test.before(t => {
// do this exactly once for all tests
})
module.exports = { test }
// test1.js
const { test } = require('../bootstrap')
test(t => { ... {)
AVA will run the before() function before each test file. I could make a check within the before call to check if it has been called but I'd like to find a cleaner process. I have tried using the require parameter with:
"ava": {
"require": [
"./test/run.js"
]
}
With:
// bootstrap,js
const test = require('ava')
module.exports = { test }
// run.js
const { test } = require('./bootstrap')
test.before(t => { })
// test1.js
const { test } = require('../bootstrap')
test(t => { ... {)
But that just breaks with worker.setRunner is not a function. Not sure what it expects there.
AVA runs each test file in its own process. test.before() should be used to set up fixtures that are used just by the process it's called in.
It sounds like you want to do setup that is reused across your test files / processes. Ideally that's avoided since you can end up creating hard-to-detect dependencies between the execution of different tests.
Still, if this is what you need then I'd suggest using a pretest npm script, which is run automatically when you do npm test.
In your package.json you could run a setup script first...
"scripts": {
"test": "node setup-test-database.js && ava '*.test.js'"
}
Then...
In that setup-test-database.js file, have it do all your bootstrappy needs, and save a test-config.json file with whatever you need to pass to the tests.
In each test you just need to add const config = require('./test-config.json'); and you'll have access to the data you need.

Resources