From 1b16b87c0c856a345bfbe854083d80737a35e87d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:07:18 +0000 Subject: [PATCH 1/6] Initial plan From 7c1243494defcd10b2439b199de32e5c6e50d679 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:11:50 +0000 Subject: [PATCH 2/6] Add plugin workflow sync system with templates and update script Co-authored-by: caner-milko <13199909+caner-milko@users.noreply.github.com> --- .github/workflows/update_workflow.yml | 74 +++++++ .nodos-template/workflow_config.json | 5 + WORKFLOW_SYNC_README.md | 116 +++++++++++ plugin_build.yml.dev | 88 +++++++++ plugin_build.yml.nodos-1.2 | 88 +++++++++ plugin_build.yml.nodos-1.3 | 88 +++++++++ repositories.json | 199 +++++++++++++++++++ scripts/update_workflows.py | 267 ++++++++++++++++++++++++++ 8 files changed, 925 insertions(+) create mode 100644 .github/workflows/update_workflow.yml create mode 100644 .nodos-template/workflow_config.json create mode 100644 WORKFLOW_SYNC_README.md create mode 100644 plugin_build.yml.dev create mode 100644 plugin_build.yml.nodos-1.2 create mode 100644 plugin_build.yml.nodos-1.3 create mode 100644 repositories.json create mode 100755 scripts/update_workflows.py diff --git a/.github/workflows/update_workflow.yml b/.github/workflows/update_workflow.yml new file mode 100644 index 0000000..f001975 --- /dev/null +++ b/.github/workflows/update_workflow.yml @@ -0,0 +1,74 @@ +# Copyright MediaZ Teknoloji A.S. All Rights Reserved. + +name: Update Plugin Workflows + +on: + push: + branches: + - main + paths: + - 'plugin_build.yml.*' + - 'repositories.json' + - 'scripts/update_workflows.py' + - '.github/workflows/update_workflow.yml' + workflow_dispatch: + inputs: + repo: + description: 'Specific repository to update (owner/repo, optional)' + required: false + type: string + branch: + description: 'Specific branch to update (requires repo, optional)' + required: false + type: string + dry_run: + description: 'Dry run mode (show what would be done)' + required: false + type: boolean + default: false + +jobs: + update-workflows: + name: Update Plugin Repository Workflows + runs-on: ubuntu-latest + + steps: + - name: Checkout actions repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Update workflows + env: + GITHUB_TOKEN: ${{ secrets.CI_TOKEN }} + run: | + python3 scripts/update_workflows.py \ + --config repositories.json \ + ${{ github.event.inputs.repo && format('--repo {0}', github.event.inputs.repo) || '' }} \ + ${{ github.event.inputs.branch && format('--branch {0}', github.event.inputs.branch) || '' }} \ + ${{ github.event.inputs.dry_run == 'true' && '--dry-run' || '' }} + + - name: Summary + if: always() + run: | + echo "## Workflow Update Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ "${{ github.event.inputs.dry_run }}" == "true" ]; then + echo "**Mode:** Dry Run (no changes made)" >> $GITHUB_STEP_SUMMARY + else + echo "**Mode:** Live Update" >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + if [ -n "${{ github.event.inputs.repo }}" ]; then + echo "**Repository:** ${{ github.event.inputs.repo }}" >> $GITHUB_STEP_SUMMARY + if [ -n "${{ github.event.inputs.branch }}" ]; then + echo "**Branch:** ${{ github.event.inputs.branch }}" >> $GITHUB_STEP_SUMMARY + fi + else + echo "**Scope:** All repositories" >> $GITHUB_STEP_SUMMARY + fi diff --git a/.nodos-template/workflow_config.json b/.nodos-template/workflow_config.json new file mode 100644 index 0000000..737efc6 --- /dev/null +++ b/.nodos-template/workflow_config.json @@ -0,0 +1,5 @@ +{ + "build_number_offset": 0, + "linux_enabled": true, + "windows_enabled": true +} diff --git a/WORKFLOW_SYNC_README.md b/WORKFLOW_SYNC_README.md new file mode 100644 index 0000000..c6b2b81 --- /dev/null +++ b/WORKFLOW_SYNC_README.md @@ -0,0 +1,116 @@ +# Plugin Workflow Sync System + +This directory contains the workflow synchronization system for plugin repositories. + +## Overview + +The system automatically syncs build workflow files from this repository to all plugin repositories, ensuring they stay in sync and up-to-date. + +## Files + +### Template Files + +- `plugin_build.yml.dev` - Workflow template for `dev` branches +- `plugin_build.yml.nodos-1.3` - Workflow template for `nodos-1.3` branches +- `plugin_build.yml.nodos-1.2` - Workflow template for `nodos-1.2` branches + +These templates contain placeholders that are replaced with repository-specific values: +- `__BUILD_NUMBER_OFFSET__` - Starting build number offset for the repository +- `__LINUX_ENABLED__` - Whether Linux builds are enabled (true/false) +- `__WINDOWS_ENABLED__` - Whether Windows builds are enabled (true/false) + +### Configuration Files + +- `repositories.json` - Maps repositories and branches to their workflow templates +- `.nodos-template/workflow_config.json` - Example repository-specific configuration + +### Scripts + +- `scripts/update_workflows.py` - Python script that performs the workflow synchronization + +### Workflows + +- `.github/workflows/update_workflow.yml` - GitHub Actions workflow that runs the sync + +## How It Works + +1. When changes are pushed to template files or configuration in this repository, the `update_workflow.yml` workflow is triggered +2. The workflow runs `update_workflows.py` which: + - Reads `repositories.json` to get the list of repositories/branches to update + - For each repository/branch: + - Clones the repository + - Reads the repository-specific configuration from `.nodos/workflow_config.json` + - Applies the template substitutions + - Writes the result to `.github/workflows/build.yml` + - Commits and pushes the changes +3. Plugin repositories are updated automatically with the latest workflow files + +## Repository-Specific Configuration + +Each plugin repository can have a `.nodos/workflow_config.json` file with the following structure: + +```json +{ + "build_number_offset": 0, + "linux_enabled": true, + "windows_enabled": true +} +``` + +**Fields:** +- `build_number_offset` (number): Offset to add to GitHub's `run_number` for build numbering. Default: 0 +- `linux_enabled` (boolean): Whether Linux builds are enabled for this repository. Default: true +- `windows_enabled` (boolean): Whether Windows builds are enabled for this repository. Default: true + +If the configuration file doesn't exist, default values are used (all enabled, no offset). + +## Adding a New Plugin Repository + +1. Add an entry to `repositories.json` for each branch you want to sync: + +```json +{ + "repo": "nodos-dev/new-plugin", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" +} +``` + +2. Optionally, create `.nodos/workflow_config.json` in the plugin repository with custom settings + +3. Push the changes to this repository, which will trigger the automatic sync + +## Manual Workflow Sync + +You can manually trigger the workflow sync from the Actions tab: + +1. Go to Actions → Update Plugin Workflows +2. Click "Run workflow" +3. Optionally specify: + - A specific repository to update (e.g., `nodos-dev/audio`) + - A specific branch (requires repository) + - Dry run mode to preview changes without applying them + +## Template Customization + +To customize the workflow templates: + +1. Edit the appropriate `plugin_build.yml.*` file +2. Use placeholders (`__PLACEHOLDER__`) for repository-specific values +3. Update `scripts/update_workflows.py` if you add new placeholders +4. Push changes to trigger automatic sync + +## Testing + +To test changes without affecting production: + +1. Use the workflow dispatch option with dry-run mode enabled +2. Or test with a specific repository/branch first +3. Check the logs to see what changes would be made + +## Notes + +- The workflow files in plugin repositories should NOT be edited directly +- Changes should be made to the templates in this repository +- The sync system uses the `CI_TOKEN` secret for authentication +- Failed syncs will be reported in the workflow logs diff --git a/plugin_build.yml.dev b/plugin_build.yml.dev new file mode 100644 index 0000000..eef5549 --- /dev/null +++ b/plugin_build.yml.dev @@ -0,0 +1,88 @@ +# Copyright MediaZ Teknoloji A.S. All Rights Reserved. +# This file is automatically synced from the nodos-dev/actions repository +# DO NOT edit this file directly in the plugin repository + +name: Build + +on: + push: + branches: [ dev ] + workflow_dispatch: + inputs: + publish_mode: + description: 'Publish Mode' + required: true + default: 'If Changed' + type: choice + options: + - If Changed + - Force + - None + plugin_names: + description: 'Publish only these plugins (semicolon-delimited) (optional)' + required: false + default: '' + type: string + run_tests: + description: 'Run Tests' + required: false + default: false + type: boolean + clean: + description: 'Clean build' + required: false + default: false + type: boolean + sign_binaries: + description: 'Sign binaries' + required: false + default: false + type: boolean + linux: + description: 'Release for Linux' + required: false + default: true + type: boolean + windows: + description: 'Release for Windows' + required: false + default: true + type: boolean + version_check: + description: 'Version Check' + required: true + default: 'strict' + type: choice + options: + - none + - loose + - strict + +run-name: >- + ${{ ((github.event_name == 'push') && format('Build Only: {0}', github.event.head_commit.message)) || + (github.event.inputs.publish_mode == 'If Changed') && 'Build & Release' || + (github.event.inputs.publish_mode == 'Force') && 'Build & Release (Force)' || + 'Build Only' }} + +concurrency: + group: single + cancel-in-progress: false + +jobs: + call-release-plugins: + name: Build + uses: nodos-dev/actions/.github/workflows/plugins.yml@main + secrets: + CI_TOKEN: ${{ secrets.CI_TOKEN }} + SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }} + with: + ref_name: ${{ github.ref_name }} + publish_mode: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.publish_mode || 'None' }} + plugin_names: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.plugin_names || '' }} + clean: ${{ github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.clean) || false }} + build_number: ${{ github.run_number + __BUILD_NUMBER_OFFSET__ }} + sign_binaries: ${{github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.sign_binaries) || false }} + linux: ${{ __LINUX_ENABLED__ && (github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.linux) || github.event_name == 'push') }} + windows: ${{ __WINDOWS_ENABLED__ && (github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.windows) || github.event_name == 'push') }} + run_tests: ${{ github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.run_tests) || false }} + version_check: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version_check || 'strict' }} diff --git a/plugin_build.yml.nodos-1.2 b/plugin_build.yml.nodos-1.2 new file mode 100644 index 0000000..48855aa --- /dev/null +++ b/plugin_build.yml.nodos-1.2 @@ -0,0 +1,88 @@ +# Copyright MediaZ Teknoloji A.S. All Rights Reserved. +# This file is automatically synced from the nodos-dev/actions repository +# DO NOT edit this file directly in the plugin repository + +name: Build + +on: + push: + branches: [ nodos-1.2 ] + workflow_dispatch: + inputs: + publish_mode: + description: 'Publish Mode' + required: true + default: 'If Changed' + type: choice + options: + - If Changed + - Force + - None + plugin_names: + description: 'Publish only these plugins (semicolon-delimited) (optional)' + required: false + default: '' + type: string + run_tests: + description: 'Run Tests' + required: false + default: false + type: boolean + clean: + description: 'Clean build' + required: false + default: false + type: boolean + sign_binaries: + description: 'Sign binaries' + required: false + default: false + type: boolean + linux: + description: 'Release for Linux' + required: false + default: true + type: boolean + windows: + description: 'Release for Windows' + required: false + default: true + type: boolean + version_check: + description: 'Version Check' + required: true + default: 'strict' + type: choice + options: + - none + - loose + - strict + +run-name: >- + ${{ ((github.event_name == 'push') && format('Build Only: {0}', github.event.head_commit.message)) || + (github.event.inputs.publish_mode == 'If Changed') && 'Build & Release' || + (github.event.inputs.publish_mode == 'Force') && 'Build & Release (Force)' || + 'Build Only' }} + +concurrency: + group: single + cancel-in-progress: false + +jobs: + call-release-plugins: + name: Build + uses: nodos-dev/actions/.github/workflows/plugins.yml@main + secrets: + CI_TOKEN: ${{ secrets.CI_TOKEN }} + SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }} + with: + ref_name: ${{ github.ref_name }} + publish_mode: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.publish_mode || 'None' }} + plugin_names: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.plugin_names || '' }} + clean: ${{ github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.clean) || false }} + build_number: ${{ github.run_number + __BUILD_NUMBER_OFFSET__ }} + sign_binaries: ${{github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.sign_binaries) || false }} + linux: ${{ __LINUX_ENABLED__ && (github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.linux) || github.event_name == 'push') }} + windows: ${{ __WINDOWS_ENABLED__ && (github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.windows) || github.event_name == 'push') }} + run_tests: ${{ github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.run_tests) || false }} + version_check: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version_check || 'strict' }} diff --git a/plugin_build.yml.nodos-1.3 b/plugin_build.yml.nodos-1.3 new file mode 100644 index 0000000..9a0c904 --- /dev/null +++ b/plugin_build.yml.nodos-1.3 @@ -0,0 +1,88 @@ +# Copyright MediaZ Teknoloji A.S. All Rights Reserved. +# This file is automatically synced from the nodos-dev/actions repository +# DO NOT edit this file directly in the plugin repository + +name: Build + +on: + push: + branches: [ nodos-1.3 ] + workflow_dispatch: + inputs: + publish_mode: + description: 'Publish Mode' + required: true + default: 'If Changed' + type: choice + options: + - If Changed + - Force + - None + plugin_names: + description: 'Publish only these plugins (semicolon-delimited) (optional)' + required: false + default: '' + type: string + run_tests: + description: 'Run Tests' + required: false + default: false + type: boolean + clean: + description: 'Clean build' + required: false + default: false + type: boolean + sign_binaries: + description: 'Sign binaries' + required: false + default: false + type: boolean + linux: + description: 'Release for Linux' + required: false + default: true + type: boolean + windows: + description: 'Release for Windows' + required: false + default: true + type: boolean + version_check: + description: 'Version Check' + required: true + default: 'strict' + type: choice + options: + - none + - loose + - strict + +run-name: >- + ${{ ((github.event_name == 'push') && format('Build Only: {0}', github.event.head_commit.message)) || + (github.event.inputs.publish_mode == 'If Changed') && 'Build & Release' || + (github.event.inputs.publish_mode == 'Force') && 'Build & Release (Force)' || + 'Build Only' }} + +concurrency: + group: single + cancel-in-progress: false + +jobs: + call-release-plugins: + name: Build + uses: nodos-dev/actions/.github/workflows/plugins.yml@main + secrets: + CI_TOKEN: ${{ secrets.CI_TOKEN }} + SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }} + with: + ref_name: ${{ github.ref_name }} + publish_mode: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.publish_mode || 'None' }} + plugin_names: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.plugin_names || '' }} + clean: ${{ github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.clean) || false }} + build_number: ${{ github.run_number + __BUILD_NUMBER_OFFSET__ }} + sign_binaries: ${{github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.sign_binaries) || false }} + linux: ${{ __LINUX_ENABLED__ && (github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.linux) || github.event_name == 'push') }} + windows: ${{ __WINDOWS_ENABLED__ && (github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.windows) || github.event_name == 'push') }} + run_tests: ${{ github.event_name == 'workflow_dispatch' && fromJson(github.event.inputs.run_tests) || false }} + version_check: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version_check || 'strict' }} diff --git a/repositories.json b/repositories.json new file mode 100644 index 0000000..1070407 --- /dev/null +++ b/repositories.json @@ -0,0 +1,199 @@ +{ + "repositories": [ + { + "repo": "nodos-dev/audio", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "nodos-dev/audio", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "nodos-dev/audio", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + }, + { + "repo": "nodos-dev/aja", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "nodos-dev/aja", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "nodos-dev/aja", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + }, + { + "repo": "nodos-dev/decklink", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "nodos-dev/decklink", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "nodos-dev/decklink", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + }, + { + "repo": "nodos-dev/display", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "nodos-dev/display", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "nodos-dev/display", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + }, + { + "repo": "nodos-dev/mediaio", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "nodos-dev/mediaio", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "nodos-dev/mediaio", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + }, + { + "repo": "nodos-dev/modules", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "nodos-dev/modules", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "nodos-dev/modules", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + }, + { + "repo": "mediaz/nos-sys-vulkan", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "mediaz/nos-sys-vulkan", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "mediaz/nos-sys-vulkan", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + }, + { + "repo": "nodos-dev/rive", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "nodos-dev/rive", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "nodos-dev/rive", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + }, + { + "repo": "nodos-dev/sys-device", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "nodos-dev/sys-device", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "nodos-dev/sys-device", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + }, + { + "repo": "nodos-dev/sys-settings", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "nodos-dev/sys-settings", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "nodos-dev/sys-settings", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + }, + { + "repo": "nodos-dev/test", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "nodos-dev/test", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "nodos-dev/test", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + }, + { + "repo": "nodos-dev/transfer", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "nodos-dev/transfer", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "nodos-dev/transfer", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + }, + { + "repo": "nodos-dev/webcam", + "branch": "dev", + "workflow_template": "plugin_build.yml.dev" + }, + { + "repo": "nodos-dev/webcam", + "branch": "nodos-1.3", + "workflow_template": "plugin_build.yml.nodos-1.3" + }, + { + "repo": "nodos-dev/webcam", + "branch": "nodos-1.2", + "workflow_template": "plugin_build.yml.nodos-1.2" + } + ] +} diff --git a/scripts/update_workflows.py b/scripts/update_workflows.py new file mode 100755 index 0000000..d6c2814 --- /dev/null +++ b/scripts/update_workflows.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 +""" +Update workflow files in plugin repositories based on templates. + +This script reads the repositories.json configuration file and updates +the build.yml workflow file in each repository/branch with the appropriate +template, applying repository-specific configuration. +""" + +import argparse +import json +import os +import sys +import subprocess +import tempfile +import shutil +from pathlib import Path + + +def run_command(cmd, cwd=None, check=True): + """Run a shell command and return the output.""" + result = subprocess.run( + cmd, + shell=True, + cwd=cwd, + capture_output=True, + text=True, + check=False + ) + if check and result.returncode != 0: + print(f"Error running command: {cmd}") + print(f"stdout: {result.stdout}") + print(f"stderr: {result.stderr}") + sys.exit(1) + return result + + +def get_repo_config(repo_path, branch): + """ + Fetch repository-specific configuration from .nodos/workflow_config.json + in the plugin repository. + """ + config_path = os.path.join(repo_path, '.nodos', 'workflow_config.json') + + default_config = { + 'build_number_offset': 0, + 'linux_enabled': True, + 'windows_enabled': True + } + + if not os.path.exists(config_path): + print(f" No config file found at {config_path}, using defaults") + return default_config + + try: + with open(config_path, 'r') as f: + config = json.load(f) + # Merge with defaults + return {**default_config, **config} + except Exception as e: + print(f" Error reading config file: {e}, using defaults") + return default_config + + +def apply_template_substitutions(template_content, repo_config): + """ + Apply repository-specific substitutions to the workflow template. + + Placeholders: + - __BUILD_NUMBER_OFFSET__: Starting build number offset + - __LINUX_ENABLED__: Whether Linux builds are enabled + - __WINDOWS_ENABLED__: Whether Windows builds are enabled + """ + content = template_content + + # Replace build number offset + build_offset = repo_config.get('build_number_offset', 0) + content = content.replace('__BUILD_NUMBER_OFFSET__', str(build_offset)) + + # Replace linux/windows enabled flags + linux_enabled = str(repo_config.get('linux_enabled', True)).lower() + windows_enabled = str(repo_config.get('windows_enabled', True)).lower() + content = content.replace('__LINUX_ENABLED__', linux_enabled) + content = content.replace('__WINDOWS_ENABLED__', windows_enabled) + + return content + + +def update_repository_workflow(repo, branch, workflow_template, token, dry_run=False): + """ + Update the workflow file in a specific repository/branch. + """ + print(f"\nProcessing {repo} (branch: {branch})") + + # Read the template file + template_path = workflow_template + if not os.path.exists(template_path): + print(f" Error: Template file not found: {template_path}") + return False + + with open(template_path, 'r') as f: + template_content = f.read() + + # Create a temporary directory for cloning + with tempfile.TemporaryDirectory() as tmpdir: + repo_dir = os.path.join(tmpdir, 'repo') + + # Clone the repository + clone_url = f"https://{token}@github.com/{repo}.git" + print(f" Cloning repository...") + result = run_command( + f"git clone --depth 1 --branch {branch} {clone_url} {repo_dir}", + check=False + ) + + if result.returncode != 0: + print(f" Failed to clone repository (branch might not exist)") + return False + + # Get repository-specific configuration + repo_config = get_repo_config(repo_dir, branch) + print(f" Config: {repo_config}") + + # Apply template substitutions + workflow_content = apply_template_substitutions(template_content, repo_config) + + # Ensure .github/workflows directory exists + workflows_dir = os.path.join(repo_dir, '.github', 'workflows') + os.makedirs(workflows_dir, exist_ok=True) + + # Write the workflow file + workflow_path = os.path.join(workflows_dir, 'build.yml') + + # Check if file needs updating + needs_update = True + if os.path.exists(workflow_path): + with open(workflow_path, 'r') as f: + current_content = f.read() + needs_update = current_content != workflow_content + + if not needs_update: + print(f" Workflow file is already up to date") + return True + + if dry_run: + print(f" [DRY RUN] Would update workflow file") + return True + + with open(workflow_path, 'w') as f: + f.write(workflow_content) + + # Configure git + run_command('git config user.name "nodos-bot"', cwd=repo_dir) + run_command('git config user.email "bot@nodos.dev"', cwd=repo_dir) + + # Check if there are changes + result = run_command('git status --porcelain', cwd=repo_dir) + if not result.stdout.strip(): + print(f" No changes to commit") + return True + + # Commit and push + run_command('git add .github/workflows/build.yml', cwd=repo_dir) + run_command( + 'git commit -m "Update build workflow from actions repository"', + cwd=repo_dir + ) + print(f" Pushing changes...") + run_command(f'git push origin {branch}', cwd=repo_dir) + + print(f" Successfully updated workflow") + return True + + +def main(): + parser = argparse.ArgumentParser( + description='Update plugin repository workflow files from templates' + ) + parser.add_argument( + '--config', + default='repositories.json', + help='Path to repositories configuration file' + ) + parser.add_argument( + '--token', + help='GitHub token for authentication (or set GITHUB_TOKEN env var)' + ) + parser.add_argument( + '--dry-run', + action='store_true', + help='Show what would be done without making changes' + ) + parser.add_argument( + '--repo', + help='Only update this specific repository (format: owner/repo)' + ) + parser.add_argument( + '--branch', + help='Only update this specific branch (requires --repo)' + ) + + args = parser.parse_args() + + # Get GitHub token + token = args.token or os.environ.get('GITHUB_TOKEN') + if not token: + print("Error: GitHub token not provided. Use --token or set GITHUB_TOKEN env var") + sys.exit(1) + + # Read repositories configuration + if not os.path.exists(args.config): + print(f"Error: Configuration file not found: {args.config}") + sys.exit(1) + + with open(args.config, 'r') as f: + config = json.load(f) + + repositories = config.get('repositories', []) + + # Filter by repo/branch if specified + if args.repo: + repositories = [r for r in repositories if r['repo'] == args.repo] + if args.branch: + repositories = [r for r in repositories if r['branch'] == args.branch] + + if not repositories: + print("No repositories to process") + sys.exit(0) + + print(f"Processing {len(repositories)} repository/branch combinations") + if args.dry_run: + print("DRY RUN MODE - No changes will be made") + + success_count = 0 + fail_count = 0 + + for repo_config in repositories: + repo = repo_config['repo'] + branch = repo_config['branch'] + workflow_template = repo_config['workflow_template'] + + try: + success = update_repository_workflow( + repo, + branch, + workflow_template, + token, + dry_run=args.dry_run + ) + if success: + success_count += 1 + else: + fail_count += 1 + except Exception as e: + print(f" Error processing {repo}/{branch}: {e}") + fail_count += 1 + + print(f"\n{'='*60}") + print(f"Summary: {success_count} succeeded, {fail_count} failed") + print(f"{'='*60}") + + if fail_count > 0: + sys.exit(1) + + +if __name__ == '__main__': + main() From 9910c818a2d2776f4fd55d0fabbc4b5f25a2f86d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:13:22 +0000 Subject: [PATCH 3/6] Update README with workflow sync system documentation Co-authored-by: caner-milko <13199909+caner-milko@users.noreply.github.com> --- README.md | 18 +++++++++++++++++- .../update_workflows.cpython-312.pyc | Bin 0 -> 10584 bytes 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 scripts/__pycache__/update_workflows.cpython-312.pyc diff --git a/README.md b/README.md index a4a79ac..3b1bf7b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,20 @@ -# Nodos Action Matrix +# Nodos Actions Repository + +This repository contains GitHub Actions workflows and automation tools for the Nodos project. + +## Plugin Workflow Sync System + +This repository includes an automated system for syncing build workflow files to all plugin repositories. This ensures that all plugins use consistent, up-to-date workflow configurations. + +**Key Features:** +- Templated workflow files for different branches (dev, nodos-1.3, nodos-1.2) +- Repository-specific configuration support (build number offsets, platform toggles) +- Automatic synchronization on template changes +- Manual sync capability for testing and updates + +For detailed information, see [WORKFLOW_SYNC_README.md](WORKFLOW_SYNC_README.md) + +## Build Status Matrix Badges below show the latest GitHub Actions run status for each build workflow on the `dev`, `nodos-1.3`, and `nodos-1.2` branches. diff --git a/scripts/__pycache__/update_workflows.cpython-312.pyc b/scripts/__pycache__/update_workflows.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f29c9d252287a1bfe6dacc0e3cfaa04d73b9a9ad GIT binary patch literal 10584 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 literal 0 HcmV?d00001 From ed49afdba6ee9c87cac4733b8459ca815ebca441 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:13:54 +0000 Subject: [PATCH 4/6] Add .gitignore and remove Python cache files Co-authored-by: caner-milko <13199909+caner-milko@users.noreply.github.com> --- .gitignore | 37 ++++++++++++++++++ .../update_workflows.cpython-312.pyc | Bin 10584 -> 0 bytes 2 files changed, 37 insertions(+) create mode 100644 .gitignore delete mode 100644 scripts/__pycache__/update_workflows.cpython-312.pyc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0610878 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +venv/ +ENV/ +env/ + +# IDEs +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db diff --git a/scripts/__pycache__/update_workflows.cpython-312.pyc b/scripts/__pycache__/update_workflows.cpython-312.pyc deleted file mode 100644 index f29c9d252287a1bfe6dacc0e3cfaa04d73b9a9ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10584 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 From 709bf98a9849246c73c5cdd38f4388d09e23a3c7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:15:47 +0000 Subject: [PATCH 5/6] Address code review feedback: remove unused imports, improve error handling and git auth Co-authored-by: caner-milko <13199909+caner-milko@users.noreply.github.com> --- scripts/update_workflows.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/scripts/update_workflows.py b/scripts/update_workflows.py index d6c2814..1de3415 100755 --- a/scripts/update_workflows.py +++ b/scripts/update_workflows.py @@ -13,8 +13,6 @@ import sys import subprocess import tempfile -import shutil -from pathlib import Path def run_command(cmd, cwd=None, check=True): @@ -35,7 +33,7 @@ def run_command(cmd, cwd=None, check=True): return result -def get_repo_config(repo_path, branch): +def get_repo_config(repo_path): """ Fetch repository-specific configuration from .nodos/workflow_config.json in the plugin repository. @@ -57,7 +55,7 @@ def get_repo_config(repo_path, branch): config = json.load(f) # Merge with defaults return {**default_config, **config} - except Exception as e: + except (json.JSONDecodeError, FileNotFoundError, PermissionError, OSError) as e: print(f" Error reading config file: {e}, using defaults") return default_config @@ -106,11 +104,26 @@ def update_repository_workflow(repo, branch, workflow_template, token, dry_run=F repo_dir = os.path.join(tmpdir, 'repo') # Clone the repository - clone_url = f"https://{token}@github.com/{repo}.git" + # Note: Token is passed via environment variable to avoid exposure in logs + clone_url = f"https://github.com/{repo}.git" print(f" Cloning repository...") - result = run_command( - f"git clone --depth 1 --branch {branch} {clone_url} {repo_dir}", - check=False + + # Configure git credentials temporarily + env = os.environ.copy() + env['GIT_TERMINAL_PROMPT'] = '0' + + result = subprocess.run( + [ + 'git', 'clone', + '--depth', '1', + '--branch', branch, + f'https://x-access-token:{token}@github.com/{repo}.git', + repo_dir + ], + capture_output=True, + text=True, + check=False, + env=env ) if result.returncode != 0: @@ -118,7 +131,7 @@ def update_repository_workflow(repo, branch, workflow_template, token, dry_run=F return False # Get repository-specific configuration - repo_config = get_repo_config(repo_dir, branch) + repo_config = get_repo_config(repo_dir) print(f" Config: {repo_config}") # Apply template substitutions From 41be49d6cedbd1a4d4675fc865cdf1f44306c6f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:17:15 +0000 Subject: [PATCH 6/6] Add explicit permissions to update_workflow to fix security issue Co-authored-by: caner-milko <13199909+caner-milko@users.noreply.github.com> --- .github/workflows/update_workflow.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/update_workflow.yml b/.github/workflows/update_workflow.yml index f001975..9467cf2 100644 --- a/.github/workflows/update_workflow.yml +++ b/.github/workflows/update_workflow.yml @@ -31,6 +31,8 @@ jobs: update-workflows: name: Update Plugin Repository Workflows runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout actions repository