Skip to content
Merged
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
61 changes: 61 additions & 0 deletions .github/workflows/yield-lab.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Verify Yield lab

on:
pull_request:
paths: ["labs/22-yield/**", "go.work", ".github/workflows/yield-lab.yml"]
push:
branches: [main]
paths: ["labs/22-yield/**", "go.work", ".github/workflows/yield-lab.yml"]

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/go-setup
with:
go-version-file: labs/22-yield/yield/go.mod
cache-dependency-path: labs/22-yield/yield/go.sum
- name: Vet and test (includes subprocess e2e)
working-directory: labs/22-yield/yield
run: |
go vet ./...
go test ./...
- name: Fixture run of the reference skill
working-directory: labs/22-yield/yield
run: |
go build -o /tmp/yskill ./cmd/yskill
/tmp/yskill test examples/investigate

# Shift-left projection gate: materialize the public surface exactly as
# operatorstack/yield would receive it and compile+test it, so a broken
# projection fails at PR time instead of downstream after merge.
projection-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@v7
- name: Project yield to a temp public tree
run: |
mkdir -p "$RUNNER_TEMP/yield-projected"
uv run --project labkit python -m labkit project \
--config labs/22-yield/publish.config.json \
--repo "$RUNNER_TEMP/yield-projected" \
--source-commit "${{ github.sha }}" --write
- uses: ./.github/actions/go-setup
with:
go-version-file: ${{ runner.temp }}/yield-projected/go.mod
cache-dependency-path: ${{ runner.temp }}/yield-projected/go.sum
- name: Build and test the projected module
working-directory: ${{ runner.temp }}/yield-projected
env:
GOWORK: "off"
run: |
go build ./...
go test ./...
44 changes: 44 additions & 0 deletions .github/workflows/yield-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by labkit (python -m labkit gen). Do not edit by hand.
# Edit labs/<lab>/publish.config.json and regenerate; drift fails `labkit doctor`.
name: Publish Yield projection

on:
push:
branches: [main]
paths:
- "labs/22-yield/**"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: publish-yield-projection
cancel-in-progress: false

jobs:
dispatch:
if: github.repository == 'operatorstack/intelligence-flow'
runs-on: ubuntu-latest
steps:
- name: Create Operator Stack Publisher token
id: app-token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ vars.OPERATOR_STACK_PUBLISHER_APP_CLIENT_ID || vars.BOATSTACK_APP_CLIENT_ID }}
private-key: ${{ secrets.OPERATOR_STACK_PUBLISHER_APP_PRIVATE_KEY || secrets.BOATSTACK_APP_PRIVATE_KEY }}
owner: operatorstack
repositories: yield
permission-actions: write
permission-contents: read

- name: Dispatch Yield sync
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
SOURCE_COMMIT: ${{ github.sha }}
shell: bash
run: >-
gh workflow run sync-upstream.yml
--repo operatorstack/yield
--ref main
-f source_commit="$SOURCE_COMMIT"
94 changes: 94 additions & 0 deletions labs/22-yield/.labkit/generated/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Generated by labkit (python -m labkit gen). Do not edit by hand.
# Edit labs/<lab>/publish.config.json and regenerate; drift fails `labkit doctor`.
# Install into operatorstack/yield at .github/workflows/release.yml (bootstrap step).
name: Release Yield

on:
push:
branches: [main]
workflow_dispatch:
inputs:
bump:
description: Version bump for a manual release
type: choice
options: [patch, minor, major]
default: patch

permissions:
contents: write
pull-requests: read

