| name | add-sdk-method |
| description | Guide for adding a new public method to the Deployer SDK facade, covering delegation in deployer.rs, the SdkError variant, re-exports in lib.rs, and a matching integration-test module. Triggers on "add sdk method", "new deployer method", "extend the sdk", "add method to deployer", "implement sdk operation", or "expose new operation in sdk". |
| metadata | {"author":"torrust","version":"1.0"} |
Add an SDK Method
Every new capability the SDK exposes follows the same four-step pattern:
- Add the delegation method to
packages/sdk/src/deployer.rs.
- Add the
SdkError variant to packages/sdk/src/error.rs.
- Re-export every new public type through
packages/sdk/src/lib.rs.
- Add an integration-test module in
packages/sdk/tests/local_operations/.
Read the existing method implementations before starting — they are the
authoritative reference for the patterns this skill describes.
Quick Decision Tree
- Does an application-layer
CommandHandler for this operation already exist
in torrust_tracker_deployer_lib? → yes → follow this guide.
- Do you need a new application handler too? → create it first (see
.github/skills/dev/cli/add-new-command/skill.md), then return here.
Phase 1: Add the Delegation Method to deployer.rs
Goal: expose the operation as a pub fn on Deployer that wires up the
application handler using the deployer's internal dependencies.
What to build
Open packages/sdk/src/deployer.rs and add your method following the existing
pattern. Every method:
- Creates a handler instance from
self's dependency fields.
- Calls
handler.execute(…).
- Maps the result to a public SDK type.
use torrust_tracker_deployer_lib::application::command_handlers::my_command::{
MyCommandHandler, MyCommandHandlerError,
};
pub fn my_operation(
&self,
name: &EnvironmentName,
) -> Result<MyOutput, MyCommandHandlerError> {
let handler = MyCommandHandler::new(
self.repository.clone() as Arc<dyn EnvironmentRepository>,
);
handler.execute(name, &self.working_dir)
}
Infrastructure operations (provision, configure, release, run, test) receive
additional dependencies (repository_factory, data_directory, listener).
Compare with provision() or configure() in the same file for that pattern.
Test
cargo build -p torrust-tracker-deployer-sdk
Expected: compiles without errors (the handler error type is not yet in
SdkError, so cargo test may still fail — that is addressed in Phase 2).
Phase 2: Add the SdkError Variant and Re-exports
Goal: surface the new error type and any new public types through the SDK's
unified API.
2a — SdkError variant
Open packages/sdk/src/error.rs and add a variant:
#[error(transparent)]
MyOperation(#[from] MyCommandHandlerError),
Follow the #[from] pattern used by all other variants so ? works
transparently in deployer.rs.
2b — Re-exports in lib.rs
Open packages/sdk/src/lib.rs and re-export every new type that appears in
method signatures (inputs and outputs). Do not export internal
implementation types.
pub use torrust_tracker_deployer_lib::application::command_handlers::my_command::{
MyCommandHandlerError,
MyOutput,
};
Test
cargo build -p torrust-tracker-deployer-sdk
cargo test -p torrust-tracker-deployer-sdk --doc
Expected: library compiles; doc-tests in module-level examples pass.
Phase 3: Add the Integration-Test Module
Goal: prove the new method works end-to-end using only the public SDK API.
For full guidance on the test structure and shared helpers, load the companion
skill: .github/skills/dev/sdk/write-sdk-integration-test/skill.md.
Quick summary
-
Create the file: packages/sdk/tests/local_operations/my_command.rs
-
Every test function uses the naming convention:
it_should_{behavior}_when_{condition}.
-
Use the shared helpers from
packages/sdk/tests/local_operations/main.rs:
deployer_in_temp_dir() — isolated workspace per test.
minimal_config(name) — minimal EnvironmentCreationConfig.
create_environment(deployer, name) — create and unwrap.
assert_environment_exists(deployer, name) /
assert_environment_not_exists(deployer, name).
-
Declare the module in main.rs:
mod my_command;
Minimal example module:
use crate::{create_environment, deployer_in_temp_dir};
#[test]
fn it_should_succeed_when_environment_exists() {
let (deployer, _tmp) = deployer_in_temp_dir();
let name = create_environment(&deployer, "my-op-test");
let result = deployer.my_operation(&name);
assert!(result.is_ok(), "my_operation failed: {:?}", result.err());
}
Test
cargo test -p torrust-tracker-deployer-sdk
Expected: all existing tests plus the new ones pass.
Phase 4: Run All Checks
cargo run --bin linter all
cargo test
Fix any linting issues before committing.
Commit
Follow the commit conventions in .github/skills/dev/git-workflow/commit-changes/skill.md.
Typical subject line:
feat(sdk): add Deployer::my_operation method
Group in a single commit:
packages/sdk/src/deployer.rs
packages/sdk/src/error.rs
packages/sdk/src/lib.rs
packages/sdk/tests/local_operations/main.rs
packages/sdk/tests/local_operations/my_command.rs