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
3 changes: 1 addition & 2 deletions .codeocean/environment.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"version": 1,
"base_image": "codeocean/mosuite-minimal:v0.3.1",
"post_install": true,
"base_image": "codeocean/mosuite-minimal:v0.3.2",
"options": {
"registry_host_arg": true,
"git_ask_pass": true,
Expand Down
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/code/MOSuite linguist-vendored
/code/MOSuite linguist-vendored
code/MOSuite linguist-vendored
191 changes: 191 additions & 0 deletions .github/workflows/syncweaver-host-contribute-patch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
name: syncweaver-contribute-patch

on:
workflow_dispatch:
inputs:
source_path:
description: Optional tracked source path override; if omitted, source_path is resolved from lockfile.
required: false
type: string
repo_url:
description: Optional source repository identifier (URL or OWNER/REPO) used to resolve source_path from lockfile.
required: false
type: string
source_repository:
description: Optional source repository in OWNER/REPO format; if omitted, derives from lockfile repo_url.
required: false
type: string
lockfile:
description: Path to the syncweaver lockfile.
required: false
default: .syncweaver-lock.json
type: string
patch_path:
description: Optional patch path override; if omitted, uses source entry patch value from lockfile.
required: false
type: string
source_base_ref:
description: Optional source repository base branch for PR; if omitted, uses source entry ref from lockfile.
required: false
type: string
syncweaver-version:
description: syncweaver version/ref to install (e.g. version tag, branch name, or commit SHA). Will use docker image if available.
required: false
type: string
default: main

permissions:
contents: read

jobs:
resolve-patch-metadata:
runs-on: ubuntu-latest
outputs:
source_path: ${{ steps.resolve.outputs.source_path }}
repo_url: ${{ steps.resolve.outputs.repo_url }}
source_repository: ${{ steps.resolve.outputs.source_repository }}
patch_path: ${{ steps.resolve.outputs.patch_path }}
source_base_ref: ${{ steps.resolve.outputs.source_base_ref }}
lockfile: ${{ env.LOCKFILE }}
env:
SOURCE_PATH: ${{ github.event.inputs.source_path || '' }}
REPO_URL: ${{ github.event.inputs.repo_url || '' }}
SOURCE_REPOSITORY: ${{ github.event.inputs.source_repository || '' }}
LOCKFILE: ${{ github.event.inputs.lockfile || '.syncweaver-lock.json' }}
PATCH_PATH: ${{ github.event.inputs.patch_path || '' }}
SOURCE_BASE_REF: ${{ github.event.inputs.source_base_ref || '' }}
SYNCWEAVER_VERSION: ${{ github.event.inputs['syncweaver-version'] || github.event.client_payload['syncweaver-version'] || 'main' }}
steps:
- name: Checkout host repository
uses: actions/checkout@v6

- name: Setup syncweaver
uses: CCBR/syncweaver/actions/setup-syncweaver@main
with:
syncweaver-version: ${{ env.SYNCWEAVER_VERSION }}

- name: Resolve source and patch metadata
id: resolve
shell: bash
env:
SOURCE_PATH_INPUT: ${{ env.SOURCE_PATH }}
REPO_URL_INPUT: ${{ env.REPO_URL }}
SOURCE_REPOSITORY_INPUT: ${{ env.SOURCE_REPOSITORY }}
LOCKFILE_PATH: ${{ env.LOCKFILE }}
PATCH_PATH_INPUT: ${{ env.PATCH_PATH }}
SOURCE_BASE_REF_INPUT: ${{ env.SOURCE_BASE_REF }}
SYNCWEAVER_HOST_CWD: ${{ github.workspace }}
run: |
set -euo pipefail
syncweaver-python -m syncweaver.contribute_patch

- name: Print resolved metadata
shell: bash
run: |
set -euo pipefail
echo "source_path=${{ steps.resolve.outputs.source_path }}"
echo "repo_url=${{ steps.resolve.outputs.repo_url }}"
echo "source_repository=${{ steps.resolve.outputs.source_repository }}"
echo "patch_path=${{ steps.resolve.outputs.patch_path }}"
echo "source_base_ref=${{ steps.resolve.outputs.source_base_ref }}"

contribute-patch:
runs-on: ubuntu-latest
needs: resolve-patch-metadata
permissions:
contents: read
env:
SOURCE_PATH: ${{ needs.resolve-patch-metadata.outputs.source_path }}
REPO_URL: ${{ needs.resolve-patch-metadata.outputs.repo_url }}
SOURCE_REPOSITORY: ${{ needs.resolve-patch-metadata.outputs.source_repository }}
PATCH_PATH: ${{ needs.resolve-patch-metadata.outputs.patch_path }}
SOURCE_BASE_REF: ${{ needs.resolve-patch-metadata.outputs.source_base_ref }}
LOCKFILE: ${{ needs.resolve-patch-metadata.outputs.lockfile }}
steps:
- name: Generate CCBR-bot token
id: ccbr_bot
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.CCBR_BOT_APP_ID }}
private-key: ${{ secrets.CCBR_BOT_PRIVATE_KEY }}

- name: Checkout host repository
uses: actions/checkout@v6
with:
path: host

- name: Checkout source repository
uses: actions/checkout@v6
with:
repository: ${{ env.SOURCE_REPOSITORY }}
ref: ${{ env.SOURCE_BASE_REF }}
token: ${{ steps.ccbr_bot.outputs.token }}
path: source

- name: Apply patch to source repository
id: apply_patch
shell: bash
run: |
set -euo pipefail

patch_file="$GITHUB_WORKSPACE/host/${PATCH_PATH}"
if [[ ! -f "$patch_file" ]]; then
echo "Error: patch file not found in host repository: ${PATCH_PATH}" >&2
exit 1
fi

branch_stub=$(printf '%s' "$SOURCE_PATH" | tr '/ ' '--' | tr -cd '[:alnum:]._-')
if [[ -z "$branch_stub" ]]; then
branch_stub="patch"
fi
branch_name="syncweaver/contribute-patch/${branch_stub}-${GITHUB_RUN_ID}"

cd "$GITHUB_WORKSPACE/source"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git switch -c "$branch_name"

if ! git apply --3way --whitespace=nowarn "$patch_file"; then
echo "Error: patch failed to apply cleanly to ${SOURCE_REPOSITORY}@${SOURCE_BASE_REF}" >&2
exit 1
fi

if git diff --quiet; then
echo "has_changes=false" >> "$GITHUB_OUTPUT"
else
echo "has_changes=true" >> "$GITHUB_OUTPUT"
fi
echo "branch_name=$branch_name" >> "$GITHUB_OUTPUT"

- name: Open pull request in source repository
if: steps.apply_patch.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@v7
with:
token: ${{ steps.ccbr_bot.outputs.token }}
path: source
base: ${{ env.SOURCE_BASE_REF }}
branch: ${{ steps.apply_patch.outputs.branch_name }}
delete-branch: true
commit-message: "chore(syncweaver): apply host patch for ${{ env.SOURCE_PATH }}"
title: "chore(syncweaver): apply host patch for ${{ env.SOURCE_PATH }}"
body: |
Automated patch contribution from host repository workflow dispatch.

Inputs used:
- source_path: ${{ env.SOURCE_PATH }}
- repo_url: ${{ env.REPO_URL }}
- source_repository: ${{ env.SOURCE_REPOSITORY }}
- source_base_ref: ${{ env.SOURCE_BASE_REF }}
- patch_path: ${{ env.PATCH_PATH }}
- lockfile: ${{ env.LOCKFILE }}

Trigger context:
- host_repository: ${{ github.repository }}
- workflow_run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}

- name: Print no-op summary
if: steps.apply_patch.outputs.has_changes == 'false'
shell: bash
run: |
set -euo pipefail
echo "Patch applied cleanly but introduced no source changes. No PR created."
172 changes: 172 additions & 0 deletions .github/workflows/syncweaver-host-update.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
name: syncweaver-host-update

on:
repository_dispatch:
workflow_dispatch:
inputs:
source_path:
description: Optional tracked source path override for manual runs; if omitted, source_path is resolved from the lockfile.
required: false
type: string
repo_url:
description: Optional source repository identifier (URL or OWNER/REPO) used to resolve source_path from lockfile; for repository_dispatch this defaults to client_payload.source_repository.
required: false
type: string
lockfile:
description: Path to the syncweaver lockfile.
required: false
default: .syncweaver-lock.json
type: string
ref:
description: Optional git ref to sync from.
required: false
type: string
remote_subdir:
description: Optional remote subdirectory to vendor.
required: false
type: string
syncweaver-version:
description: syncweaver version/ref to install (e.g. version tag, branch name, or commit SHA). Will use docker image if available.
required: false
type: string
default: main

permissions:
contents: write
pull-requests: write

jobs:
resolve-source-paths:
runs-on: ubuntu-latest
outputs:
source_paths: ${{ steps.resolve_source_paths.outputs.source_paths }}
source_count: ${{ steps.resolve_source_paths.outputs.source_count }}
lockfile: ${{ env.LOCKFILE }}
ref: ${{ env.REF }}
remote_subdir: ${{ env.REMOTE_SUBDIR }}
repo_url: ${{ env.REPO_URL }}
syncweaver_version: ${{ steps.job_meta.outputs.syncweaver_version }}
env:
# workflow_dispatch may provide source_path directly; repository_dispatch usually
# omits it so the workflow resolves source_path from lockfile + source_repository.
SOURCE_PATH: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.source_path || github.event.client_payload.source_path || '' }}
# Prefer explicit repo_url, then fall back to source_repository from dispatch payload.
REPO_URL: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.repo_url || github.event.client_payload.repo_url || github.event.client_payload.source_repository || '' }}
LOCKFILE: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.lockfile || github.event.client_payload.lockfile || '.syncweaver-lock.json' }}
REF: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ref || github.event.client_payload.ref || '' }}
REMOTE_SUBDIR: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.remote_subdir || github.event.client_payload.remote_subdir || '' }}
SYNCWEAVER_VERSION: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs['syncweaver-version'] || github.event.client_payload['syncweaver-version'] || 'main' }}
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Setup syncweaver
uses: CCBR/syncweaver/actions/setup-syncweaver@main
with:
syncweaver-version: ${{ env.SYNCWEAVER_VERSION }}

