Enterprise software · J.M. Smucker

Production deployment

BIP-OBTI Automated Deployment

A production workflow that converts Oracle BI Publisher promotions into validated pull requests and approved CI/CD deployments.

Interactive project overview

Explore the system in operation.

These demonstrations present the project's state, timing, and key tradeoffs. The full case study and implementation details follow below.

01

Promotion request workflow

Submit a fictional request, inspect the generated pull request, approve and merge it, then follow the simulated private runner through the Oracle SOAP promotion.

Preparing promotion workflow…

Problem and objectives.

Oracle BI Publisher lacked a direct, governed path for moving report objects between development and production. Each manual promotion required DBA time and could remain blocked for weeks.

The delay discouraged teams from using the feature. The replacement needed to reduce repetitive work while preserving authentication, DBA approval, private configuration, and control of the final production action.

System architecture.

Follow a report object through request validation, Oracle verification, generated metadata, DBA approval, and the private deployment runner.

Interactive architecture

Governed Oracle BI Publisher promotion

The public Next.js proof of concept creates the request and review record. A private runner performs the approved environment move.

Data Approval
REQUESTValidate input and verify the source object before creating repository state.
Validate input and verify the source object before creating repository state.01Authenticated requesterCompany user02Next.js request formReusable UI03Validation APISanitize + strict parse04Oracle objectExistSOAP verification

Selected component

Authenticated requester

The requester supplies promotion metadata and authenticates with their own Oracle BI Publisher account.

Accessible component list

My responsibilities.

The components I designed, implemented, tested, or integrated.

  1. 01

    Designed the request workflow as a reusable Next.js application instead of a one-off operator script.

  2. 02

    Validated and sanitized request data, checked the source object against Oracle BI Publisher, and generated deterministic promotion metadata.

  3. 03

    Used the GitHub API to create a branch, commit the request record, fill a review template, and open a pull request for authorized DBAs.

  4. 04

    Validated recursive catalog discovery and SOAP download/upload operations before integrating them with the private CI runner.

  5. 05

    Stored environment endpoints in GitHub Secrets, required Oracle authentication, and restricted repository review to authorized DBAs.

Key engineering decisions.

The constraints and tradeoffs that shaped the implementation.

01

Use pull requests as the approval object

Constraint. The process needed an auditable review gate that fit the administrators' existing access model.

Decision. Store each promotion as versioned metadata on a dedicated branch and use a protected pull request for DBA review and approval.

02

Verify against the source environment

Constraint. A syntactically valid form does not prove that the requester can authenticate or that the source object exists.

Decision. Verify the source object through Oracle with the requester's account before creating repository state. The portfolio demo shows this boundary without collecting credentials.

03

Keep the production runner private

Constraint. The public proof of concept demonstrates the interface and integration pattern, but production endpoints and promotion internals are company-controlled.

Decision. Publish only the safe UI/API proof of concept and describe the private runner at an architectural level. Production configuration remains in repository secrets.

Development timeline.

Important revisions, technical pivots, and lessons from each stage.

01 / Proof

Proved the Oracle catalog operations

Python scripts established recursive object discovery and the download/upload sequence needed to move a report object between catalog paths.

02 / Interface

Converted operator knowledge into a guided request

A Next.js form made the source, target, request type, and report metadata explicit and reusable across departments.

03 / Governance

Added repository-backed review

The API created branches, YAML metadata, and templated pull requests in a repository accessible only to authorized DBAs.

04 / Production

Connected merge to automated promotion

The private GitHub Actions workflow consumed the approved request and performed the controlled environment-to-environment SOAP deployment.

Results and system metrics.

Measurements, configuration boundaries, and outcomes that show the scope of the work.

Lifecycle

Production

The automated deployment workflow was released for real company use.

Organizational reach

>90%

The workflow made the Oracle capability available to business areas representing more than 90% of the company workforce. This measures organizational reach, not active users.

Previous wait

Weeks+

Manual promotions could take weeks or longer before this workflow addressed the administrative bottleneck.

Governance

PR → merge → runner

Authenticated submission, private DBA review, and protected repository controls guard the production action.

Implementation highlights.

Focused excerpts paired with the engineering behavior each one implements.

01Reject malformed promotion requestssrc/app/api/handle-submit/route.ts

The public proof of concept accepts JSON only, requires an object body, sanitizes each field, and applies a strict schema before any Oracle or GitHub operation. Sensitive fields are intentionally omitted from this public excerpt.

Open source file
typescript
01if (request.headers.get("content-type") !== "application/json") {02  return NextResponse.json(03    { error: "Expected application/json" },04    { status: 415 }05  );06}07 08const rawRequestBody: unknown = await request.json();09 10if (11  rawRequestBody === null ||12  typeof rawRequestBody !== "object" ||13  Array.isArray(rawRequestBody)14) {15  return NextResponse.json(16    { error: "Request body must be a JSON object" },17    { status: 422 }18  );19}20 21const parseResult = requestBodySchema.safeParse(22  sanitizedRequest23);
02Create one review branch per requestsrc/app/api/handle-submit/route.ts

Each request receives a Git reference from the latest protected base revision, creating a discrete and reviewable change.

Open source file
typescript
01export async function createBranch(02  newBranch: string,03  sha: string04): Promise<void> {05  await gitFetch(06    `/repos/${GITHUB_OWNER}/${GITHUB_REPO}/git/refs`,07    {08      method: 'POST',09      body: { ref: `refs/heads/${newBranch}`, sha },10    }11  )12}
03Turn metadata into a DBA-reviewable pull requestsrc/app/api/handle-submit/route.ts

The API opens a pull request from the generated branch to the configured base. Repository access and protected review provide the authorization boundary for the production workflow.

Open source file
typescript
01export async function createPullRequest(02  newBranch: string,03  pullRequestMarkDownBody: string04): Promise<PrResponse> {05  return gitFetch<PrResponse>(06    `/repos/${GITHUB_OWNER}/${GITHUB_REPO}/pulls`,07    {08      method: 'POST',09      body: {10        title: newBranch,11        head: newBranch,12        base: `${GITHUB_BRANCH}`,13        body: pullRequestMarkDownBody,14        draft: false,15      },16    }17  )18}
04Walk the BI Publisher catalog recursivelyget-folder-path-by-filename.py

The Python proof of concept parsed SOAP catalog items and recursively traversed folders to build a complete object list.

python
01objects: list[FolderContents] = []02 03for item in items_parent.findall("ns2:item", ns):04    obj = FolderContents(05        absolutePath=item.findtext(06            ".//ns2:absolutePath",07            default="",08            namespaces=ns09        ),10        fileName=item.findtext(11            ".//ns2:fileName",12            default="",13            namespaces=ns14        ),15        type=item.findtext(16            ".//ns2:type",17            default="",18            namespaces=ns19        )20    )21 22    if obj.type.lower() == "folder":23        objects.extend(24            getAllFileNameAbsolutePath(obj.absolutePath)25        )26 27    objects.append(obj)28 29return objects
05Generate a consistent review bodysrc/lib/MarkDownEnvSub.ts

An allow-listed substitution helper fills the review template with validated promotion metadata and keeps pull-request formatting consistent.

Open source file
typescript
01export async function markDownEnvSub(02  filePath: string,03  envVars: Record<string, string | number>04): Promise<string> {05  const template = await readFile(06    resolve(filePath),07    "utf8"08  );09 10  return template.replace(11    /${([A-Z0-9_]+)}/g,12    (_, key) => key in envVars13      ? String(envVars[key])14      : ""15  );16}

Sources and boundaries.

Public links open in a new tab. Private code and project artifacts are summarized without exposing infrastructure details or credentials.

repository

Public BI Publisher UI/API proof of concept

owner code

Oracle SOAP promotion proof-of-concept excerpts

owner statement

Production deployment and organizational impact record