Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more hooks #27

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
27 changes: 23 additions & 4 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,29 @@ relative to the base of the repo; other paths are relative to that root
arbitrary labels to you projects, which is useful when using the
`info` command.
- `hooks`: (optional) A set of hooks that run at certain points of the
release process. Currently, only the `post_write` hook is supported:
this hook runs after local file changes are made, but before any VCS
commits/push/tagging is performed; it's useful to make additional
file changes that need to be committed with the release.
release process. Hooks are not run if the `dry-run` or
`changelog-only` flags are set. Note that commits, tags, and other
release operations are not executed on a project-by-project basis,
so all project hooks of the same type will be run together. Here are
the hooks you can use:
- `pre_begin`: runs before any other release activity is performed.
You can use this hook to perform any preperation for the release
process.
- `pre_write`: runs before any data is written to the local
filesystem; you can use this to prep files or record the fs state.
- `post_write`: runs after local file changes are made,
but before any VCS commits/push/tagging is performed; it's useful
to make additional file changes that need to be committed with the
release.
- `post_commit`: runs after local file changes are committed and/or
pushed to the VCS, but before tags are added/changed. Use this if
you want to perform additional VCS operations before tagging.
- `post_tag`: runs after tags are added/changed and pushed to the
VCS. Useful if you want to add your own tags, or perform final VCS
operations.
- `post_end`: runs after any other release activity. Use this if you
have cleanup operations that you want to run after your release is
done.

- `commit`

Expand Down
27 changes: 27 additions & 0 deletions docs/use_cases.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,31 @@ directories or files listed in any `.gitignore` files. If you want to
include projects in hidden or ignored locations, you'll have to add
those by hand to the resulting `.versio.yaml` file.

## Perform a Release

This is the most commonly-used command: `release` will scan for
conventional commits, increment all project version numbers accordingly,
update changelogs, add and move tags, and commit and push all changes.

```
$ versio release
```

### Release dry-run

You can run `versio -l local -c release -d` to run a "dry-run" release,
which won't actually write or commit anything, but will print out the
new version numbers that are expected. Using `-l local -c` will cause
versio to run only on the local repository, and ignore problems with
local changes: no network or remote operations will be consulted (see
[VCS Levels](./vcs_levels.md)). This command can be used while
performing edits to see that changes have the expected effect on a
project version.

Note that the actual release may calculate different version numbers
than any given dry-run, especially if the configuration, network, or
commit/PR history is different than found in the dry-run environment.

## Gitflow / Oneflow

