Skip to content

AcuOps Architecture

Pipeline Flow

┌─────────────────────────────────────────────────────────────────────┐
│                        GitHub Repository                             │
│                                                                      │
│  Customization/_project/project.xml   ←── Source of truth            │
│  acuops.yaml                          ←── Pipeline configuration     │
│  scripts/                             ←── Deployment tooling         │
└──────────────────────┬──────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│                     GitHub Actions Pipeline                          │
│                                                                      │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐        │
│  │  Build   │──▸│  Backup  │──▸│  Deploy  │   │ Validate │        │
│  │          │   │          │   │          │   │ (PR only)│        │
│  │ validate │   │ download │   │ import   │   │          │        │
│  │ package  │   │ current  │   │ publish  │   │ import   │        │
│  │ .zip     │   │ .zip     │   │ co-pub   │   │ no pub   │        │
│  └──────────┘   └──────────┘   └──────────┘   └──────────┘        │
└──────────────────────┬──────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│                    Acumatica Customization API                       │
│                                                                      │
│  POST /entity/auth/login          ── Session authentication          │
│  POST /CustomizationApi/Import    ── Upload .zip package             │
│  POST /CustomizationApi/publishBegin ── Start compile + publish      │
│  POST /CustomizationApi/publishEnd   ── Poll completion              │
│  POST /CustomizationApi/getProject   ── Download (backup)            │
│  POST /entity/auth/logout         ── Release session                 │
└─────────────────────────────────────────────────────────────────────┘

Component Responsibilities

Build Job

  1. Reads acuops.yaml for project config
  2. Runs validate-project.py (XML structure, C# validation, security scan)
  3. Detects and builds C# extension libraries (.csproj)
  4. Packages Customization/_project/ into timestamped .zip
  5. Uploads .zip as GitHub artifact

Backup Job

  1. Authenticates to Acumatica (login with retry)
  2. Downloads current published package via getProject API
  3. Saves as timestamped .zip artifact (30-day retention)
  4. Skipped for PRs and when backup.enabled: false

Deploy Job

  1. Downloads build artifact
  2. Resolves target environment (production/staging)
  3. Authenticates to Acumatica
  4. Imports package via Import API
  5. Publishes with co-publish projects via publishBegin
  6. Polls publishEnd until complete or timeout
  7. Posts summary to GitHub and optionally Slack

Validate Job (PR only)

  1. Downloads build artifact
  2. Authenticates to staging Acumatica
  3. Imports with isOnlyValidation: true (compile check, no publish)
  4. Reports result as PR check

Script Architecture

scripts/
├── deploy.sh              ── Primary deployer (GitHub Actions)
│   ├── load_config()      ── Read acuops.yaml via yq
│   ├── login()            ── Auth with retry (5 attempts)
│   ├── backup()           ── Optional pre-deploy backup
│   ├── import()           ── Upload base64-encoded .zip
│   ├── publish()          ── publishBegin + poll publishEnd
│   └── cleanup()          ── Logout + temp file removal (trap)
├── deploy.py              ── Python deployer (alternative)
│   └── AcumaticaCustomizationClient
│       ├── login()        ── Session with context manager
│       ├── import_package()
│       ├── publish()      ── With co-publish support
│       └── download_package()
├── backup.sh              ── Standalone backup script
├── restore.sh             ── Rollback from backup
├── validate-project.py    ── 10-check XML + C# validator
├── setup.sh               ── Interactive setup wizard
└── generate-solution-objects.py ── ISV certification CSV

Error Handling

Login Retry

All scripts implement login retry with exponential backoff: - 5 max attempts - Wait: 15s * attempt number (15s, 30s, 45s, 60s, 75s) - Handles API Login Limit (HTTP 500)

Cleanup Trap

Bash scripts register a trap cleanup EXIT handler that: - Logs out of Acumatica (releases session) - Removes temporary files (cookie jar, response files) - Runs even on script failure or interruption

publishEnd Response Handling

The API returns two different response formats: - Plain text: "true" (complete) or "false" (in progress) - JSON: {"isCompleted": true} or {"isFailed": true, "log": "..."}

Both are handled transparently by the deploy scripts.

Configuration Hierarchy

GitHub Variables  >  acuops.yaml  >  CLI arguments  >  Defaults
(highest priority)                                     (lowest)

The Build job reads acuops.yaml and passes values as job outputs. Deploy and Backup jobs receive config through job dependency outputs.

Compatibility

The Customization API is version-independent — the same endpoints work across all Acumatica versions from 2022 R2 onward. No version-specific API paths or behaviors.

Testing focus areas per version: - Auth behavior (session cookie format) - publishEnd response format (both handled) - Import URL casing (case-sensitive in all versions)