-
-
Notifications
You must be signed in to change notification settings - Fork 0
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
Refactored core modules and improved application architecture #2
Conversation
…nd enhance error handling - Refactored core modules for better maintainability and scalability - Introduced comprehensive type annotations to improve type safety - Enhanced error handling with more descriptive messages and structured exception management - Updated existing components to align with the new architecture - Improved overall application performance and reliability
WalkthroughA comprehensive refactoring of the project's configuration and initialization processes has been implemented. The changes focus on improving dependency checks, key generation, and system configuration for Git and GPG. A new GitHub Actions workflow for release management has been added, along with semantic release configuration. The project now includes more robust error handling, asynchronous operations, and improved system compatibility, particularly for checking and setting up GPG and Git configurations across different platforms. Changes
Sequence DiagramsequenceDiagram
participant User
participant CLI
participant SystemCheck
participant GitConfig
participant GPGConfig
participant KeyGen
User->>CLI: Start command
CLI->>SystemCheck: Check dependencies
SystemCheck-->>CLI: Dependency status
alt Dependencies OK
CLI->>GPGConfig: Check existing keys
GPGConfig-->>CLI: Key status
alt No existing keys
CLI->>KeyGen: Create PGP key
KeyGen-->>CLI: Key generation result
end
CLI->>GitConfig: Configure Git
GitConfig-->>CLI: Configuration status
CLI->>User: Display result
else Dependencies Missing
CLI->>User: Show error
end
Poem
Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Nitpick comments (9)
src/utils/checkSecretKeys.ts (1)
20-22
: Review error handling for the GPG processThe
error
event on thegpgProcess
is emitted only if the process couldn't be spawned or there was an issue during spawning. It does not capture errors from the GPG command itself. Consider handling errors fromstderr
to catch issues reported by GPG.You can listen to
gpgProcess.stderr
to capture error messages from GPG:gpgProcess.on('error', () => { resolve(GitKeyKitCodes.ERR_NO_SECRET_KEYS); }); + gpgProcess.stderr.on('data', (data: Buffer) => { + const errorOutput = data.toString(); + // Handle specific GPG error messages if necessary + });src/commands/start.ts (2)
7-7
: Remove commented-out import statementThe import of
chalk
is commented out. If it's not needed, consider removing it to keep the code clean.Apply this diff to remove the unused import:
-// import chalk from 'chalk';
54-56
: Include stack trace in error logging for better debuggingWhen logging unexpected errors, including the stack trace can aid in diagnosing issues more effectively.
Apply this diff to enhance error logging:
if (error instanceof Error) { - logger.error(`Unexpected error: ${error.message}`); + logger.error(`Unexpected error: ${error.stack || error.message}`); }src/utils/linuxConfig.ts (2)
12-20
: SimplifycreateDirectory
function by removing unnecessary error handlingUsing
mkdir
with{ recursive: true }
will not throw an error if the directory already exists. The catch block checking for'EEXIST'
can be removed to simplify the code.Apply this diff to simplify the function:
async function createDirectory(path: string): Promise<void> { - try { await mkdir(path, { mode: 0o700, recursive: true }); - } catch (error) { - if ((error as { code?: string }).code !== "EEXIST") { - throw error; - } - } }
84-84
: Improve error logging in the catch blockDirectly logging
error
may not provide meaningful information. Castingerror
toError
and logging the message can offer clearer insights.Apply this diff to enhance error logging:
console.error(chalk.red(`Unexpected error: ${error}`)); + console.error(chalk.red(`Unexpected error: ${(error as Error).message}`));
src/utils/checkDependencies.ts (1)
4-7
: Update function documentation to accurately reflect the return typeThe JSDoc comment indicates that the function returns a promise resolving to GPG path or error code. However, the function actually returns an object containing the status code and optionally the GPG path.
Consider updating the comment to match the actual return value:
/** - * Checks all required dependencies - * @returns Promise resolving to GPG path or error code + * Checks all required dependencies. + * @returns {Promise<{ code: GitKeyKitCodes, gpgPath?: string }>} An object containing the status code and optional GPG path. */src/systemCheck.ts (2)
8-11
: Consider handling unsupported platforms explicitlyWhile the commands are correctly defined for Windows and Unix-like systems, consider adding explicit handling for unsupported platforms to prevent runtime errors.
const COMMANDS = { - GPG_CHECK: platform() === 'win32' ? 'where gpg' : 'which gpg', - GIT_CHECK: platform() === 'win32' ? 'where git' : 'which git' + GPG_CHECK: (() => { + switch (platform()) { + case 'win32': return 'where gpg'; + case 'linux': + case 'darwin': return 'which gpg'; + default: throw new Error(`Unsupported platform: ${platform()}`); + } + })(), + GIT_CHECK: (() => { + switch (platform()) { + case 'win32': return 'where git'; + case 'linux': + case 'darwin': return 'which git'; + default: throw new Error(`Unsupported platform: ${platform()}`); + } + })() };
43-50
: Maintain consistency with GPG check implementationFor consistency and robustness, consider applying similar improvements as suggested for the GPG check:
- More specific error handling
- Validation of Git executable
export async function checkGitInstallation(): Promise<GitKeyKitCodes> { try { await execAsync(COMMANDS.GIT_CHECK); + // Verify Git is executable + await execAsync('git --version'); return GitKeyKitCodes.SUCCESS; } catch (error) { + if (error instanceof Error && error.message.includes('not found')) { + return GitKeyKitCodes.ERR_GIT_NOT_FOUND; + } - return GitKeyKitCodes.ERR_GIT_NOT_FOUND; + return GitKeyKitCodes.ERR_GIT_CHECK_FAILED; } }.github/workflows/release.yml (1)
27-27
: Fix YAML formatting issuesAddress the following formatting issues:
- Remove trailing spaces on line 27
- Add a newline at the end of the file
Also applies to: 32-32
🧰 Tools
🪛 yamllint (1.35.1)
[error] 27-27: trailing spaces
(trailing-spaces)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
.github/workflows/release.yml
(1 hunks)bin/index.ts
(1 hunks)package.json
(2 hunks)release.config.cjs
(1 hunks)src/commands/_start.txt
(0 hunks)src/commands/import.ts
(1 hunks)src/commands/reset.ts
(2 hunks)src/commands/start.ts
(1 hunks)src/systemCheck.ts
(1 hunks)src/utils/checkDependencies.ts
(1 hunks)src/utils/checkSecretKeys.ts
(1 hunks)src/utils/configureGPG.ts
(0 hunks)src/utils/createKey.ts
(1 hunks)src/utils/extractKey.ts
(0 hunks)src/utils/generate.ts
(0 hunks)src/utils/linuxConfig.ts
(1 hunks)src/utils/setGitConfig.ts
(1 hunks)
💤 Files with no reviewable changes (4)
- src/commands/_start.txt
- src/utils/extractKey.ts
- src/utils/generate.ts
- src/utils/configureGPG.ts
✅ Files skipped from review due to trivial changes (4)
- src/commands/import.ts
- src/commands/reset.ts
- release.config.cjs
- bin/index.ts
🧰 Additional context used
🪛 yamllint (1.35.1)
.github/workflows/release.yml
[error] 27-27: trailing spaces
(trailing-spaces)
[error] 32-32: no new line character at the end of file
(new-line-at-end-of-file)
🔇 Additional comments (4)
src/commands/start.ts (1)
13-52
: Well-structured initialization with comprehensive error handlingThe
start
function is well-organized, with clear steps for checking dependencies, creating keys, configuring Git, and adding extra configuration for non-Windows platforms. Error handling is appropriately managed at each step, ensuring robust execution.src/utils/linuxConfig.ts (1)
60-65
: Assess the necessity of restarting the GPG agentForcefully killing and restarting the
gpg-agent
may disrupt other processes depending on it. Confirm that this action is necessary and consider notifying the user before proceeding.Alternatively, you might include a check or prompt to ensure that restarting the agent won't adversely affect the user's environment.
src/systemCheck.ts (1)
56-69
: LGTM! Well-structured orchestration functionThe function properly orchestrates the dependency checks in a logical sequence with clear error handling and return values.
package.json (1)
31-32
: LGTM! Proper semantic-release integrationThe semantic-release script and dependency are properly integrated with consistent versioning across the workflow.
Also applies to: 48-48
gpgProcess.stdout.on('data', (data: Buffer) => { | ||
const output = data.toString(); | ||
if (output.includes('sec')) { | ||
foundSecretKey = true; | ||
} | ||
logger.green("Setup finished! Happy coding!"); | ||
} else { | ||
logger.warning("No secret keys found on your system."); | ||
const ok = await confirm({ message: "Do you want to generate GPG keys now?" }); | ||
if (ok) { | ||
await generateGpgKeys(); | ||
await setGitConfig(gpgAgentAddress); | ||
logger.highlight("Before config"); | ||
if (platform === "linux") { | ||
await configureGPG(); | ||
logger.green("Setup finished! Happy coding!"); | ||
process.exit(1); | ||
} | ||
logger.green("Setup finished! Happy coding!"); | ||
process.exit(1); | ||
} else { | ||
process.exit(1); | ||
} | ||
} | ||
} catch (error: any) { | ||
logger.error("Error:", (error as Error).message); | ||
} | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Accumulate stdout data to ensure complete output is processed
Currently, the code checks for 'sec' in each data chunk, which might miss the keyword if it's split across chunks. Consider accumulating the data and processing it after the GPG process has closed to ensure accurate detection.
Apply this diff to adjust the data handling:
let foundSecretKey = false;
+ let output = '';
gpgProcess.stdout.on('data', (data: Buffer) => {
- const output = data.toString();
- if (output.includes('sec')) {
- foundSecretKey = true;
- }
+ output += data.toString();
});
gpgProcess.on('error', () => {
resolve(GitKeyKitCodes.ERR_NO_SECRET_KEYS);
});
gpgProcess.on('close', () => {
- resolve(foundSecretKey ?
+ if (output.includes('sec')) {
+ resolve(GitKeyKitCodes.SUCCESS);
+ } else {
GitKeyKitCodes.ERR_NO_SECRET_KEYS
+ }
});
Committable suggestion skipped: line range outside the PR's diff.
await writeFile(gpgConfPath, ""); | ||
} catch (error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid overwriting existing GPG configuration
The writeFile
call overwrites the existing gpg.conf
, which may erase user's configurations. Instead, remove this step and allow appendToFile
to create the file if it doesn't exist.
Apply this diff to prevent overwriting:
try {
- await writeFile(gpgConfPath, "");
} catch (error) {
console.error(chalk.red("Error: Could not open gpg.conf"));
return GitKeyKitCodes.ERR_INVALID_INPUT;
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
await writeFile(gpgConfPath, ""); | |
} catch (error) { | |
try { | |
} catch (error) { |
|
||
async function setGitConfigValue(key: string, value: string): Promise<void> { | ||
try { | ||
await execAsync(`git config --global ${key} "${value}"`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prevent potential command injection by sanitizing inputs
The value
parameter is directly interpolated into a shell command, which can lead to command injection if value
contains special characters. Consider sanitizing the value
or using a safer method to execute the command.
You can use the execFile
method from the child_process
module, which avoids shell interpolation by accepting arguments as an array.
Apply this diff to refactor the function:
-import { exec } from 'child_process';
+import { execFile } from 'child_process';
-import { promisify } from 'util';
-const execAsync = promisify(exec);
+const execFileAsync = promisify(execFile);
async function setGitConfigValue(key: string, value: string): Promise<void> {
try {
- await execAsync(`git config --global ${key} "${value}"`);
+ await execFileAsync('git', ['config', '--global', key, value]);
} catch (error) {
throw new Error(`Error setting git config ${key}`);
}
}
Committable suggestion skipped: line range outside the PR's diff.
const { stdout } = await execAsync('gpg --list-secret-keys'); | ||
|
||
// Find the longest string that could be a fingerprint | ||
const lines = stdout.split('\n'); | ||
let maxLength = 0; | ||
let keyFingerprint = ''; | ||
|
||
logger.log("Setting up your key"); | ||
const gpgLog: string = execSync("gpg --list-secret-keys").toString(); | ||
const keyID: string | null = extractKey(gpgLog); | ||
for (const line of lines) { | ||
const tokens = line.trim().split(/\s+/); | ||
for (const token of tokens) { | ||
if (token.length > maxLength) { | ||
keyFingerprint = token; | ||
maxLength = token.length; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve the method for extracting GPG key fingerprint
The current method of finding the GPG key fingerprint by selecting the longest token in the output of gpg --list-secret-keys
is not robust and may fail if the output format changes or contains unexpected data. Consider using the --with-colons
option to get machine-readable output and parse it reliably.
You can refactor the function to use gpg --list-secret-keys --with-colons
and parse the 'fpr' (fingerprint) lines to extract the fingerprint.
Apply this diff to improve the function:
async function getGpgKeyFingerprint(): Promise<string> {
try {
- const { stdout } = await execAsync('gpg --list-secret-keys');
+ const { stdout } = await execAsync('gpg --list-secret-keys --with-colons');
- // Find the longest string that could be a fingerprint
- const lines = stdout.split('\n');
- let maxLength = 0;
- let keyFingerprint = '';
- for (const line of lines) {
- const tokens = line.trim().split(/\s+/);
- for (const token of tokens) {
- if (token.length > maxLength) {
- keyFingerprint = token;
- maxLength = token.length;
- }
- }
- }
+ const lines = stdout.split('\n');
+ let keyFingerprint = '';
+ for (const line of lines) {
+ const parts = line.split(':');
+ if (parts[0] === 'fpr') {
+ keyFingerprint = parts[9];
+ break;
+ }
+ }
if (!keyFingerprint) {
throw new Error('No GPG key found');
}
console.log(chalk.green(`Found GPG key: ${keyFingerprint}`));
return keyFingerprint;
} catch (error) {
throw new Error('Failed to get GPG key fingerprint');
}
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const { stdout } = await execAsync('gpg --list-secret-keys'); | |
// Find the longest string that could be a fingerprint | |
const lines = stdout.split('\n'); | |
let maxLength = 0; | |
let keyFingerprint = ''; | |
logger.log("Setting up your key"); | |
const gpgLog: string = execSync("gpg --list-secret-keys").toString(); | |
const keyID: string | null = extractKey(gpgLog); | |
for (const line of lines) { | |
const tokens = line.trim().split(/\s+/); | |
for (const token of tokens) { | |
if (token.length > maxLength) { | |
keyFingerprint = token; | |
maxLength = token.length; | |
} | |
} | |
} | |
const { stdout } = await execAsync('gpg --list-secret-keys --with-colons'); | |
const lines = stdout.split('\n'); | |
let keyFingerprint = ''; | |
for (const line of lines) { | |
const parts = line.split(':'); | |
if (parts[0] === 'fpr') { | |
keyFingerprint = parts[9]; | |
break; | |
} | |
} |
const gpg = spawn("gpg", ["--full-generate-key"], { | ||
stdio: "inherit", | ||
}); | ||
|
||
gpg.on("close", (code) => { | ||
if (code === 0) { | ||
console.log(chalk.green("GPG key has been generated successfully.")); | ||
resolve(GitKeyKitCodes.SUCCESS); | ||
} else { | ||
console.error(chalk.red("Error: Failed to generate GPG key.")); | ||
resolve(GitKeyKitCodes.ERR_KEY_GENERATION); | ||
} | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling for the spawned process to cover unexpected errors
Currently, the child process gpg
only handles the 'close' event. If the process fails to start or encounters an error, the 'error' event should be handled to catch these cases and prevent the promise from hanging.
You can add an error handler as follows:
const gpg = spawn("gpg", ["--full-generate-key"], {
stdio: "inherit",
});
+ gpg.on("error", (error) => {
+ console.error(chalk.red(`Failed to start GPG process: ${error.message}`));
+ resolve(GitKeyKitCodes.ERR_KEY_GENERATION);
+ });
gpg.on("close", (code) => {
if (code === 0) {
console.log(chalk.green("GPG key has been generated successfully."));
resolve(GitKeyKitCodes.SUCCESS);
} else {
console.error(chalk.red("Error: Failed to generate GPG key."));
resolve(GitKeyKitCodes.ERR_KEY_GENERATION);
}
});
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const gpg = spawn("gpg", ["--full-generate-key"], { | |
stdio: "inherit", | |
}); | |
gpg.on("close", (code) => { | |
if (code === 0) { | |
console.log(chalk.green("GPG key has been generated successfully.")); | |
resolve(GitKeyKitCodes.SUCCESS); | |
} else { | |
console.error(chalk.red("Error: Failed to generate GPG key.")); | |
resolve(GitKeyKitCodes.ERR_KEY_GENERATION); | |
} | |
}); | |
}); | |
const gpg = spawn("gpg", ["--full-generate-key"], { | |
stdio: "inherit", | |
}); | |
gpg.on("error", (error) => { | |
console.error(chalk.red(`Failed to start GPG process: ${error.message}`)); | |
resolve(GitKeyKitCodes.ERR_KEY_GENERATION); | |
}); | |
gpg.on("close", (code) => { | |
if (code === 0) { | |
console.log(chalk.green("GPG key has been generated successfully.")); | |
resolve(GitKeyKitCodes.SUCCESS); | |
} else { | |
console.error(chalk.red("Error: Failed to generate GPG key.")); | |
resolve(GitKeyKitCodes.ERR_KEY_GENERATION); | |
} | |
}); | |
}); |
export async function checkGpgInstallation(): Promise<{ code: GitKeyKitCodes, path?: string }> { | ||
try { | ||
const { stdout } = await execAsync(COMMANDS.GPG_CHECK); | ||
const gpgPath = stdout.trim(); | ||
|
||
if (gpgPath) { | ||
return { | ||
code: GitKeyKitCodes.SUCCESS, | ||
path: gpgPath | ||
}; | ||
} | ||
|
||
return { | ||
code: GitKeyKitCodes.ERR_GPG_NOT_FOUND | ||
}; | ||
} catch (error) { | ||
return { | ||
code: GitKeyKitCodes.ERR_GPG_NOT_FOUND | ||
}; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance error handling and path validation
The error handling could be more specific and include path validation:
- Distinguish between different types of errors (e.g., command not found vs execution error)
- Validate the GPG path exists and is executable
export async function checkGpgInstallation(): Promise<{ code: GitKeyKitCodes, path?: string }> {
try {
const { stdout } = await execAsync(COMMANDS.GPG_CHECK);
const gpgPath = stdout.trim();
if (gpgPath) {
+ try {
+ // Verify GPG is executable
+ await execAsync(`"${gpgPath}" --version`);
return {
code: GitKeyKitCodes.SUCCESS,
path: gpgPath
};
+ } catch (error) {
+ return {
+ code: GitKeyKitCodes.ERR_GPG_NOT_EXECUTABLE
+ };
+ }
}
return {
code: GitKeyKitCodes.ERR_GPG_NOT_FOUND
};
} catch (error) {
+ if (error instanceof Error && error.message.includes('not found')) {
+ return {
+ code: GitKeyKitCodes.ERR_GPG_NOT_FOUND
+ };
+ }
return {
- code: GitKeyKitCodes.ERR_GPG_NOT_FOUND
+ code: GitKeyKitCodes.ERR_GPG_CHECK_FAILED
};
}
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export async function checkGpgInstallation(): Promise<{ code: GitKeyKitCodes, path?: string }> { | |
try { | |
const { stdout } = await execAsync(COMMANDS.GPG_CHECK); | |
const gpgPath = stdout.trim(); | |
if (gpgPath) { | |
return { | |
code: GitKeyKitCodes.SUCCESS, | |
path: gpgPath | |
}; | |
} | |
return { | |
code: GitKeyKitCodes.ERR_GPG_NOT_FOUND | |
}; | |
} catch (error) { | |
return { | |
code: GitKeyKitCodes.ERR_GPG_NOT_FOUND | |
}; | |
} | |
} | |
export async function checkGpgInstallation(): Promise<{ code: GitKeyKitCodes, path?: string }> { | |
try { | |
const { stdout } = await execAsync(COMMANDS.GPG_CHECK); | |
const gpgPath = stdout.trim(); | |
if (gpgPath) { | |
try { | |
// Verify GPG is executable | |
await execAsync(`"${gpgPath}" --version`); | |
return { | |
code: GitKeyKitCodes.SUCCESS, | |
path: gpgPath | |
}; | |
} catch (error) { | |
return { | |
code: GitKeyKitCodes.ERR_GPG_NOT_EXECUTABLE | |
}; | |
} | |
} | |
return { | |
code: GitKeyKitCodes.ERR_GPG_NOT_FOUND | |
}; | |
} catch (error) { | |
if (error instanceof Error && error.message.includes('not found')) { | |
return { | |
code: GitKeyKitCodes.ERR_GPG_NOT_FOUND | |
}; | |
} | |
return { | |
code: GitKeyKitCodes.ERR_GPG_CHECK_FAILED | |
}; | |
} | |
} |
jobs: | ||
release: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version: 20 | ||
- uses: pnpm/action-setup@v4 | ||
with: | ||
version: latest | ||
- run: pnpm install --frozen-lockfile | ||
- run: pnpm run build | ||
|
||
- name: Release | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | ||
run: npm run semantic-release |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance workflow security and reliability
Consider these improvements to the workflow:
- Add concurrency control to prevent parallel releases
- Pin the semantic-release version
- Add timeout limits
- Consider caching dependencies
+concurrency:
+ group: release-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
release:
runs-on: ubuntu-latest
+ timeout-minutes: 15
steps:
- uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 20
+ cache: 'pnpm'
- uses: pnpm/action-setup@v4
with:
version: latest
- run: pnpm install --frozen-lockfile
- run: pnpm run build
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- run: npm run semantic-release
+ run: npx semantic-release@24.2.1
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
jobs: | |
release: | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-node@v4 | |
with: | |
node-version: 20 | |
- uses: pnpm/action-setup@v4 | |
with: | |
version: latest | |
- run: pnpm install --frozen-lockfile | |
- run: pnpm run build | |
- name: Release | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | |
run: npm run semantic-release | |
concurrency: | |
group: release-${{ github.ref }} | |
cancel-in-progress: true | |
jobs: | |
release: | |
runs-on: ubuntu-latest | |
timeout-minutes: 15 | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- uses: actions/setup-node@v4 | |
with: | |
node-version: 20 | |
cache: 'pnpm' | |
- uses: pnpm/action-setup@v4 | |
with: | |
version: latest | |
- run: pnpm install --frozen-lockfile | |
- run: pnpm run build | |
- name: Release | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | |
run: npx semantic-release@24.2.1 |
🧰 Tools
🪛 yamllint (1.35.1)
[error] 27-27: trailing spaces
(trailing-spaces)
[error] 32-32: no new line character at the end of file
(new-line-at-end-of-file)
🎉 This PR is included in version 2.1.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Summary by CodeRabbit
Release Notes
New Features
Improvements
Dependency Updates
semantic-release
for managing release processesCode Organization