If you're using
Expand Down Expand Up @@ -286,6 +311,7 @@ jobs:
run: versio check
- name: Print changes
run: versio plan
- any other pr actions...
```

## CI Release
Expand Down Expand Up @@ -325,4 +351,5 @@ jobs:
run: git fetch --unshallow
- name: Generate release
run: versio release
- any other release actions...
```
7 changes: 5 additions & 2 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::errors::{Context as _, Result};
use crate::git::Repo;
use crate::mono::{Mono, Plan};
use crate::output::{Output, ProjLine};
use crate::state::{CommitState, StateRead};
use crate::state::{CommitState, ResumeArgs, StateRead};
use crate::template::read_template;
use crate::vcs::{VcsLevel, VcsRange, VcsState};
use schemars::schema_for;
Expand Down Expand Up @@ -397,6 +397,7 @@ pub async fn release(

pub fn resume(user_pref_vcs: Option<VcsRange>) -> Result<()> {
let vcs = combine_vcs(user_pref_vcs, VcsLevel::None, VcsLevel::Smart, VcsLevel::Local, VcsLevel::Smart)?;

let output = Output::new();
let mut output = output.resume();

Expand All @@ -409,8 +410,10 @@ pub fn resume(user_pref_vcs: Option<VcsRange>) -> Result<()> {
remove_file(".versio-paused")?;
commit
};

let repo = Repo::open(".", VcsState::new(vcs.max(), false), commit.commit_config().clone())?;
commit.resume(&repo)?;
let file = ConfigFile::from_dir(repo.root())?;
commit.resume(&repo, ResumeArgs::new(&file.hooks()))?;

output.write_done()?;
output.commit()?;
Expand Down
5 changes: 5 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,12 @@ impl HookSet {
Ok(())
}

pub fn execute_pre_begin(&self, root: &Option<&String>) -> Result<()> { self.execute("pre_begin", root) }
pub fn execute_pre_write(&self, root: &Option<&String>) -> Result<()> { self.execute("pre_write", root) }
pub fn execute_post_write(&self, root: &Option<&String>) -> Result<()> { self.execute("post_write", root) }
pub fn execute_post_commit(&self, root: &Option<&String>) -> Result<()> { self.execute("post_commit", root) }
pub fn execute_post_tag(&self, root: &Option<&String>) -> Result<()> { self.execute("post_tag", root) }
pub fn execute_post_end(&self, root: &Option<&String>) -> Result<()> { self.execute("post_end", root) }
}

impl<'de> Deserialize<'de> for HookSet {
Expand Down
10 changes: 10 additions & 0 deletions src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl Repo {
// returns successfully at the Smart level.

pub fn commit_config(&self) -> &CommitConfig { &self.commit_config }
pub fn root(&self) -> &Path { self.vcs.root() }

/// Return the vcs level that this repository can support.
pub fn detect<P: AsRef<Path>>(path: P) -> Result<VcsLevel> {
Expand Down Expand Up @@ -822,6 +823,15 @@ impl GitVcsLevel {
VcsLevel::Smart => GitVcsLevel::Smart { repo, branch_name, remote_name, fetches }
}
}

fn root(&self) -> &Path {
match self {
Self::None { root } => root,
Self::Local { repo, .. } => repo.workdir().unwrap(),
Self::Remote { repo, .. } => repo.workdir().unwrap(),
Self::Smart { repo, .. } => repo.workdir().unwrap()
}
}
}

/// A git commit hash-like (hash, branch, tag, etc) to revwalk "from" (a.k.a. "hide"), or none if the hash-like
Expand Down
63 changes: 53 additions & 10 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,38 +190,50 @@ impl StateWrite {
Ok(())
}

pub fn commit(&mut self, repo: &Repo, data: CommitArgs) -> Result<()> {
pub fn commit(&mut self, repo: &Repo, args: CommitArgs) -> Result<()> {
for proj_id in &self.proj_writes {
if let Some((root, hooks)) = args.hooks.get(proj_id) {
hooks.execute_pre_begin(root)?;
}
}

for proj_id in &self.proj_writes {
if let Some((root, hooks)) = args.hooks.get(proj_id) {
hooks.execute_pre_write(root)?;
}
}
Comment on lines +194 to +204
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need two hooks that are in the same place but different name?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does seem a little weird, but the idea is that the hooks are semantically different. Long term goal would be that the pre-begin hook runs on all projects on every release, whereas the pre-write hook runs only on projects that actually will write something. Also, if there later exists some hook-able action that occurs before write, the pre-write hook will come after that, but pre-begin will still come before it. Finally, because hooks are all run together, this will give a user to have some control over when their hooks will run in relation to each other.


for write in &self.writes {
write.write()?;
}
let did_write = !self.writes.is_empty();
self.writes.clear();

for proj_id in &self.proj_writes {
if let Some((root, hooks)) = data.hooks.get(proj_id) {
if let Some((root, hooks)) = args.hooks.get(proj_id) {
hooks.execute_post_write(root)?;
}
}

let me = take(self);
let prev_tag = data.prev_tag.to_string();
let last_commits = data.last_commits.clone();
let old_tags = data.old_tags.clone();
let prev_tag = args.prev_tag.to_string();
let last_commits = args.last_commits.clone();
let old_tags = args.old_tags.clone();
let mut commit_state = CommitState::new(
me,
did_write,
prev_tag,
last_commits,
old_tags,
data.advance_prev,
args.advance_prev,
repo.commit_config().clone()
);

if data.pause {
if args.pause {
let file = OpenOptions::new().create(true).write(true).truncate(true).open(".versio-paused")?;
Ok(serde_json::to_writer(file, &commit_state)?)
} else {
commit_state.resume(repo)
commit_state.resume(repo, args.into_resume_args())
}
}
}
Expand All @@ -242,6 +254,18 @@ impl<'a> CommitArgs<'a> {
) -> CommitArgs<'a> {
CommitArgs { prev_tag, last_commits, old_tags, advance_prev, hooks, pause }
}

pub fn into_resume_args(self) -> ResumeArgs<'a> { ResumeArgs { hooks: self.hooks } }
}

pub struct ResumeArgs<'a> {
hooks: &'a HashMap<ProjectId, (Option<&'a String>, &'a HookSet)>
}

impl<'a> ResumeArgs<'a> {
pub fn new(hooks: &'a HashMap<ProjectId, (Option<&'a String>, &'a HookSet)>) -> ResumeArgs<'a> {
ResumeArgs { hooks }
}
}

fn fill_from_old(old: &HashMap<ProjectId, String>, new_tags: &mut HashMap<ProjectId, String>) {
Expand Down Expand Up @@ -274,14 +298,20 @@ impl CommitState {

pub fn commit_config(&self) -> &CommitConfig { &self.commit_config }

pub fn resume(&mut self, repo: &Repo) -> Result<()> {
pub fn resume(&mut self, repo: &Repo, args: ResumeArgs) -> Result<()> {
if self.did_write {
trace!("Wrote files, so committing.");
repo.commit()?;
} else {
trace!("No files written, so not committing.");
}

for proj_id in &self.write.proj_writes {
if let Some((root, hooks)) = args.hooks.get(proj_id) {
hooks.execute_post_commit(root)?;
}
}

for tag in &self.write.tag_head {
repo.update_tag_head(tag)?;
}
Expand All @@ -298,7 +328,6 @@ impl CommitState {
}
}
self.write.tag_head_or_last.clear();
self.write.proj_writes.clear();

for (tag, oid) in &self.write.tag_commit {
repo.update_tag(tag, oid)?;
Expand All @@ -311,6 +340,20 @@ impl CommitState {
repo.update_tag_head_anno(&self.prev_tag, &msg)?;
}

for proj_id in &self.write.proj_writes {
if let Some((root, hooks)) = args.hooks.get(proj_id) {
hooks.execute_post_tag(root)?;
}
}

for proj_id in &self.write.proj_writes {
if let Some((root, hooks)) = args.hooks.get(proj_id) {
hooks.execute_post_end(root)?;
}
}
Comment on lines +343 to +353
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(see above)


self.write.proj_writes.clear();

Ok(())
}
}
Expand Down