Skip to content

Add GitHub Actions for CI/CD automation#163

Merged
clavery merged 19 commits intomainfrom
clavery/github-actions
Feb 19, 2026
Merged

Add GitHub Actions for CI/CD automation#163
clavery merged 19 commits intomainfrom
clavery/github-actions

Conversation

@clavery
Copy link
Collaborator

@clavery clavery commented Feb 18, 2026

Summary

  • Add composite YAML GitHub Actions for automating B2C Commerce operations
  • Foundation actions: setup (install CLI + set env vars), run (execute any command), root action (setup + run in one step)
  • High-level actions: code-deploy, mrt-deploy, job-run, webdav-upload with typed inputs
  • Starter workflow templates for code deploy, MRT deploy, and data import
  • CI workflow (test-actions.yml) with smoke tests and E2E tests gated on e2e-dev environment
  • User guide at docs/guide/ci-cd.md added to VitePress sidebar

Test plan

  • Verify test-actions.yml workflow passes on this PR (setup-latest, setup-nightly, root-action, setup-then-run, help smoke tests)
  • Review action YAML for correct input/output mappings
  • Verify docs build: pnpm run docs:dev and check CI/CD guide page
  • E2E tests run on merge to main against e2e-dev environment

Composite YAML actions for B2C CLI operations: setup, run, code-deploy,
mrt-deploy, job-run, and webdav-upload. Includes starter workflow
templates, CI test workflow, and user guide documentation.
The setup action already sets SFCC_DISABLE_TELEMETRY and NO_COLOR via
$GITHUB_ENV — no need to duplicate at the workflow level.
Only disable telemetry in our own test workflow, not for customers.
Most use cases will derive the code version dynamically rather than
storing it as a static repository variable.
--json now only controls structured result output to stdout. Logs
always use pino-pretty on stderr. A new --jsonl flag (with --json-logs
alias and SFCC_JSON_LOGS env var) is available for users who explicitly
want JSONL log output.

In the run action, stderr is no longer merged into stdout so
human-readable logs stream directly to the GitHub Actions step log.
The setup action now accepts a log-level input that sets SFCC_LOG_LEVEL
for all subsequent steps. Test actions workflow uses trace level for
maximum visibility. Document logging configuration in CI/CD guide and
actions README.
Add practical examples showing how to use fromJSON() to extract fields
from code-deploy, job-run, and code-list results. Remove pino-pretty
implementation detail from logging section.
Lead with direct output reference, only introduce fromJSON() where
it's actually needed (conditional expressions, extracting fields).
Restore echo of captured stdout in the run action so command output
(help text, JSON results) appears in the GitHub Actions step log.
Stderr already streams directly. Update the Using Outputs docs to
show continue-on-error pattern for inspecting failed job results.
Replace buffered capture with tee + temp file so stdout streams to the
step log as the command runs. Long-running commands like code deploy
and job run --wait now show progress immediately instead of buffering
until completion.
New high-level action that handles upload, job execution, waiting, and
cleanup in a single step. Update the workflow template to use it.
Copy link

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

This PR adds comprehensive GitHub Actions for CI/CD automation of B2C Commerce operations. The changes introduce composite YAML actions for common deployment tasks, along with documentation and workflow templates to help users get started quickly.

