Skip to content

Develop#5

Merged
volta2030 merged 3 commits into
mainfrom
develop
Apr 29, 2026
Merged

Develop#5
volta2030 merged 3 commits into
mainfrom
develop

Conversation

@volta2030
Copy link
Copy Markdown
Owner

This pull request adds comprehensive support for Jenkins post blocks (including always, success, and failure actions) at both the stage and pipeline levels in the Jenkinsfile-to-Bitbucket Pipelines converter. The main changes involve extracting, processing, and emitting these post actions correctly in the generated YAML, ensuring proper handling for both Linux and Windows environments. Additionally, the codebase is refactored to improve modularity and maintainability by moving utility functions to dedicated files.

Jenkins post block handling:

  • Added new logic to extract post actions (always, success, failure) from both stage and pipeline levels, and emit them as after-script steps in the Bitbucket Pipelines YAML. This includes conditional command emission based on the job's exit code and OS-specific syntax. (src/built-in-steps/post.ts, src/converter.ts, [1] [2] [3] [4] [5]
  • Introduced the PostActions interface and related helper functions (extractPostActions, stripPostBlock, emitAfterScript) to modularize and clarify the handling of post blocks. (src/built-in-steps/post.ts, src/built-in-steps/post.tsR1-R87)

Utility and code structure improvements:

  • Moved the getBalancedBlock function (for parsing balanced curly-brace blocks) and its interface to a dedicated utility module to improve code reuse and clarity. (src/built-in-steps/utils.ts, src/converter.ts, [1] [2] [3] [4]
  • Updated the convertStageBody function to better handle quoted shell command extraction, supporting both single and double quotes, and allowing for nested quotes. (src/converter.ts, src/converter.tsL153-R137)

Testing and versioning:

  • Added a new Jenkinsfile example (tests/Jenkinsfile-example4) covering various uses of stage and pipeline-level post blocks for improved test coverage.
  • Bumped the package version to 0.2.4 to reflect the new feature addition. (package.json, package.jsonL3-R3)

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Jenkins post block conversion support to the Jenkinsfile → Bitbucket Pipelines converter, aiming to emit always/success/failure actions as Bitbucket after-script entries and refactoring brace-parsing utilities into a shared module.

Changes:

  • Introduces post-block extraction/stripping/emission helpers (PostActions, extractPostActions, stripPostBlock, emitAfterScript) and wires them into stage conversion.
  • Extracts getBalancedBlock into src/built-in-steps/utils.ts and updates converter usage.
  • Bumps package version and adds a new Jenkinsfile example intended to cover post-block scenarios.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Jenkinsfile-example4 Adds an example Jenkinsfile with stage- and pipeline-level post blocks.
src/built-in-steps/post.ts New helper module to parse Jenkins post blocks and emit Bitbucket after-script YAML lines.
src/built-in-steps/utils.ts New shared getBalancedBlock utility extracted from the converter.
src/plugins/built-in-steps/post.ts Adds a duplicate post helper file (currently with a broken import path).
src/converter.ts Integrates post-block extraction into stage conversion and emits after-script; adds pipeline-level post handling logic.
package.json Bumps version to 0.2.4.
package-lock.json Updates lockfile, but introduces an inconsistent top-level version value.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/converter.ts
Comment on lines +407 to +426
// Convert pipeline-level post into a dedicated "Post" step appended to items.
// always -> script:, success/failure -> after-script: with $BITBUCKET_EXIT_CODE conditions.
const hasPipelinePost =
pipelinePostActions.always.length > 0 ||
pipelinePostActions.success.length > 0 ||
pipelinePostActions.failure.length > 0;
if (hasPipelinePost) {
const postStep: StepItem = {
kind: 'step',
name: 'Post',
commands: pipelinePostActions.always,
activePlugins: new Set(),
postActions: {
always: [],
success: pipelinePostActions.success,
failure: pipelinePostActions.failure,
},
};
items.push(postStep);
logger.log("Pipeline-level post block -> added as 'Post' step");
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pipeline-level post is converted into a final "Post" step appended to items. In Bitbucket Pipelines, if an earlier step fails the pipeline stops and later steps do not run, so Jenkins post { always { ... } } semantics are not preserved (it won't run on failures). Consider emitting pipeline-level post actions as after-script on each generated step (or otherwise documenting/implementing a strategy that guarantees execution even when earlier steps fail).

Suggested change
// Convert pipeline-level post into a dedicated "Post" step appended to items.
// always -> script:, success/failure -> after-script: with $BITBUCKET_EXIT_CODE conditions.
const hasPipelinePost =
pipelinePostActions.always.length > 0 ||
pipelinePostActions.success.length > 0 ||
pipelinePostActions.failure.length > 0;
if (hasPipelinePost) {
const postStep: StepItem = {
kind: 'step',
name: 'Post',
commands: pipelinePostActions.always,
activePlugins: new Set(),
postActions: {
always: [],
success: pipelinePostActions.success,
failure: pipelinePostActions.failure,
},
};
items.push(postStep);
logger.log("Pipeline-level post block -> added as 'Post' step");
// Pipeline-level post cannot be represented only as a final step in Bitbucket Pipelines,
// because later steps do not run after an earlier failure. To preserve failure semantics,
// attach pipeline-level always/failure actions to each generated step's after-script path,
// and keep a final "Post" step only for the success path.
const hasPipelinePost =
pipelinePostActions.always.length > 0 ||
pipelinePostActions.success.length > 0 ||
pipelinePostActions.failure.length > 0;
if (hasPipelinePost) {
const pipelineFailureActions = [
...pipelinePostActions.always,
...pipelinePostActions.failure,
];
if (pipelineFailureActions.length > 0) {
for (const item of items) {
item.postActions.failure = [
...item.postActions.failure,
...pipelineFailureActions,
];
}
logger.log('Pipeline-level post block -> attached always/failure actions to each step after-script');
}
const needsFinalPostStep =
pipelinePostActions.always.length > 0 ||
pipelinePostActions.success.length > 0;
if (needsFinalPostStep) {
const postStep: StepItem = {
kind: 'step',
name: 'Post',
commands: pipelinePostActions.always,
activePlugins: new Set(),
postActions: {
always: [],
success: pipelinePostActions.success,
failure: [],
},
};
items.push(postStep);
logger.log("Pipeline-level post block -> added success-path 'Post' step");
}

Copilot uses AI. Check for mistakes.
Comment thread src/converter.ts
Comment on lines +312 to +314
const postActions = extractPostActions(blockContent, isWindows, convertStageBody);
const bodyForCommands = stripPostBlock(blockContent);
const commands = convertStageBody(bodyForCommands, isWindows);
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Post-action conversion is new behavior but there are no Jest assertions covering the generated YAML (after-script presence, and success/failure conditional emission for both OS modes). The newly added tests/Jenkinsfile-example4 is not referenced from the test suite, so this feature can regress silently. Add/extend tests/converter.test.ts to run convert() on an input containing stage + pipeline post blocks and assert the resulting YAML structure.

Copilot uses AI. Check for mistakes.
Comment thread src/converter.ts
Comment on lines 559 to +563
for (const r of runners) lines.push(` - ${r}`);
}
lines.push(' script:');
emitStepScript(item, ' ');
emitAfterScript(item.postActions, lines, ' ', isWindows);
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emitAfterScript() is only invoked in the non---all output path. With --all, stage/pipeline post actions will be dropped from the emitted YAML. If --all is meant to preserve behavior, add equivalent after-script emission to the merged-step output (or explicitly error/flag when post blocks are present).

Copilot uses AI. Check for mistakes.
@volta2030 volta2030 merged commit de516db into main Apr 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants