Go to file
Hongming Wang e7c6798fba ci: extract PR-based auto-promote-staging into reusable workflow (P9)
Moves the canonical PR-based staging→main auto-promote flow into a
reusable workflow that protected-branch repos can call instead of
duplicating ~240 lines of YAML each.

Why two reusable variants in this repo:

  auto-promote-staging.yml           (existing — ff-only, direct push)
    For repos WITHOUT required-status-checks branch protection.
    Already used for molecule-ci, molecule-app, molecule-docs,
    molecule-monorepo. Cannot satisfy protected-branch rules
    requiring status checks "set by expected GitHub apps".

  auto-promote-staging-pr.yml        (THIS PR — PR-based)
    For repos WITH required-status-checks. Opens (or reuses) a
    staging→main PR, enables auto-merge, lets the merge queue land
    it. Required path for molecule-core + molecule-controlplane
    (per the 2026-04-28 incident where direct ff-only push was
    failing GH006 on protected refs).

Inputs:
  gates           — CSV of workflow filenames to require green
  target-branch   — promote target (default: main)
  source-branch   — promote source (default: staging)
  enabled-var     — repo variable name gating rollout
                    (default: AUTO_PROMOTE_ENABLED)
  merge-method    — merge|squash|rebase (default: merge — matches
                    user preference for merge commits over squash)
  force           — pass through caller's workflow_dispatch.force input

Caller pattern (kept minimal — see header comment in the workflow):

  on:
    workflow_run:
      workflows: [CI, ...]
      types: [completed]
    workflow_dispatch:
      inputs:
        force: ...
  permissions:
    contents: write
    pull-requests: write
  jobs:
    promote:
      uses: Molecule-AI/molecule-ci/.github/workflows/auto-promote-staging-pr.yml@main
      with:
        gates: "ci.yml,e2e-staging-canvas.yml,..."
        force: ${{ github.event.inputs.force == 'true' }}
      secrets: inherit

The caller's `on.workflow_run.workflows` (display names) MUST stay in
sync with the `gates` input (filenames). The reusable can't validate
this because GitHub Actions decouples display names from filenames;
this is the same coupling the original molecule-core workflow had.

Migration of the existing 242-line molecule-core workflow to this
reusable is a follow-up PR. Same pattern applies to
molecule-controlplane once it grows protected-branch
auto-promote (today CP uses the auto-sync-main-to-staging shape
inherited from #142).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 01:01:52 -07:00
.github/workflows ci: extract PR-based auto-promote-staging into reusable workflow (P9) 2026-04-30 01:01:52 -07:00
.molecule-ci/scripts fix(validator): address post-merge review findings on #17 + #18 (#19) 2026-04-28 12:17:44 -07:00
docs feat(validate-workspace-template): strict drift gate + canonical-fetch workflow 2026-04-27 14:50:55 -07:00
scripts fix(validator): handle abstract intermediates + class-aliasing + lock GITHUB_TOKEN scope (#21) 2026-04-28 12:27:09 -07:00
.gitignore chore: remove accidentally-committed __pycache__ + gitignore Python caches (#20) 2026-04-28 12:18:46 -07:00
README.md docs: add disable-auto-merge-on-push to README (#11) 2026-04-27 06:46:40 -07:00

molecule-ci

Shared CI workflows for the Molecule AI ecosystem. Every plugin, workspace template, and org template repo calls these reusable workflows to enforce a standard validation gate.

Usage

Plugin repos (molecule-ai-plugin-*)

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  validate:
    uses: Molecule-AI/molecule-ci/.github/workflows/validate-plugin.yml@main

Workspace template repos (molecule-ai-workspace-template-*)

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  validate:
    uses: Molecule-AI/molecule-ci/.github/workflows/validate-workspace-template.yml@main

Org template repos (molecule-ai-org-template-*)

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  validate:
    uses: Molecule-AI/molecule-ci/.github/workflows/validate-org-template.yml@main

Any repo with auto-merge enabled

PR-time guards (currently: disable auto-merge on follow-up push). Consume from a thin caller:

# .github/workflows/pr-guards.yml
name: pr-guards
on:
  pull_request:
    types: [synchronize]
permissions:
  pull-requests: write
jobs:
  disable-auto-merge-on-push:
    uses: Molecule-AI/molecule-ci/.github/workflows/disable-auto-merge-on-push.yml@main

When the team lands more PR-time guards in this repo, add them as additional jobs in the same caller — keeps each consuming repo's footprint to one file.

What each workflow validates

validate-plugin

Check Severity What it catches
plugin.yaml exists Error Missing manifest
Required fields (name, version, description) Error Incomplete plugin
Has content (SKILL.md, hooks/, skills/, or rules/) Error Empty plugin
SKILL.md starts with heading Warning Bad formatting
No committed secrets Error Leaked API keys
No build artifacts Error node_modules, pycache

validate-workspace-template

Check Severity What it catches
config.yaml exists Error Missing config
Required fields (name, runtime) Error Incomplete template
template_schema_version: 1 Error Missing version contract
Known runtime check Warning Typo in runtime name
adapter.py imports molecule_runtime Warning Legacy imports
Dockerfile builds Error Broken image
molecule-ai-workspace-runtime dependency Warning Missing base package
No committed secrets Error Leaked API keys

validate-org-template

Check Severity What it catches
org.yaml exists Error Missing org definition
Required fields (name) Error Incomplete template
Workspace structure valid Error Malformed hierarchy
files_dir references exist Warning Broken system-prompt paths
template_schema_version present Warning Missing version contract
No committed secrets Error Leaked API keys

disable-auto-merge-on-push

PR-time safety guard. When pull_request:synchronize fires (= a new commit pushed to an open PR) and auto-merge is already enabled, this workflow disables auto-merge and posts a comment requiring the operator to re-engage explicitly.

Why it exists: on 2026-04-27, molecule-core PR #2174 auto-merged with only its first commit because the second commit was pushed AFTER the merge queue had locked the PR's SHA. The second commit ended up orphaned on a merged-and-deleted branch.

Pairs with the org-wide repo setting "Automatically delete head branches" (already enabled on all 10 Molecule-AI repos). Defense in depth:

  1. Repo setting blocks pushes to a merged-and-deleted branch (catches the post-merge orphan case).
  2. This workflow catches the in-queue race (push during queue processing) by force-disabling auto-merge.

Together they cover the full lifecycle of "auto-merge enabled → new commits arrive" without operator discipline.

False-positive note: if a CI bot pushes (dependency update, secret rotation), this also disables auto-merge. That's intentional — the operator who originally enabled auto-merge gets notified and re-engages, which is exactly the verify-after-machine-edits behavior we want.

License

Business Source License 1.1 — © Molecule AI.