Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.template
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
STRIPE_API_KEY=
STRIPE_PUBLISHABLE_KEY=
STRIPE_WEBHOOK_SECRET=
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ about: Request a new feature or enhancement

<!-- Thanks for taking the time to recommend a feature! Please fill out the form below -->

## Summary
# Summary

<!-- High level description of what this feature is -->

Expand Down
54 changes: 54 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copilot Instructions for AI Coding Agents

## Project Overview

- This is a template for creating ColdBox modules, following conventions for modular, testable, and maintainable ColdFusion (CFML) code.
- The root directory is the module root. Key files: `ModuleConfig.cfc` (module config), `box.json` (metadata), and `build/Build.cfc` (build logic).
- The `test-harness` app is a full ColdBox app for module testing, with specs in `test-harness/tests/specs`.

## Architecture & Patterns

- Modules are installed into the ColdBox's application `modules` or `modules_app` convention, they can alo be hierarchical.
- Modules are self-contained: all code, config, and tests live under the module root.
- Business logic and public APIs go in the `models/` directory. Only this folder is documented by default via DocBox.
- Build and release automation is handled by CommandBox tasks in `build/`.
- TestBox is used for all testing, with specs organized under `test-harness/tests/specs`.
- Engine support is managed via `server-*.json` files for different CFML engines.

## Developer Workflows

- **Setup:** Run `box task run taskFile=build/SetupTemplate` to initialize a new module from this template.
- **Build:** Use `box task run build/Build.cfc` for building and packaging.
- **Test:** Use `box testbox run bundles=test-harness/tests` (or run the VS Code task `Run TestBox Bundle`).
- **API Docs:** Generated via the build task, only for `models/` by default.
- **CI/CD:** GitHub Actions in `.github/workflows` automate test, build, and deploy. Environment variables (e.g., `FORGEBOX_TOKEN`, `AWS_ACCESS_KEY`) are required for deployment.

## Conventions & Customizations

- Follow Ortus/ColdBox standards for formatting (`.cfformat.json`), linting (`.cflintrc`), and markdown (`.markdownlint.json`).
- Extend or customize build/test logic by editing files in `build/`.
- Add new engine support by copying and editing `server-xx@x.json` files.
- Place all module-specific tests/specs in `test-harness/tests/specs`.
- For ORM-based modules, enable ORM fixtures in the test harness as needed.

## Integration Points

- Modules are loaded into the test harness via `config/ColdBox.cfc` after aspects load.
- External dependencies are managed via `box.json` and ForgeBox, both in the root and the test harness.
- CI/CD integrates with ForgeBox and AWS S3 for publishing and docs if this becomes an Ortus module.

## Examples

- To add a new model: place CFC in `models/`, document with DocBox comments.
- To add a test: create a spec in `test-harness/tests/specs/`.
- To add a build step: edit `build/Build.cfc`.
- To add a new handler: create a CFC in `handlers/` and create an integration test in `test-harness/tests/specs/integration/`.
- To add a new interceptor create them in the `interceptors/` directory and register them in the `ModuleConfig.cfc`.
- To add a new view: create a file in `views/`
- To add a new layout: create a file in `layouts/`

## References

- See `README.md` for full setup, workflow, and learning resources and document the module here but first removing all the boilerplate text.
- See `.github/workflows/` for CI/CD automation details.
- See `build/Build.cfc` and `test-harness/tests/specs/` for build and test patterns.
19 changes: 19 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: 2
updates:
# GitHub Actions - updates uses: statements in workflows
- package-ecosystem: "github-actions"
directory: "/" # Where your .github/workflows/ folder is
schedule:
interval: "monthly"

# Gradle - updates dependencies in build.gradle or build.gradle.kts
- package-ecosystem: "gradle"
directory: "/" # Adjust if build.gradle is in a subfolder
schedule:
interval: "monthly"

# NPM
- package-ecosystem: "npm"
directory: "/" # adjust if needed
schedule:
interval: "monthly"
93 changes: 93 additions & 0 deletions .github/workflows/cron.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: Daily compatibility

on:
schedule:
- cron: "0 7 * * *"
workflow_dispatch:

permissions:
contents: read
issues: write

jobs:
locked-matrix:
uses: ./.github/workflows/tests.yml

dependency-freshness:
name: Dependency freshness / Lucee 7
runs-on: ubuntu-latest
continue-on-error: true
timeout-minutes: 20
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: temurin
java-version: "21"
- uses: ortus-boxlang/setup-boxlang@ff3947fc932eb2e0e2e44fa8e88760aa7ec5b26a # 1.5.0
with:
with-commandbox: true
- name: Resolve current compatible dependencies
run: |
box package set dependencies.stripecfml='*'
box install --force
cd test-harness
box package set dependencies.coldbox='be'
box install --force
- name: Run freshness suite
run: |
box server start serverConfigFile=server-lucee@7.json --noSaveSettings
curl --retry 60 --retry-delay 1 --retry-all-errors --fail 'http://127.0.0.1:60299/?fwreinit=1'
box testbox run runner='http://127.0.0.1:60299/tests/runner.cfm'
- name: Stop server
if: always()
run: box server stop serverConfigFile=server-lucee@7.json || true

