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
33 changes: 33 additions & 0 deletions packages/bash-ast/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ const ast = parse(source);
console.log(JSON.stringify(ast, null, 2));
```

#### Options

```typescript
parse(source, {
// keep comments as `Comment` nodes instead of dropping them (default: false)
keepComments: true,
// hard wall-clock budget; exceeding it throws instead of running unbounded
timeoutMs: 5000
});
```

### Deparsing

```typescript
Expand Down Expand Up @@ -70,16 +81,38 @@ console.log(JSON.stringify(clean1) === JSON.stringify(clean2)); // true
- Input (`<`)
- Output (`>`, `>>`)
- Here strings (`<<<`)
- Here-documents (`<<EOF`, `<<-EOF`, `<<'EOF'`) — the body is opaque text, never re-lexed as shell
- File descriptor redirects (`2>&1`)

### Other
- Asynchronous commands (`cmd &`)
- Comments (with `keepComments`)
- Process substitution (`<(cmd)`, `>(cmd)`)
- Variable assignments (`VAR=value`)
- Function definitions
- Quoted strings (single and double)
- Variable expansion (`$VAR`, `${VAR}`)
- Command substitution (`$(cmd)`, `` `cmd` ``)
- Arithmetic expansion (`$((expr))`)

## Round-tripping

`deparse(parse(x))` is meant to be *semantically* equivalent to `x`, not
character-identical: layout and optional whitespace are normalized. The
properties the test suite enforces over a corpus
of real GitHub Actions `run:` blocks (`__fixtures__/workflows`) are:

- `parse(deparse(parse(x)))` equals `parse(x)` once positions are stripped
(`cleanTree`);
- `deparse` is idempotent from the second pass on;
- the emitted text is accepted by `bash -n`.

Grouping is what makes this safe: a brace group or subshell stays a single
command through pipelines and `&&`/`||`, `&` stays on the command it
backgrounds, and `NAME=value` is an assignment only in assignment position (a
command prefix, or an operand of `export`/`local`/`declare`/`readonly`/`typeset`)
— elsewhere it is an ordinary argument, as in `psql --set ON_ERROR_STOP=1`.

## License

MIT
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# variant -> "jit tuned work_mem". `tuned` mirrors what
# validate-introspection does (pgpm tune --yes), so `baseline` is the
# configuration the real CI job runs under.
# On a bench/** push there are no inputs, so fall back to the pair that
# answers the open question — does the runner's slow mode spill?
VARIANTS='${{ inputs.variants }}'
[ -z "$VARIANTS" ] && VARIANTS='baseline,work_mem'
REPEAT='${{ inputs.repeat }}'
[ -z "$REPEAT" ] && REPEAT=1