Changes:

  • Separate --json (structured output) and --jsonl/SFCC_JSON_LOGS (JSON log messages) flags in the CLI to distinguish between command output and logging
  • Foundation actions: setup (CLI installation + environment configuration), run (command execution), and root action (combined setup + run)
  • High-level actions: code-deploy, mrt-deploy, job-run, data-import, and webdav-upload with typed inputs
  • Comprehensive CI/CD guide documentation with examples and patterns
  • Workflow templates for common deployment scenarios
  • Test workflow with smoke tests and E2E tests

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
packages/b2c-tooling-sdk/src/logging/index.ts Updated example to use SFCC_JSON_LOGS instead of CI env var
packages/b2c-tooling-sdk/src/cli/base-command.ts Added separate --jsonl flag for JSON log output, distinct from --json for structured results
docs/guide/ci-cd.md Comprehensive guide for using GitHub Actions with examples, patterns, and configuration details
docs/.vitepress/config.mts Added CI/CD guide to documentation sidebar
actions/workflow-templates/*.yml Starter workflow templates for code deploy, MRT deploy, and data import
actions/setup/action.yml Foundation action to install CLI and configure environment variables
actions/run/action.yml Foundation action to execute CLI commands with JSON output capture
action.yml Root action combining setup and run in one step
actions/code-deploy/action.yml High-level action for deploying cartridges with typed inputs
actions/mrt-deploy/action.yml High-level action for MRT bundle deployment
actions/job-run/action.yml High-level action for executing B2C jobs
actions/data-import/action.yml High-level action for site archive import
actions/webdav-upload/action.yml High-level action for WebDAV file uploads
actions/README.md Quick reference guide for all actions
.github/workflows/test-actions.yml CI workflow with smoke tests and E2E tests
.changeset/github-actions.md Changeset for minor version bump

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

CMD="job run ${{ inputs.job-id }}"

if [ "${{ inputs.wait }}" = "true" ]; then
CMD="$CMD --wait --timeout ${{ inputs.timeout }}"
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The timeout input should be properly quoted to prevent command injection. Consider: CMD="$CMD --wait --timeout \"${{ inputs.timeout }}\""

Suggested change
CMD="$CMD --wait --timeout ${{ inputs.timeout }}"
CMD="$CMD --wait --timeout \"${{ inputs.timeout }}\""

Copilot uses AI. Check for mistakes.
with:
command: 'webdav put --help'
json: 'false'

Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The test suite only runs help commands for the high-level composite actions (code-deploy, mrt-deploy, job-run, data-import, webdav-upload) but doesn't actually test using these actions themselves. Consider adding test cases that use these composite actions with mock credentials to verify they correctly call the setup and run actions with properly constructed commands.

Suggested change
code-deploy-composite:
name: 'Code Deploy (composite)'
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Use code-deploy composite with mock credentials
uses: ./actions/code-deploy
with:
client-id: 'mock-client-id'
client-secret: 'mock-client-secret'
server: 'https://mock.example.com'
username: 'mock-username'
password: 'mock-password'
mrt-deploy-composite:
name: 'MRT Deploy (composite)'
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Use mrt-deploy composite with mock credentials
uses: ./actions/mrt-deploy
with:
client-id: 'mock-client-id'
client-secret: 'mock-client-secret'
server: 'https://mock.example.com'
username: 'mock-username'
password: 'mock-password'
job-run-composite:
name: 'Job Run (composite)'
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Use job-run composite with mock credentials
uses: ./actions/job-run
with:
client-id: 'mock-client-id'
client-secret: 'mock-client-secret'
server: 'https://mock.example.com'
username: 'mock-username'
password: 'mock-password'
data-import-composite:
name: 'Data Import (composite)'
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Use data-import composite with mock credentials
uses: ./actions/data-import
with:
client-id: 'mock-client-id'
client-secret: 'mock-client-secret'
server: 'https://mock.example.com'
username: 'mock-username'
password: 'mock-password'
webdav-upload-composite:
name: 'WebDAV Upload (composite)'
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Use webdav-upload composite with mock credentials
uses: ./actions/webdav-upload
with:
client-id: 'mock-client-id'
client-secret: 'mock-client-secret'
server: 'https://mock.example.com'
username: 'mock-username'
password: 'mock-password'

Copilot uses AI. Check for mistakes.

- name: Install B2C CLI
shell: bash
run: npm install -g @salesforce/b2c-cli@${{ inputs.version }}
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The version input should be properly quoted to prevent command injection. Consider: run: npm install -g "@salesforce/b2c-cli@${{ inputs.version }}"

Suggested change
run: npm install -g @salesforce/b2c-cli@${{ inputs.version }}
run: npm install -g "@salesforce/b2c-cli@${{ inputs.version }}"

Copilot uses AI. Check for mistakes.
IFS=',' read -ra XCARTS <<< "${{ inputs.exclude-cartridges }}"
for cart in "${XCARTS[@]}"; do
cart=$(echo "$cart" | xargs)
CMD="$CMD -x $cart"
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The cartridge names in the exclude loop should be properly quoted to prevent issues with cartridge names containing spaces or special characters. Consider: CMD="$CMD -x \"$cart\""

Suggested change
CMD="$CMD -x $cart"
CMD="$CMD -x \"$cart\""

Copilot uses AI. Check for mistakes.
fi

if [ -n "${{ inputs.code-version }}" ]; then
CMD="$CMD -v ${{ inputs.code-version }}"
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The code-version input should be properly quoted to prevent command injection and handle versions with spaces or special characters. Consider: CMD="$CMD -v \"${{ inputs.code-version }}\""

Suggested change
CMD="$CMD -v ${{ inputs.code-version }}"
CMD="$CMD -v \"${{ inputs.code-version }}\""

Copilot uses AI. Check for mistakes.
id: upload
uses: ./actions/run
with:
command: "webdav put ${{ inputs.local-path }} ${{ inputs.remote-path }} --root ${{ inputs.root }}"
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

All path inputs (local-path, remote-path, root) should be properly quoted to prevent command injection and handle paths with spaces or special characters. Consider: command: "webdav put \"${{ inputs.local-path }}\" \"${{ inputs.remote-path }}\" --root \"${{ inputs.root }}\""

Suggested change
command: "webdav put ${{ inputs.local-path }} ${{ inputs.remote-path }} --root ${{ inputs.root }}"
command: "webdav put \"${{ inputs.local-path }}\" \"${{ inputs.remote-path }}\" --root \"${{ inputs.root }}\""

Copilot uses AI. Check for mistakes.
id: build-cmd
shell: bash
run: |
CMD="code deploy ${{ inputs.cartridge-path }}"
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The cartridge-path input should be properly quoted to prevent command injection and handle paths with spaces or special characters. Consider using double quotes around the variable interpolation: CMD="code deploy \"${{ inputs.cartridge-path }}\""

Suggested change
CMD="code deploy ${{ inputs.cartridge-path }}"
CMD="code deploy \"${{ inputs.cartridge-path }}\""

Copilot uses AI. Check for mistakes.
IFS=',' read -ra CARTS <<< "${{ inputs.cartridges }}"
for cart in "${CARTS[@]}"; do
cart=$(echo "$cart" | xargs)
CMD="$CMD -c $cart"
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The cartridge names in the loop should be properly quoted to prevent issues with cartridge names containing spaces or special characters. Consider: CMD="$CMD -c \"$cart\""

Copilot uses AI. Check for mistakes.
fi

if [ -n "${{ inputs.timeout }}" ]; then
CMD="$CMD --timeout ${{ inputs.timeout }}"
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The timeout input should be properly quoted to prevent command injection. Consider: CMD="$CMD --timeout \"${{ inputs.timeout }}\""

Suggested change
CMD="$CMD --timeout ${{ inputs.timeout }}"
CMD="$CMD --timeout \"${{ inputs.timeout }}\""

Copilot uses AI. Check for mistakes.
server: ${{ vars.SFCC_SERVER }}
username: ${{ secrets.SFCC_USERNAME }}
password: ${{ secrets.SFCC_PASSWORD }}
target: ${{ github.event.inputs.import-file }}
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The target: ${{ github.event.inputs.import-file }} workflow example wires a manual workflow_dispatch input directly into the data-import action, which ultimately builds a shell command string and executes it via the run action. Because import-file is provided at dispatch time, a less-trusted user who can trigger this workflow could inject shell metacharacters (e.g., ;, &&, $()) into the path and cause arbitrary commands to run on the GitHub runner with access to repository secrets. To prevent command injection, ensure that import-file is restricted/validated to safe path patterns (or passed in a way that does not get interpolated into a shell command string), or update the underlying action to avoid constructing and executing shell strings from untrusted input.

Copilot uses AI. Check for mistakes.
Accept a list of plugins (one per line) to install after the CLI.
Cache the oclif data directory (~/.local/share/b2c) alongside npm
so plugin installs are reused across runs.
Copy link
Contributor

@patricksullivansf patricksullivansf left a comment

Choose a reason for hiding this comment

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

interesting approach. i still have much to learn.

@clavery clavery merged commit 87321c0 into main Feb 19, 2026
15 checks passed
@clavery clavery deleted the clavery/github-actions branch February 19, 2026 01:29
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.

3 participants