# Install Packs Workflow # Complete workflow for installing packs from multiple sources with dependency resolution name: install_packs ref: core.install_packs label: "Install Packs" description: "Install one or more packs from git repositories, HTTP archives, or pack registry with automatic dependency resolution" version: "1.0.0" # Input parameters (StackStorm-style with inline required/secret) parameters: packs: type: array description: "List of packs to install (git URLs, HTTP URLs, or pack refs like 'slack@1.0.0')" items: type: string minItems: 1 required: true ref_spec: type: string description: "Git reference to checkout for git URLs (branch, tag, or commit)" skip_dependencies: type: boolean description: "Skip installing pack dependencies" default: false skip_tests: type: boolean description: "Skip running pack tests before registration" default: false skip_env_build: type: boolean description: "Skip building runtime environments (Python/Node.js)" default: false force: type: boolean description: "Force installation even if packs already exist or tests fail" default: false registry_url: type: string description: "Pack registry URL for resolving pack refs" default: "https://registry.attune.io/index.json" packs_base_dir: type: string description: "Base directory for permanent pack storage" default: "/opt/attune/packs" api_url: type: string description: "Attune API URL" default: "http://localhost:8080" timeout: type: integer description: "Timeout in seconds for the entire workflow" default: 1800 minimum: 300 maximum: 7200 # Workflow variables vars: - temp_dir: null - downloaded_packs: [] - missing_dependencies: [] - installed_pack_refs: [] - failed_packs: [] - start_time: null # Workflow tasks tasks: # Task 1: Initialize workflow - name: initialize action: core.noop input: message: "Starting pack installation workflow" publish: - start_time: "{{ now() }}" - temp_dir: "/tmp/attune-pack-install-{{ uuid() }}" on_success: download_packs # Task 2: Download packs from specified sources - name: download_packs action: core.download_packs input: packs: "{{ parameters.packs }}" destination_dir: "{{ workflow.temp_dir }}" registry_url: "{{ parameters.registry_url }}" ref_spec: "{{ parameters.ref_spec }}" api_url: "{{ parameters.api_url }}" timeout: 300 verify_ssl: true publish: - downloaded_packs: "{{ task.download_packs.result.downloaded_packs }}" - failed_packs: "{{ task.download_packs.result.failed_packs }}" on_success: - when: "{{ task.download_packs.result.success_count > 0 }}" do: check_download_results on_failure: cleanup_on_failure # Task 3: Check if any packs were successfully downloaded - name: check_download_results action: core.noop input: message: "Downloaded {{ task.download_packs.result.success_count }} pack(s)" on_success: - when: "{{ not parameters.skip_dependencies }}" do: get_dependencies - when: "{{ parameters.skip_dependencies }}" do: build_environments # Task 4: Get pack dependencies from pack.yaml files - name: get_dependencies action: core.get_pack_dependencies input: pack_paths: "{{ workflow.downloaded_packs | map(attribute='pack_path') | list }}" api_url: "{{ parameters.api_url }}" skip_validation: false publish: - missing_dependencies: "{{ task.get_dependencies.result.missing_dependencies }}" on_success: - when: "{{ task.get_dependencies.result.missing_dependencies | length > 0 }}" do: install_dependencies - when: "{{ task.get_dependencies.result.missing_dependencies | length == 0 }}" do: build_environments on_failure: cleanup_on_failure # Task 5: Recursively install missing pack dependencies - name: install_dependencies action: core.install_packs input: packs: "{{ workflow.missing_dependencies | map(attribute='pack_ref') | list }}" skip_dependencies: false skip_tests: "{{ parameters.skip_tests }}" skip_env_build: "{{ parameters.skip_env_build }}" force: "{{ parameters.force }}" registry_url: "{{ parameters.registry_url }}" packs_base_dir: "{{ parameters.packs_base_dir }}" api_url: "{{ parameters.api_url }}" timeout: 900 publish: - installed_pack_refs: "{{ task.install_dependencies.result.registered_packs | map(attribute='pack_ref') | list }}" on_success: build_environments on_failure: - when: "{{ parameters.force }}" do: build_environments - when: "{{ not parameters.force }}" do: cleanup_on_failure # Task 6: Build runtime environments (Python virtualenvs, npm install) - name: build_environments action: core.build_pack_envs input: pack_paths: "{{ workflow.downloaded_packs | map(attribute='pack_path') | list }}" packs_base_dir: "{{ parameters.packs_base_dir }}" python_version: "3.11" nodejs_version: "20" skip_python: false skip_nodejs: false force_rebuild: "{{ parameters.force }}" timeout: 600 on_success: - when: "{{ not parameters.skip_tests }}" do: run_tests - when: "{{ parameters.skip_tests }}" do: register_packs on_failure: - when: "{{ parameters.force or parameters.skip_env_build }}" do: - when: "{{ not parameters.skip_tests }}" next: run_tests - when: "{{ parameters.skip_tests }}" next: register_packs - when: "{{ not parameters.force and not parameters.skip_env_build }}" do: cleanup_on_failure # Task 7: Run pack tests to verify functionality - name: run_tests action: core.run_pack_tests input: pack_paths: "{{ workflow.downloaded_packs | map(attribute='pack_path') | list }}" timeout: 300 fail_on_error: false on_success: register_packs on_failure: - when: "{{ parameters.force }}" do: register_packs - when: "{{ not parameters.force }}" do: cleanup_on_failure # Task 8: Register packs in database and copy to permanent storage - name: register_packs action: core.register_packs input: pack_paths: "{{ workflow.downloaded_packs | map(attribute='pack_path') | list }}" packs_base_dir: "{{ parameters.packs_base_dir }}" skip_validation: false skip_tests: "{{ parameters.skip_tests }}" force: "{{ parameters.force }}" api_url: "{{ parameters.api_url }}" on_success: cleanup_success on_failure: cleanup_on_failure # Task 9: Cleanup temporary directory on success - name: cleanup_success action: core.noop input: message: "Pack installation completed successfully. Cleaning up temporary directory: {{ workflow.temp_dir }}" publish: - cleanup_status: "success" # Task 10: Cleanup temporary directory on failure - name: cleanup_on_failure action: core.noop input: message: "Pack installation failed. Cleaning up temporary directory: {{ workflow.temp_dir }}" publish: - cleanup_status: "failed" # Output schema output_schema: registered_packs: type: array description: "Successfully registered packs" items: type: object properties: pack_ref: type: string pack_id: type: integer pack_version: type: string storage_path: type: string components_count: type: integer failed_packs: type: array description: "Packs that failed to install" items: type: object properties: source: type: string error: type: string stage: type: string installed_dependencies: type: array description: "Pack dependencies that were installed" items: type: string summary: type: object description: "Installation summary" properties: total_requested: type: integer success_count: type: integer failure_count: type: integer dependencies_installed: type: integer duration_seconds: type: integer # Metadata metadata: description: | This workflow orchestrates the complete pack installation process: 1. Download Packs: Downloads packs from git repositories, HTTP archives, or pack registry 2. Get Dependencies: Analyzes pack.yaml files to identify dependencies 3. Install Dependencies: Recursively installs missing pack dependencies 4. Build Environments: Creates Python virtualenvs, installs requirements.txt and package.json deps 5. Run Tests: Executes pack test suites (if present and not skipped) 6. Register Packs: Loads pack components into database and copies to permanent storage The workflow supports: - Multiple pack sources (git URLs, HTTP archives, pack refs) - Automatic dependency resolution (recursive) - Runtime environment setup (Python, Node.js) - Pack testing before registration - Force mode to override validation failures - Comprehensive error handling and cleanup examples: - name: "Install pack from git repository" input: packs: - "https://github.com/attune/pack-slack.git" ref_spec: "v1.0.0" skip_dependencies: false skip_tests: false force: false - name: "Install multiple packs from registry" input: packs: - "slack@1.0.0" - "aws@2.1.0" - "kubernetes@3.0.0" skip_dependencies: false skip_tests: false force: false - name: "Install pack with force mode (skip validations)" input: packs: - "https://github.com/myorg/pack-custom.git" ref_spec: "main" skip_dependencies: true skip_tests: true force: true - name: "Install from HTTP archive" input: packs: - "https://example.com/packs/custom-pack.tar.gz" skip_dependencies: false skip_tests: false force: false tags: - pack - installation - workflow - automation - dependencies - git - registry