declare -A V=(
[baseline]="on yes default"
[work_mem]="on yes 256MB"
[jit_off]="off yes default"
[untuned]="on no default"
)
ITEMS=()
IFS=',' read -ra WANT <<< "$VARIANTS"
for v in "${WANT[@]}"; do
v=$(echo "$v" | tr -d '[:space:]')
[ -z "${V[$v]:-}" ] && { echo "::error::unknown variant $v"; exit 1; }
read -r jit tuned wm <<< "${V[$v]}"
for i in $(seq 1 "$REPEAT"); do
ITEMS+=("{\"name\":\"$v-$i\",\"jit\":\"$jit\",\"tuned\":\"$tuned\",\"work_mem\":\"$wm\"}")
done
done
printf 'matrix={"include":[%s]}\n' "$(IFS=,; echo "${ITEMS[*]}")" >> $GITHUB_OUTPUT
printf 'planned: %s\n' "${ITEMS[*]}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# The runner itself is a variable in this experiment, so record it
# next to the numbers.
{
echo "runner_name=$RUNNER_NAME"
echo "nproc=$(nproc)"
echo "mem_total_kb=$(awk '/MemTotal/{print $2}' /proc/meminfo)"
grep -m1 'model name' /proc/cpuinfo
echo "postgres_image_digest=$(docker inspect --format '{{index .RepoDigests 0}}' ghcr.io/constructive-io/docker/postgres-plus:18 2>/dev/null || echo unknown)"
} | tee runner-info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cd compute
npx tsx ../compute/fun/cli/src/generate-standalone.ts --packages-only
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pgpm admin-users bootstrap --yes
pgpm admin-users add --test --yes
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ci/bench-generate.sh \
"${{ matrix.name }}" \
"${{ matrix.jit }}" \
"${{ matrix.tuned }}" \
"${{ matrix.work_mem }}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
echo "## \`${{ matrix.name }}\` — jit=${{ matrix.jit }} tuned=${{ matrix.tuned }} work_mem=${{ matrix.work_mem }}"
echo
echo '```'
cat bench-results/${{ matrix.name }}/wall.txt 2>/dev/null
cat runner-info.txt
echo '```'
echo
echo '### Top statements by total_exec_time'
echo
echo '```'
head -13 bench-results/${{ matrix.name }}/pgss_top.csv 2>/dev/null | cut -c1-200
echo '```'
} >> $GITHUB_STEP_SUMMARY
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cd compute
echo "matrix=$(tsx ../compute/fun/cli/src/image-type-matrix.ts)" >> "$GITHUB_OUTPUT"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cd compute
tsx ../compute/fun/cli/src/generate-standalone.ts --only=${{ matrix.handler }}
tsx ../compute/fun/cli/src/generate-dockerfiles.ts --only=${{ matrix.handler }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
set -euo pipefail
plan=$([ "$ALL" = 'true' ] \
&& pnpm exec tsx ci/functions/plan.ts --all \
|| pnpm exec tsx ci/functions/plan.ts)
features=$(echo "$plan" | jq -c '.features')
echo "features=$features" >> "$GITHUB_OUTPUT"
echo "any=$([ "$features" = '[]' ] && echo false || echo true)" >> "$GITHUB_OUTPUT"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pnpm --filter '@constructive-functions/test-utils...'
--filter '@constructive-functions/seeds'
--filter '@constructive-db/compute-runtime...'
--filter '@constructive-db/agentic-metering...'
run build
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pgpm admin-users bootstrap --yes
# The stack grants CONNECT to app_user/app_admin, so a database it
# deploys into needs them to exist as well as the platform roles.
pgpm admin-users add --test --yes
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
set -euo pipefail
echo "plan=$PLAN features=$FEATURES (any=$ANY)"
[ "$PLAN" = 'success' ]
if [ "$ANY" = 'true' ]; then
[ "$FEATURES" = 'success' ]
fi
2 changes: 2 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/generate-all-0088.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
2 changes: 2 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/generate-all-0134.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pgpm admin-users bootstrap --yes
pgpm admin-users add --test --yes
79 changes: 79 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/generate-all-0175.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Check introspection output changes (application/constructive/)
APP_UNTRACKED=$(git ls-files --others --exclude-standard application/ | head -20)
if git diff --quiet application/ && [ -z "$APP_UNTRACKED" ]; then
echo "has_introspection_changes=false" >> $GITHUB_OUTPUT
echo "No introspection changes detected"
else
echo "has_introspection_changes=true" >> $GITHUB_OUTPUT
echo "Introspection changes detected:"
git diff --stat application/
if [ -n "$APP_UNTRACKED" ]; then
echo "New untracked files in application/:"
echo "$APP_UNTRACKED"
fi
fi

# Check schema changes
if git diff --quiet sdk/constructive-schema/schemas/; then
echo "has_schema_changes=false" >> $GITHUB_OUTPUT
echo "No schema changes detected"
else
echo "has_schema_changes=true" >> $GITHUB_OUTPUT
echo "Schema changes detected:"
git diff --stat sdk/constructive-schema/schemas/
fi

# Check all SDK changes (tracked + untracked)
SDK_UNTRACKED=$(git ls-files --others --exclude-standard sdk/ | head -20)
if git diff --quiet sdk/ && [ -z "$SDK_UNTRACKED" ]; then
echo "has_sdk_changes=false" >> $GITHUB_OUTPUT
echo "No SDK changes detected"
else
echo "has_sdk_changes=true" >> $GITHUB_OUTPUT
echo "SDK changes detected:"
git diff --stat sdk/
if [ -n "$SDK_UNTRACKED" ]; then
echo "New untracked files in sdk/:"
echo "$SDK_UNTRACKED"
fi
fi

# Check .agents/skills changes (codegen generates skill reference docs)
AGENTS_UNTRACKED=$(git ls-files --others --exclude-standard .agents/ | head -20)
if git diff --quiet .agents/ && [ -z "$AGENTS_UNTRACKED" ]; then
echo "has_agents_changes=false" >> $GITHUB_OUTPUT
echo "No agents/skills changes detected"
else
echo "has_agents_changes=true" >> $GITHUB_OUTPUT
echo "Agents/skills changes detected:"
git diff --stat .agents/
if [ -n "$AGENTS_UNTRACKED" ]; then
echo "New untracked files in .agents/:"
echo "$AGENTS_UNTRACKED"
fi
fi

# Overall: any changes in sdk/ OR application/ OR .agents/?
SDK_CHANGED="false"
APP_CHANGED="false"
AGENTS_CHANGED="false"
if ! git diff --quiet sdk/ || [ -n "$SDK_UNTRACKED" ]; then
SDK_CHANGED="true"
fi
if ! git diff --quiet application/ || [ -n "$APP_UNTRACKED" ]; then
APP_CHANGED="true"
fi
if ! git diff --quiet .agents/ || [ -n "$AGENTS_UNTRACKED" ]; then
AGENTS_CHANGED="true"
fi
if [ "$SDK_CHANGED" = "true" ] || [ "$APP_CHANGED" = "true" ] || [ "$AGENTS_CHANGED" = "true" ]; then
echo "has_any_changes=true" >> $GITHUB_OUTPUT
echo ""
echo "=== SUMMARY ==="
echo "Introspection changed: $APP_CHANGED"
echo "SDK changed: $SDK_CHANGED"
echo "Agents changed: $AGENTS_CHANGED"
else
echo "has_any_changes=false" >> $GITHUB_OUTPUT
echo "All generated outputs are up-to-date."
fi
10 changes: 10 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/generate-all-0298.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
echo "## Generation Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Source: \`${{ steps.refs.outputs.ref_sha }}\` (ref: \`${{ inputs.ref || 'main' }}\`)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Output | Changed |" >> $GITHUB_STEP_SUMMARY
echo "|--------|---------|" >> $GITHUB_STEP_SUMMARY
echo "| application/constructive/ (introspection) | ${{ steps.check_changes.outputs.has_introspection_changes }} |" >> $GITHUB_STEP_SUMMARY
echo "| sdk/constructive-schema/ (schemas) | ${{ steps.check_changes.outputs.has_schema_changes }} |" >> $GITHUB_STEP_SUMMARY
echo "| sdk/ (SDKs + CLI) | ${{ steps.check_changes.outputs.has_sdk_changes }} |" >> $GITHUB_STEP_SUMMARY
echo "| .agents/ (skills) | ${{ steps.check_changes.outputs.has_agents_changes }} |" >> $GITHUB_STEP_SUMMARY
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cd compute/fun/k8s
npx tsx scripts/check-image-freshness.ts --write | tee "$GITHUB_STEP_SUMMARY"
45 changes: 45 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/image-freshness-0068.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
set -euo pipefail
BRANCH="chore/pin-constructive-$TAG"

# A rerun before the last PR merges would otherwise fail on push.
if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null 2>&1; then
echo "Branch $BRANCH already exists — the bump to $TAG is already open."
exit 0
fi

git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git checkout -b "$BRANCH"
git add compute/fun/env/src/images.ts

cat > /tmp/commit-msg.txt <<EOF
chore(k8s): pin the constructive image to $TAG

Resolved from the published \`latest\` tag by the image-freshness
workflow. This moves the opt-in pin only; the default stays \`:latest\`.
EOF
git commit -F /tmp/commit-msg.txt
git push origin "$BRANCH"

cat > /tmp/pr-body.md <<EOF
The digest \`GRAPHQL_IMAGE_PINNED\` points at is no longer the build \`latest\` resolves to.

| | tag | digest |
|---|---|---|
| was | \`$PREVIOUS_TAG\` | — |
| now | \`$TAG\` | \`$DIGEST\` |

This is the **opt-in pin** only — the default remains \`:latest\` with
\`imagePullPolicy: Always\`, so no cluster was running the stale build.
What was stale is the reference an operator gets when they ask for
reproducibility, and the value tests use when they need a build that
cannot move.

Opened by [image-freshness](${{ github.server_url }}/${{ github.repository }}/actions/workflows/image-freshness.yml).
EOF

gh pr create \
--base main \
--head "$BRANCH" \
--title "chore(k8s): pin the constructive image to $TAG" \
--body-file /tmp/pr-body.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
git config --global user.name "CI Test User"
git config --global user.email "ci@example.com"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pgpm admin-users bootstrap --yes
pgpm admin-users add --test --yes
37 changes: 37 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/knative-test-0086.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
set -euo pipefail

if [ "$IS_PR" != 'true' ]; then
echo "cluster=true" >> "$GITHUB_OUTPUT"
echo "::notice::${{ github.event_name }} run — cluster suites always run"
exit 0
fi

if [ "$LABELLED" = 'true' ]; then
echo "cluster=true" >> "$GITHUB_OUTPUT"
echo "::notice::needs-knative label present — cluster suites run"
exit 0
fi

changed=$(git diff --name-only "origin/${BASE_REF}...HEAD")
echo "Changed files:"; echo "$changed"

plumbing=$(echo "$changed" | grep -vE \
-e '^compute/system/' \
-e '^compute/fixtures/' \
-e '^compute/runtimes/node/' \
-e '^compute/testkit/' \
-e '^functions/' \
-e '^compute/tests/' \
-e '^compute/docs/' \
-e '^ui/www/' \
-e '^fbp/' \
-e '\.md$' || true)

if [ -n "$plumbing" ]; then
echo "cluster=true" >> "$GITHUB_OUTPUT"
echo "::notice::Plumbing changed — cluster suites run"
echo "$plumbing"
else
echo "cluster=false" >> "$GITHUB_OUTPUT"
echo "::notice::Handler/runtime-only change — skipping the cluster suites. Add the 'needs-knative' label to force them."
fi
2 changes: 2 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/knative-test-0156.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
git config --global user.name "CI Test User"
git config --global user.email "ci@example.com"
6 changes: 6 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/knative-test-0195.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pnpm
--filter "@constructive-functions/cli..."
--filter "@constructive-db/compute-worker..."
--filter "@constructive-db/functions-integration-tests..."
--filter "@constructive-functions/seeds..."
run build
2 changes: 2 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/knative-test-0206.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cd compute/tests
pnpm typecheck
2 changes: 2 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/knative-test-0211.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cd compute/tests
pnpm jest --config jest.config.js --no-coverage --forceExit --verbose 'agentic-server|agent-context|agent-handlers|env-layering' 2>&1
2 changes: 2 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/knative-test-0218.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cd compute/tests
pnpm test:worker
2 changes: 2 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/knative-test-0227.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pgpm admin-users bootstrap --yes
pgpm admin-users add --test --yes
18 changes: 18 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/knative-test-0253.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
set -euo pipefail
mkdir -p ~/.ollama-models
docker run -d --name ollama \
-v ~/.ollama-models:/root/.ollama \
-p 11434:11434 \
ollama/ollama:0.32.9
for i in $(seq 1 30); do
curl -sf http://localhost:11434/api/tags >/dev/null && break
sleep 2
done
curl -sf http://localhost:11434/api/tags >/dev/null
if curl -sf http://localhost:11434/api/tags | grep -q '"nomic-embed-text'; then
echo "model already cached"
else
curl -sf http://localhost:11434/api/pull \
-d '{"name":"nomic-embed-text"}' -o /tmp/pull.log
grep -q '"status":"success"' /tmp/pull.log || { cat /tmp/pull.log; exit 1; }
fi
2 changes: 2 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/knative-test-0276.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cd compute/tests
pnpm jest --config jest.config.js --no-coverage --forceExit --verbose 'live-embed'
2 changes: 2 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/knative-test-0286.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cd functions/embedding
pnpm jest --no-coverage --forceExit --verbose 'live-record-loop'
2 changes: 2 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/knative-test-0294.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cd compute/testkit/test-utils
pnpm test --forceExit
2 changes: 2 additions & 0 deletions packages/bash-ast/__fixtures__/workflows/knative-test-0301.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cd compute/fun/k8s
pnpm test
Loading
Loading