Skip to content

Commit b5c22f1

Browse files
committed
Add optional post-build hook
1 parent 0916361 commit b5c22f1

File tree

2 files changed

+74
-13
lines changed

2 files changed

+74
-13
lines changed

cli/src/config.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ pub struct Config {
273273
pub provider: ProviderConfig,
274274
pub programs: ProgramsConfig,
275275
pub scripts: ScriptsConfig,
276+
pub hooks: Option<HooksConfig>,
276277
pub workspace: WorkspaceConfig,
277278
// Separate entry next to test_config because
278279
// "anchor localnet" only has access to the Anchor.toml,
@@ -308,6 +309,16 @@ pub struct ProviderConfig {
308309

309310
pub type ScriptsConfig = BTreeMap<String, String>;
310311

312+
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
313+
pub struct HooksConfig {
314+
pub pre_build: Option<String>,
315+
pub post_build: Option<String>,
316+
pub pre_test: Option<String>,
317+
pub post_test: Option<String>,
318+
pub pre_deploy: Option<String>,
319+
pub post_deploy: Option<String>,
320+
}
321+
311322
pub type ProgramsConfig = BTreeMap<Cluster, BTreeMap<String, ProgramDeployment>>;
312323

313324
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
@@ -412,6 +423,7 @@ struct _Config {
412423
provider: Provider,
413424
workspace: Option<WorkspaceConfig>,
414425
scripts: Option<ScriptsConfig>,
426+
hooks: Option<HooksConfig>,
415427
test: Option<_TestValidator>,
416428
}
417429

@@ -445,6 +457,7 @@ impl ToString for Config {
445457
true => None,
446458
false => Some(self.scripts.clone()),
447459
},
460+
hooks: self.hooks.clone(),
448461
programs,
449462
workspace: (!self.workspace.members.is_empty() || !self.workspace.exclude.is_empty())
450463
.then(|| self.workspace.clone()),
@@ -470,6 +483,7 @@ impl FromStr for Config {
470483
wallet: shellexpand::tilde(&cfg.provider.wallet).parse()?,
471484
},
472485
scripts: cfg.scripts.unwrap_or_default(),
486+
hooks: cfg.hooks,
473487
test_validator: cfg.test.map(Into::into),
474488
test_config: None,
475489
programs: cfg.programs.map_or(Ok(BTreeMap::new()), deser_programs)?,

cli/src/lib.rs

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,9 @@ pub fn build(
755755
}
756756

757757
let cfg = Config::discover(cfg_override)?.expect("Not in workspace.");
758+
759+
try_run_hook(&cfg, HookType::PreBuild)?;
760+
758761
let build_config = BuildConfig {
759762
verifiable,
760763
solana_version: solana_version.or_else(|| cfg.solana_version.clone()),
@@ -822,6 +825,8 @@ pub fn build(
822825

823826
set_workspace_dir_or_exit();
824827

828+
try_run_hook(&cfg, HookType::PostBuild)?;
829+
825830
Ok(())
826831
}
827832

@@ -1848,6 +1853,9 @@ fn test(
18481853
if (!is_localnet || skip_local_validator) && !skip_deploy {
18491854
deploy(cfg_override, None, None)?;
18501855
}
1856+
1857+
try_run_hook(&cfg, HookType::PreTest)?;
1858+
18511859
let mut is_first_suite = true;
18521860
if cfg.scripts.get("test").is_some() {
18531861
is_first_suite = false;
@@ -1892,6 +1900,9 @@ fn test(
18921900
)?;
18931901
}
18941902
}
1903+
1904+
try_run_hook(&cfg, HookType::PostTest)?;
1905+
18951906
Ok(())
18961907
})
18971908
}
@@ -2357,6 +2368,8 @@ fn deploy(
23572368
let url = cluster_url(cfg, &cfg.test_validator);
23582369
let keypair = cfg.provider.wallet.to_string();
23592370

2371+
try_run_hook(&cfg, HookType::PreDeploy)?;
2372+
23602373
// Deploy the programs.
23612374
println!("Deploying workspace: {}", url);
23622375
println!("Upgrade authority: {}", keypair);
@@ -2418,6 +2431,8 @@ fn deploy(
24182431

24192432
println!("Deploy success");
24202433

2434+
try_run_hook(&cfg, HookType::PostDeploy)?;
2435+
24212436
Ok(())
24222437
})
24232438
}
@@ -2767,27 +2782,59 @@ fn shell(cfg_override: &ConfigOverride) -> Result<()> {
27672782

27682783
fn run(cfg_override: &ConfigOverride, script: String) -> Result<()> {
27692784
with_workspace(cfg_override, |cfg| {
2770-
let url = cluster_url(cfg, &cfg.test_validator);
27712785
let script = cfg
27722786
.scripts
27732787
.get(&script)
27742788
.ok_or_else(|| anyhow!("Unable to find script"))?;
2775-
let exit = std::process::Command::new("bash")
2776-
.arg("-c")
2777-
.arg(&script)
2778-
.env("ANCHOR_PROVIDER_URL", url)
2779-
.env("ANCHOR_WALLET", cfg.provider.wallet.to_string())
2780-
.stdout(Stdio::inherit())
2781-
.stderr(Stdio::inherit())
2782-
.output()
2783-
.unwrap();
2784-
if !exit.status.success() {
2785-
std::process::exit(exit.status.code().unwrap_or(1));
2786-
}
2789+
run_bash_cmd(&cfg, script)?;
27872790
Ok(())
27882791
})
27892792
}
27902793

2794+
#[derive(Debug, Clone, Serialize, Deserialize)]
2795+
pub enum HookType {
2796+
PreBuild,
2797+
PostBuild,
2798+
PreTest,
2799+
PostTest,
2800+
PreDeploy,
2801+
PostDeploy,
2802+
}
2803+
2804+
fn try_run_hook(cfg: &Config, hook_type: HookType) -> Result<()> {
2805+
if let Some(hooks) = &cfg.hooks {
2806+
let cmd = match hook_type {
2807+
HookType::PreBuild => &hooks.pre_build,
2808+
HookType::PostBuild => &hooks.post_build,
2809+
HookType::PreTest => &hooks.pre_test,
2810+
HookType::PostTest => &hooks.post_test,
2811+
HookType::PreDeploy => &hooks.pre_deploy,
2812+
HookType::PostDeploy => &hooks.post_deploy,
2813+
};
2814+
if let Some(cmd) = &cmd {
2815+
run_bash_cmd(&cfg, cmd)?;
2816+
};
2817+
};
2818+
Ok(())
2819+
}
2820+
2821+
fn run_bash_cmd(cfg: &Config, cmd: &String) -> Result<()> {
2822+
let url = cluster_url(cfg, &cfg.test_validator);
2823+
let exit = std::process::Command::new("bash")
2824+
.arg("-c")
2825+
.arg(cmd)
2826+
.env("ANCHOR_PROVIDER_URL", url)
2827+
.env("ANCHOR_WALLET", cfg.provider.wallet.to_string())
2828+
.stdout(Stdio::inherit())
2829+
.stderr(Stdio::inherit())
2830+
.output()
2831+
.unwrap();
2832+
if !exit.status.success() {
2833+
std::process::exit(exit.status.code().unwrap_or(1));
2834+
}
2835+
Ok(())
2836+
}
2837+
27912838
fn login(_cfg_override: &ConfigOverride, token: String) -> Result<()> {
27922839
let dir = shellexpand::tilde("~/.config/anchor");
27932840
if !Path::new(&dir.to_string()).exists() {

0 commit comments

Comments
 (0)