Skip to content

Commit

Permalink
fix: add info cmd and premerge compat
Browse files Browse the repository at this point in the history
Add the 'info' subcommand, better PR handling for premerge checks, and
make some minor github workflow changes.
  • Loading branch information
chaaz committed Sep 17, 2020
1 parent 7e87eed commit a7140f6
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 62 deletions.
2 changes: 0 additions & 2 deletions .github/snippets/matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ value:
- name: Find cargo matrix
id: find-cargo-matrix
run: 'echo "::set-output name=matrix::{\"include\": $(versio -l none info -i 0 -R -N)}"'
- name: debug
run: 'echo "::debug::{\"include\": $(versio -l none info -i 0 -R -N)}"'
- name: Find all matrix
id: find-all-matrix
run: 'echo "::set-output name=matrix::{\"include\": $(versio -l none info -a -R -N)}"'
2 changes: 0 additions & 2 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ jobs:
- name: Find cargo matrix
id: find-cargo-matrix
run: "echo \"::set-output name=matrix::{\\\"include\\\": $(versio -l none info -i 0 -R -N)}\""
- name: debug
run: "echo \"::debug::{\\\"include\\\": $(versio -l none info -i 0 -R -N)}\""
- name: Find all matrix
id: find-all-matrix
run: "echo \"::set-output name=matrix::{\\\"include\\\": $(versio -l none info -a -R -N)}\""
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ jobs:
- name: Find cargo matrix
id: find-cargo-matrix
run: "echo \"::set-output name=matrix::{\\\"include\\\": $(versio -l none info -i 0 -R -N)}\""
- name: debug
run: "echo \"::debug::{\\\"include\\\": $(versio -l none info -i 0 -R -N)}\""
- name: Find all matrix
id: find-all-matrix
run: "echo \"::set-output name=matrix::{\\\"include\\\": $(versio -l none info -a -R -N)}\""
Expand Down
24 changes: 24 additions & 0 deletions docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ versio
│  └─ ... . . . . . . . . src and unit tests
├─ tests
│ └─ ... . . . . . . . . integration tests
└─ .github
└─ ... . . . . . . . . GitHub Actions
```

<!--
Expand Down Expand Up @@ -148,6 +150,28 @@ shouldn't be unit tested, if the reason isn't obvious.
To run service tests, run the `builds/test/service-tests.sh` script,
which runs versio and tests in a docker container.

## GitHub Actions

Versio uses
[Yambler](https://github.com/chaaz/versio-actions/tree/main/yambler) in
order to more easily handle repetitive GitHub Actions. The main
workflows are saved in `.github/workflows-src/` and snippets in
`.github/snippets/`. When you create or change workflows, just run the
script `yamble-repo.sh` (available from
[here](https://github.com/chaaz/versio-actions/blob/main/scripts/yamble-repo.sh))
which generates workflow files into `~/.github/workflows`.

**DON'T EDIT THE WORKFLOW FILES DIRECTLY**. You should only edit the
workflow sources in `workflow-src`, or the snippets in `snippets`, and
then run the `yamble-repo` script. You will still need to
add/commit/push the generated files in `workflow`, however, in order for
GitHub Actions to use them.

As mentioned in the Yambler README, you can copy the companion script
`yamble-repo-pre-push.sh` to a file named `.git/hooks/pre-push` in your
local copy of the `versio` repo. This will ensure that your workflows
are synced before you push them up.

## Platform-specific help

[platform-specific help]: #platform-specific-help
Expand Down
56 changes: 56 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,56 @@ pub fn execute(info: &EarlyInfo) -> Result<()> {
)
.display_order(1)
)
.subcommand(
SubCommand::with_name("info")
.setting(AppSettings::UnifiedHelpMessage)
.about("Print info about projects")
.arg(
Arg::with_name("id")
.short("i")
.long("id")
.takes_value(true)
.value_name("id")
.multiple(true)
.number_of_values(1)
.min_values(1)
.display_order(1)
.help("Info on project ID")
)
.arg(
Arg::with_name("name")
.short("n")
.long("name")
.takes_value(true)
.value_name("name")
.multiple(true)
.number_of_values(1)
.min_values(1)
.display_order(1)
.help("Info on project name")
)
.arg(
Arg::with_name("all").short("a").long("all").takes_value(false).display_order(1).help("Info on all projects")
)
.group(ArgGroup::with_name("which").args(&["id", "name", "all"]).required(false))
.arg(
Arg::with_name("showroot")
.short("R")
.long("show-root")
.takes_value(false)
.display_order(1)
.help("Show the project(s) root")
)
.arg(
Arg::with_name("showname")
.short("N")
.long("show-name")
.takes_value(false)
.display_order(1)
.help("Show the project(s) name")
)
.display_order(1)
)
.get_matches();

parse_matches(m)
Expand All @@ -248,6 +298,12 @@ fn parse_matches(m: ArgMatches) -> Result<()> {
("plan", Some(_)) => plan(pref_vcs)?,
("release", Some(m)) => release(pref_vcs, m.is_present("all"), m.is_present("dry"))?,
("init", Some(m)) => init(m.value_of("maxdepth").map(|d| d.parse().unwrap()).unwrap_or(5))?,
("info", Some(m)) => {
let names = m.values_of("name").map(|v| v.collect::<Vec<_>>());
let ids =
m.values_of("id").map(|v| v.map(|i| i.parse()).collect::<std::result::Result<Vec<_>, _>>()).transpose()?;
info(pref_vcs, ids, names, m.is_present("all"), m.is_present("showname"), m.is_present("showroot"))?
}
("", _) => empty_cmd()?,
(c, _) => unknown_cmd(c)?
}
Expand Down
39 changes: 38 additions & 1 deletion src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! The command-line options for the executable.
use crate::config::{Config, ConfigFile, Size};
use crate::config::{Config, ConfigFile, ProjectId, Size};
use crate::errors::{Result, ResultExt};
use crate::git::Repo;
use crate::mono::Mono;
Expand Down Expand Up @@ -150,6 +150,43 @@ pub fn plan(pref_vcs: Option<VcsRange>) -> Result<()> {
output.commit(&mono)
}

pub fn info(
pref_vcs: Option<VcsRange>, ids: Option<Vec<ProjectId>>, names: Option<Vec<&str>>, all: bool, show_name: bool,
show_root: bool
) -> Result<()> {
let mono = build(pref_vcs, VcsLevel::None, VcsLevel::Smart, VcsLevel::None, VcsLevel::Smart)?;
let output = Output::new();
let mut output = output.info(show_name, show_root);

let cfg = mono.config();
let reader = cfg.state_read();

if all {
output.write_projects(cfg.projects().iter().map(|p| ProjLine::from(p, reader)))?;
} else if let Some(ids) = ids {
output.write_projects(
ids
.iter()
.map(|id| cfg.get_project(id).ok_or_else(|| bad!("No such project: {}.", id)))
.collect::<Result<Vec<_>>>()?
.into_iter()
.map(|p| ProjLine::from(p, reader))
)?;
} else if let Some(names) = names {
output.write_projects(
names
.iter()
.map(|n| cfg.find_unique(n).map(|id| cfg.get_project(id).unwrap()))
.collect::<Result<Vec<_>>>()?
.into_iter()
.map(|p| ProjLine::from(p, reader))
)?;
}

output.commit()?;
Ok(())
}

pub fn release(pref_vcs: Option<VcsRange>, all: bool, dry: bool) -> Result<()> {
let mut mono = build(pref_vcs, VcsLevel::None, VcsLevel::Smart, VcsLevel::Local, VcsLevel::Smart)?;
let output = Output::new();
Expand Down
2 changes: 0 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,7 @@ pub struct Project {
impl Project {
pub fn id(&self) -> &ProjectId { &self.id }
pub fn name(&self) -> &str { &self.name }

pub fn depends(&self) -> &[ProjectId] { &self.depends }

pub fn root(&self) -> Option<&String> { self.root.as_ref().and_then(|r| if r == "." { None } else { Some(r) }) }

fn annotate<S: StateRead>(&self, state: &S) -> Result<AnnotatedMark> {
Expand Down
85 changes: 60 additions & 25 deletions src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,13 @@ impl Repo {
Ok(E2::B(self.commits_between(from, head_oid, incl_from)?))
}

pub fn get_oid_head(&self) -> Result<AnnotatedCommit> { self.get_oid(self.branch_name()?) }
pub fn get_oid_head(&self) -> Result<AnnotatedCommit> {
if let Some(branch_name) = self.branch_name()? {
self.get_oid(branch_name)
} else {
self.get_oid("HEAD")
}
}

pub fn get_oid(&self, spec: &str) -> Result<AnnotatedCommit> {
match &self.vcs {
Expand All @@ -212,8 +218,13 @@ impl Repo {
}
GitVcsLevel::Remote { repo, branch_name, remote_name, fetches }
| GitVcsLevel::Smart { repo, branch_name, remote_name, fetches } => {
// get_oid_remote() will verify current
get_oid_remote(repo, branch_name, spec, remote_name, fetches)
if spec == "HEAD" {
verify_current(repo).chain_err(|| "Can't complete get.")?;
get_oid_local(repo, spec)
} else {
// get_oid_remote() will verify current
get_oid_remote(repo, branch_name, spec, remote_name, fetches)
}
}
}
}
Expand Down Expand Up @@ -327,6 +338,7 @@ impl Repo {
| GitVcsLevel::Smart { repo, branch_name, remote_name, .. } => (repo, branch_name, remote_name)
};

let branch_name = branch_name.as_ref().ok_or_else(|| bad!("No branch name for push."))?;
let mut refs = vec![format!("+refs/heads/{}", branch_name)];
for tag in tags {
refs.push(format!("+refs/tags/{}", tag));
Expand All @@ -346,7 +358,7 @@ impl Repo {
do_push(repo, remote_name, &[format!("+refs/tags/{}", tag)])
}

pub fn branch_name(&self) -> Result<&String> {
pub fn branch_name(&self) -> Result<&Option<String>> {
match &self.vcs {
GitVcsLevel::None { .. } => err!("No branch name at `none` level."),
GitVcsLevel::Local { branch_name, .. }
Expand Down Expand Up @@ -557,12 +569,14 @@ pub struct FullPr {
base_time: Time,
commits: Vec<CommitInfoBuf>,
excludes: Vec<String>,
closed_at: DateTime<FixedOffset>
closed_at: DateTime<FixedOffset>,
discovery_order: usize
}

impl FullPr {
pub fn lookup(
repo: &Repo, base: FromTagBuf, headref: String, number: u32, title: String, closed_at: DateTime<FixedOffset>
repo: &Repo, base: FromTagBuf, headref: String, number: u32, title: String, closed_at: DateTime<FixedOffset>,
discovery_order: usize
) -> Result<FullPr> {
let commit = repo.get_oid(&headref);
match lookup_from_commit(repo, base.clone(), commit)? {
Expand All @@ -577,7 +591,8 @@ impl FullPr {
base_time: Time::new(0, 0),
commits: Vec::new(),
excludes: Vec::new(),
closed_at
closed_at,
discovery_order
})
}
Ok((commit, commits, base_time)) => Ok(FullPr {
Expand All @@ -589,7 +604,8 @@ impl FullPr {
base_time,
commits,
excludes: Vec::new(),
closed_at
closed_at,
discovery_order
})
}
}
Expand All @@ -604,6 +620,7 @@ impl FullPr {
pub fn best_guess(&self) -> bool { self.head_oid.is_none() }
pub fn has_exclude(&self, oid: &str) -> bool { self.excludes.iter().any(|c| c == oid) }
pub fn closed_at(&self) -> &DateTime<FixedOffset> { &self.closed_at }
pub fn discovery_order(&self) -> usize { self.discovery_order }

pub fn included_commits(&self) -> impl Iterator<Item = &CommitInfoBuf> + '_ {
self.commits.iter().filter(move |c| !self.has_exclude(c.id()))
Expand Down Expand Up @@ -660,14 +677,14 @@ impl IterString {

enum GitVcsLevel {
None { root: PathBuf },
Local { repo: Repository, branch_name: String },
Remote { repo: Repository, branch_name: String, remote_name: String, fetches: RefCell<HashMap<String, Oid>> },
Smart { repo: Repository, branch_name: String, remote_name: String, fetches: RefCell<HashMap<String, Oid>> }
Local { repo: Repository, branch_name: Option<String> },
Remote { repo: Repository, branch_name: Option<String>, remote_name: String, fetches: RefCell<HashMap<String, Oid>> },
Smart { repo: Repository, branch_name: Option<String>, remote_name: String, fetches: RefCell<HashMap<String, Oid>> }
}

impl GitVcsLevel {
fn from(
level: VcsLevel, root: PathBuf, repo: Repository, branch_name: String, remote_name: String,
level: VcsLevel, root: PathBuf, repo: Repository, branch_name: Option<String>, remote_name: String,
fetches: RefCell<HashMap<String, Oid>>
) -> GitVcsLevel {
match level {
Expand Down Expand Up @@ -746,8 +763,19 @@ fn find_root_blind<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
}
}

fn find_remote_name(repo: &Repository, branch_name: &str) -> Result<String> {
repo.config()?.get_str(&format!("branch.{}.remote", branch_name)).map(|s| s.to_string()).or_else(|_| {
fn find_remote_name(repo: &Repository, branch_name: &Option<String>) -> Result<String> {
let configured = branch_name
.as_ref()
.and_then(|branch_name| {
repo
.config()
.map(|config| config.get_str(&format!("branch.{}.remote", branch_name)).map(|s| s.to_string()).ok())
.transpose()
})
.transpose()?
.ok_or_else(|| bad!("No configured repo found for {:?}.", branch_name));

configured.or_else(|_| {
let remotes = repo.remotes()?;
if remotes.is_empty() {
err!("No remotes in this repo.")
Expand All @@ -759,16 +787,20 @@ fn find_remote_name(repo: &Repository, branch_name: &str) -> Result<String> {
})
}

fn find_branch_name(repo: &Repository) -> Result<String> {
fn find_branch_name(repo: &Repository) -> Result<Option<String>> {
let head_ref = repo.find_reference("HEAD").map_err(|e| bad!("Couldn't resolve head: {:?}.", e))?;
if head_ref.kind() != Some(ReferenceType::Symbolic) {
return err!("Not on a branch.");
Ok(None)
} else {
let branch_name = head_ref.symbolic_target().ok_or_else(|| bad!("Branch is not named."))?;
if branch_name.starts_with("refs/heads/") {
Ok(branch_name[11 ..].to_string())
} else {
return err!("Current {} is not a branch.", branch_name);
match head_ref.symbolic_target() {
None => Ok(None),
Some(branch_name) => {
if branch_name.starts_with("refs/heads/") {
Ok(Some(branch_name[11 ..].to_string()))
} else {
return err!("Current {} is not a branch.", branch_name);
}
}
}
}
}
Expand Down Expand Up @@ -959,13 +991,16 @@ fn get_oid_local<'r>(repo: &'r Repository, spec: &str) -> Result<AnnotatedCommit
}

fn get_oid_remote<'r>(
repo: &'r Repository, branch_name: &str, spec: &str, remote_name: &str, fetches: &RefCell<HashMap<String, Oid>>
repo: &'r Repository, branch_name: &Option<String>, spec: &str, remote_name: &str,
fetches: &RefCell<HashMap<String, Oid>>
) -> Result<AnnotatedCommit<'r>> {
let (commit, cached) = verified_fetch(repo, remote_name, fetches, spec)?;

if !cached && (spec == branch_name || spec == "HEAD") {
info!("Merging to \"{}\" on local.", spec);
ff_merge(repo, branch_name, &commit)?;
if let Some(branch_name) = branch_name {
if !cached && spec == branch_name {
info!("Merging to \"{}\" on local.", spec);
ff_merge(repo, branch_name, &commit)?;
}
}
Ok(commit)
}
Expand Down
Loading

0 comments on commit a7140f6

Please sign in to comment.