scheduled-failure-issue:
name: Maintain persistent compatibility failure issue
needs: locked-matrix
if: ${{ always() && github.event_name == 'schedule' }}
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
ISSUE_TITLE: "[CI] Persistent daily compatibility failure"
steps:
- name: Open one issue after consecutive failures
if: needs.locked-matrix.result == 'failure'
env:
CURRENT_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
previous_conclusion=$(gh api --method GET \
"repos/${GITHUB_REPOSITORY}/actions/workflows/cron.yml/runs" \
-f event=schedule \
-f status=completed \
-f per_page=1 \
--jq '.workflow_runs[0].conclusion // ""')
test "$previous_conclusion" = "failure" || exit 0

existing=$(gh issue list \
--repo "$GITHUB_REPOSITORY" \
--state open \
--search "${ISSUE_TITLE} in:title" \
--json number \
--jq '.[0].number // empty')
test -z "$existing" || exit 0

gh issue create \
--repo "$GITHUB_REPOSITORY" \
--title "$ISSUE_TITLE" \
--body "The required compatibility matrix failed on two consecutive scheduled runs. Latest failure: ${CURRENT_RUN_URL}. Close this issue only after the required matrix is green."

- name: Close the issue after recovery
if: needs.locked-matrix.result == 'success'
run: |
existing=$(gh issue list \
--repo "$GITHUB_REPOSITORY" \
--state open \
--search "${ISSUE_TITLE} in:title" \
--json number \
--jq '.[0].number // empty')
test -n "$existing" || exit 0
gh issue close "$existing" \
--repo "$GITHUB_REPOSITORY" \
--comment "The required daily compatibility matrix recovered in ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}."
56 changes: 56 additions & 0 deletions .github/workflows/live-stripe.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Live Stripe contract

on:
schedule:
- cron: "0 9 * * 2"
workflow_dispatch:
workflow_call:
secrets:
STRIPE_API_KEY:
description: Stripe test-mode secret key
required: true

permissions:
contents: read

jobs:
stripe-test-mode:
name: Checkout, payment, refund, and webhook
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: temurin
java-version: "21"
- uses: ortus-boxlang/setup-boxlang@ff3947fc932eb2e0e2e44fa8e88760aa7ec5b26a # 1.5.0
with:
with-commandbox: true
- run: box run-script install:dependencies
- name: Start reference engine
run: |
box server start serverConfigFile=server-lucee@6.json --noSaveSettings
curl --retry 60 --retry-delay 1 --retry-all-errors --fail 'http://127.0.0.1:60299/?fwreinit=1'
- name: Run secret-bearing contract with scrubbed TestBox output
env:
CBPAYMENTS_LIVE_REQUIRED: "true"
STRIPE_API_KEY: ${{ secrets.STRIPE_API_KEY }}
run: |
mkdir -p test-harness/tests/results
box testbox run \
runner='http://127.0.0.1:60299/tests/runner.cfm' \
bundles='tests.specs.live.StripeLiveSpec' \
outputFile='test-harness/tests/results/live-stripe' \
outputFormats='json,antjunit'
build/secret-scan.sh
- name: Stop reference engine
if: always()
run: box server stop serverConfigFile=server-lucee@6.json || true
- name: Upload scrubbed live-test evidence
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: live-stripe-results
path: test-harness/tests/results
if-no-files-found: warn
72 changes: 50 additions & 22 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
@@ -1,34 +1,62 @@
name: Pull Requests
name: Pull requests

on:
push:
branches-ignore:
- "main"
- "master"
- "development"
- "releases/v*"
pull_request:
branches:
- "releases/v*"
- development

permissions:
checks: write
pull-requests: write
contents: read

concurrency:
group: pr-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
tests:
uses: ./.github/workflows/tests.yml
secrets: inherit

# Format PR
format_check:
name: Checks Source Code Formatting
runs-on: ubuntu-20.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
live-stripe:
name: Required Stripe test-mode contract
if: github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]'
uses: ./.github/workflows/live-stripe.yml
secrets:
STRIPE_API_KEY: ${{ secrets.STRIPE_API_KEY }}

- uses: Ortus-Solutions/commandbox-action@v1.0.2
quality-and-package:
name: Quality and packaged-consumer gate
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Check out exact source
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Java
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: temurin
java-version: "21"
- name: Set up BoxLang and CommandBox
uses: ortus-boxlang/setup-boxlang@ff3947fc932eb2e0e2e44fa8e88760aa7ec5b26a # 1.5.0
with:
with-commandbox: true
- name: Install locked dependencies
run: box run-script install:dependencies
- name: Validate package metadata and formatting
run: |
build/validate-package.sh
box run-script format:check
npx --yes markdownlint-cli@0.45.0 'readme.md' 'changelog.md' 'docs/**/*.md' 'providers/**/*.md'
git diff --check
- name: Build release-shaped artifacts
run: |
box run-script build:module
build/package-provider.sh
- name: Audit and boot the packaged module
run: |
archive=$(find .artifacts/cbpayments -name 'cbpayments-*.zip' ! -name '*-docs-*' -type f | head -1)
provider_archive=$(find .artifacts/cbpayments-monei -name 'cbpayments-monei-*.zip' -type f | head -1)
build/release-dry-run.sh "$archive"
build/package-smoke.sh "$archive" "$provider_archive"
- name: Upload package evidence
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
cmd: run-script format:check
name: cbpayments-pr-artifacts
path: .artifacts
Loading
Loading