- name: Capture syncweaver inputs
id: job_meta
shell: bash
run: |
set -euo pipefail
echo "syncweaver_version=${SYNCWEAVER_VERSION}" >> "$GITHUB_OUTPUT"

- name: Resolve source paths
id: resolve_source_paths
shell: bash
env:
SOURCE_PATH_INPUT: ${{ env.SOURCE_PATH }}
REPO_URL_INPUT: ${{ env.REPO_URL }}
LOCKFILE_PATH: ${{ env.LOCKFILE }}
run: |
set -euo pipefail
syncweaver-python - <<'PY' >> "$GITHUB_OUTPUT"
import json
import os
import pathlib

from syncweaver.lockfile import resolve_source_paths_from_lockfile

source_path_input = os.environ["SOURCE_PATH_INPUT"].strip()
repo_url_input = os.environ["REPO_URL_INPUT"].strip()
lockfile_path = pathlib.Path(os.environ["LOCKFILE_PATH"])

try:
resolved_source_paths = resolve_source_paths_from_lockfile(
lockfile=lockfile_path,
source_path=source_path_input,
repo_url=repo_url_input,
)
except ValueError as exc:
raise SystemExit(f"Error: {exc}") from exc

print(f"source_paths={json.dumps(resolved_source_paths)}")
print(f"source_count={len(resolved_source_paths)}")
PY

- name: Print resolved source paths
shell: bash
run: |
set -euo pipefail
echo "source_count=${{ steps.resolve_source_paths.outputs.source_count }}"
echo "source_paths=${{ steps.resolve_source_paths.outputs.source_paths }}"

update-source:
runs-on: ubuntu-latest
needs: resolve-source-paths
strategy:
fail-fast: false
matrix:
source_path: ${{ fromJson(needs.resolve-source-paths.outputs.source_paths) }}
env:
LOCKFILE: ${{ needs.resolve-source-paths.outputs.lockfile }}
REF: ${{ needs.resolve-source-paths.outputs.ref }}
REMOTE_SUBDIR: ${{ needs.resolve-source-paths.outputs.remote_subdir }}
REPO_URL: ${{ needs.resolve-source-paths.outputs.repo_url }}
SYNCWEAVER_VERSION: ${{ needs.resolve-source-paths.outputs.syncweaver_version }}
steps:
- name: Generate CCBR-bot token
id: ccbr_bot
uses: actions/create-github-app-token@v1
with:
app-id: ${{ vars.CCBR_BOT_APP_ID }}
private-key: ${{ secrets.CCBR_BOT_PRIVATE_KEY }}

- name: Checkout repository
uses: actions/checkout@v6
with:
token: ${{ steps.ccbr_bot.outputs.token }}

- name: Run update-source composite action
id: update_source
uses: CCBR/syncweaver/actions/update-source@latest
with:
source_path: ${{ matrix.source_path }}
lockfile: ${{ env.LOCKFILE }}
ref: ${{ env.REF }}
remote_subdir: ${{ env.REMOTE_SUBDIR }}
syncweaver-version: ${{ env.SYNCWEAVER_VERSION }}

- name: Commit changes and open PR
uses: peter-evans/create-pull-request@v7
with:
token: ${{ steps.ccbr_bot.outputs.token }}
branch: syncweaver/update-source/${{ matrix.source_path }}
delete-branch: true
commit-message: "chore(syncweaver): update ${{ matrix.source_path }} from ${{ steps.update_source.outputs.source_repo }}@${{ steps.update_source.outputs.ref }}"
title: "chore(syncweaver): update ${{ matrix.source_path }} from ${{ steps.update_source.outputs.source_repo }}@${{ steps.update_source.outputs.ref }}"
body: |
Automated source update from the update-source workflow.

Inputs used:
- source_path: ${{ matrix.source_path }}
- repo_url: ${{ env.REPO_URL }}
- lockfile: ${{ env.LOCKFILE }}
- ref: ${{ env.REF }}
- remote_subdir: ${{ env.REMOTE_SUBDIR }}

Resolved from lockfile after update:
- source_url: ${{ steps.update_source.outputs.source_url }}
- ref: ${{ steps.update_source.outputs.ref }}
- remote_subdir: ${{ steps.update_source.outputs.remote_subdir }}
12 changes: 12 additions & 0 deletions .syncweaver-lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"host": "NIDAP-Community/MOSuite-plot-volcano-summary",
"orchestrator": "NIDAP-Community/syncweaver-orchestrator",
"syncweaver_version": "0.0.1-dev",
"sources": {
"code/MOSuite": {
"repo_url": "https://github.com/CCBR/MOSuite",
"ref": "v0.3.2",
"git_sha": "f4465c58a7d04f5feb41d4455a019ca4946a4ca8"
}
}
}
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Development version

- Improved the Code Ocean parameter UI for the plot volcano summary capsule (#2, @phoman14).
- Use MOSuite v0.3.2. (#3, @kelly-sovacool)

## v4.0

Expand Down
Loading
Loading