concurrency:
group: release-yield
cancel-in-progress: false

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Resolve release policy
id: policy
env:
GH_TOKEN: ${{ github.token }}
MANUAL_BUMP: ${{ inputs.bump }}
shell: bash
run: |
bump="${MANUAL_BUMP:-patch}"
skip="false"
if [[ "${GITHUB_EVENT_NAME}" == "push" ]]; then
labels="$(gh api \
-H 'Accept: application/vnd.github+json' \
"/repos/${GITHUB_REPOSITORY}/commits/${GITHUB_SHA}/pulls" \
--jq '.[0].labels[].name' 2>/dev/null || true)"
if grep -qx 'skip-release' <<<"$labels"; then skip="true"; fi
if grep -qx 'major' <<<"$labels"; then
bump="major"
elif grep -qx 'minor' <<<"$labels"; then
bump="minor"
fi
fi
echo "bump=$bump" >> "$GITHUB_OUTPUT"
echo "skip=$skip" >> "$GITHUB_OUTPUT"
- name: Compute version
if: steps.policy.outputs.skip != 'true'
id: version
env:
BUMP: ${{ steps.policy.outputs.bump }}
shell: bash
run: |
latest="$(git tag --list 'v[0-9]*' --sort=-v:refname | head -n 1)"
if [[ -z "$latest" ]]; then
next="v0.1.0"
else
raw="${latest#v}"
IFS=. read -r major minor patch <<<"$raw"
case "$BUMP" in
major) major=$((major + 1)); minor=0; patch=0 ;;
minor) minor=$((minor + 1)); patch=0 ;;
patch) patch=$((patch + 1)) ;;
*) echo "Invalid bump: $BUMP" >&2; exit 2 ;;
esac
next="v${major}.${minor}.${patch}"
fi
echo "version=$next" >> "$GITHUB_OUTPUT"
- name: Publish release
if: steps.policy.outputs.skip != 'true'
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.version.outputs.version }}
shell: bash
run: |
if git rev-parse --verify --quiet "refs/tags/$VERSION"; then
echo "Tag $VERSION already exists; nothing to release."
exit 0
fi
git tag "$VERSION" "$GITHUB_SHA"
git push origin "$VERSION"
gh release create "$VERSION" \
--repo "$GITHUB_REPOSITORY" \
--title "$VERSION" \
--generate-notes \
--verify-tag
134 changes: 134 additions & 0 deletions labs/22-yield/.labkit/generated/sync-upstream.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Generated by labkit (python -m labkit gen). Do not edit by hand.
# Edit labs/<lab>/publish.config.json and regenerate; drift fails `labkit doctor`.
# Install into operatorstack/yield at .github/workflows/sync-upstream.yml (bootstrap step).
name: Sync from Intelligence Flow

on:
schedule:
- cron: "19 */6 * * *"
workflow_dispatch:
inputs:
source_commit:
description: Exact Intelligence Flow commit to project (defaults to main)
required: false
type: string

permissions:
contents: write
pull-requests: write

concurrency:
group: sync-intelligence-flow
cancel-in-progress: false

jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Create Operator Stack Publisher token
id: app-token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ vars.OPERATOR_STACK_PUBLISHER_APP_CLIENT_ID || vars.BOATSTACK_APP_CLIENT_ID }}
private-key: ${{ secrets.OPERATOR_STACK_PUBLISHER_APP_PRIVATE_KEY || secrets.BOATSTACK_APP_PRIVATE_KEY }}
owner: operatorstack
repositories: |
intelligence-flow
yield
permission-contents: write
permission-pull-requests: write
- name: Check out Yield
uses: actions/checkout@v4
with:
path: public-repo
token: ${{ steps.app-token.outputs.token }}
- name: Check out Intelligence Flow
uses: actions/checkout@v4
with:
repository: operatorstack/intelligence-flow
ref: ${{ inputs.source_commit || 'main' }}
fetch-depth: 0
path: intelligence-flow
token: ${{ steps.app-token.outputs.token }}
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install labkit
shell: bash
run: python3 -m pip install --quiet ./intelligence-flow/labkit
- name: Generate projection
id: generate
shell: bash
run: |
source_commit="$(git -C intelligence-flow log -1 --format=%H -- labs/22-yield)"
current_commit="$(jq -r '.source.commit // empty' public-repo/UPSTREAM.json 2>/dev/null || echo '')"
if [[ -n "$current_commit" ]] &&
! git -C intelligence-flow merge-base --is-ancestor "$current_commit" "$source_commit"; then
echo "Ignoring stale request; Yield already records $current_commit."
echo "stale=true" >> "$GITHUB_OUTPUT"
exit 0
fi
python3 -m labkit project \
--config intelligence-flow/labs/22-yield/publish.config.json \
--repo public-repo \
--source-commit "$source_commit" \
--write
echo "source_commit=$source_commit" >> "$GITHUB_OUTPUT"
echo "stale=false" >> "$GITHUB_OUTPUT"
- name: Open generated pull request
if: steps.generate.outputs.stale != 'true'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
SOURCE_COMMIT: ${{ steps.generate.outputs.source_commit }}
shell: bash
run: |
cd public-repo
if [[ -z "$(git status --porcelain)" ]]; then
echo "Yield already matches Intelligence Flow."
exit 0
fi
git add -A
rewritten=()
while IFS= read -r note; do rewritten+=("$note"); done < <(
git diff --cached --name-only --diff-filter=MD --no-renames -- 'release-notes/*.md')
if (( ${#rewritten[@]} > 0 )); then
echo "BLOCKED: Yield release notes are append-only:" >&2
printf ' %s\n' "${rewritten[@]}" >&2
exit 1
fi
added=()
while IFS= read -r note; do added+=("$note"); done < <(
git diff --cached --name-only --diff-filter=A --no-renames -- 'release-notes/*.md' | LC_ALL=C sort)
if (( ${#added[@]} == 0 )); then
echo "BLOCKED: projected changes require a release note in release-notes/." >&2
exit 1
fi
body_file="$(mktemp)"
{
echo "## What this sync releases"; echo
for note in "${added[@]}"; do cat "$note"; echo; done
echo "<details><summary>Projection provenance</summary>"; echo
echo "Generated from \`operatorstack/intelligence-flow@$SOURCE_COMMIT\`."
echo "Review provenance, tests, and examples before merging."; echo
echo "</details>"
} > "$body_file"
short="${SOURCE_COMMIT:0:12}"
branch="sync/intelligence-flow-$short"
existing="$(gh pr list --head "$branch" --state open --json url --jq '.[0].url')"
git config user.name "${{ steps.app-token.outputs.app-slug }}[bot]"
git config user.email "${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com"
git switch -c "$branch"
git commit -m "Sync Yield from Intelligence Flow @ $short"
git push --force --set-upstream origin "$branch"
if [[ -z "$existing" ]]; then
pr_url="$(gh pr create --base main --head "$branch" \
--title "Sync Yield from Intelligence Flow @ $short" \
--body-file "$body_file")"
echo "Opened generated PR: $pr_url"
else
pr_url="$existing"
echo "Updated existing PR: $existing"
fi
gh pr merge "$pr_url" --auto --squash
echo "Native auto-merge requested; branch protection owns merge eligibility."
56 changes: 56 additions & 0 deletions labs/22-yield/.labkit/generated/verify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Generated by labkit (python -m labkit gen). Do not edit by hand.
# Edit labs/<lab>/publish.config.json and regenerate; drift fails `labkit doctor`.
# Install into operatorstack/yield at .github/workflows/verify.yml (bootstrap step).
name: Verify Yield distribution

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

concurrency:
group: verify-yield-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache: true
- run: go test ./...
- run: go build ./...

verify-sync-provenance:
if: >-
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository &&
startsWith(github.head_ref, 'sync/intelligence-flow-')
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Verify generated projection provenance
env:
HEAD_BRANCH: ${{ github.head_ref }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
shell: bash
run: |
source_repo="$(jq -r '.source.repository' UPSTREAM.json)"
source_commit="$(jq -r '.source.commit' UPSTREAM.json)"
short="${source_commit:0:12}"
[[ "$PR_AUTHOR" == "operator-stack-publisher[bot]" ]]
[[ "$source_repo" == "operatorstack/intelligence-flow" ]]
[[ "$HEAD_BRANCH" == "sync/intelligence-flow-$short" ]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Yield is now published from Intelligence Flow

This repository is a projection of `operatorstack/intelligence-flow` at `labs/22-yield`. Do not edit files
here directly; changes land via the automated sync PR. See the lab's
`publish.config.json` for the published surface.
Loading
Loading