App-Gitc

 view release on metacpan or  search on metacpan

bin/gitc-promote  view on Meta::CPAN

    # extract structure from the command line
    my $target = pop @argv;
    my @changesets = grep { !/^-/ } @argv;

    # validate the promotion target
    die "You must specify a promotion target\n" if not $target;
    die "Invalid promotion target '$target'\n"
        if not defined environment_preceding($target);

    # validate changesets
    my $refs = validate_changesets( $target, @changesets );
    return ( $target, $refs, \@changesets );
}

# checks a list of changeset names for sanity. dies on anything bad.
# if the changesets are ok, it returns an arrayref of Git refs for
# those changesets
sub validate_changesets {
    my ( $target, @changesets ) = @_;
    return ( $target, [] ) if not @changesets;
    die "You may not cherry pick promote to prod\n"
        if !$force and $target eq 'prod' and @changesets;

    warn "Validating changesets\n";
    my @refs;
    my @already_promoted;
    my %seen;
    for my $changeset (@changesets) {
        die "You may not cherry pick '$changeset' to $target\n"
            if $changeset =~ m/^(master|test|stage|prod)$/;
        die   "You asked to promote '$changeset' twice.  Did you mean\n"
            . "to list it once or did you mistype some other changeset?\n"
            if $seen{$changeset}++;
        push @refs, full_changeset_name($changeset);
        push @already_promoted, $changeset
            if is_valid_ref("cs/$changeset/to-$target");
    }
    if (@already_promoted) {
        my $msg = "These changesets have already been promoted to $target:\n";
        $msg .= "  - $_\n" for @already_promoted;
        die $msg;
    }
    return \@refs;
}

# quickly locate any changeset dependencies that were not explicitly listed.
# takes a promotion target and a list of refs to promote.
# returns a list of the refs for those dependencies
sub find_missing_dependencies {
    my ( $target, @wanted ) = @_;
    my @extras = map { full_changeset_name($_) }
        unpromoted( \@wanted, "origin/$target" );

    # find refs that weren't explicitly listed
    my %extras = map { ( $_ => 1 ) } @extras;
    delete @extras{@wanted};
    return keys %extras;
}

# given a list of requested changeset refs and a list of missing dependency
# refs, prompts the user what to do and returns a new list of requested
# changeset refs
sub handle_missing_dependencies {
    my ( $wanted, $missing ) = @_;

    my @pretty = map { short_ref_name($_) } @$missing;
    sort_changesets_by_name(\@pretty);
    warn "The following changeset dependencies are missing:\n";
    warn "  - $_\n" for @pretty;
    die "Exiting promotion because of missing dependencies\n" if not -t STDIN;
    print STDERR 'What do you want to do? '
        . '(p)romote these too, e(x)it, see (d)etails: ';
    chomp ( my $choice = <STDIN> );
    if ( $choice eq 'p' ) {
        return ( @$wanted, @$missing );
    }
    elsif ( $choice eq 'd' ) {
        warn "\n";
        my $dep = build_ref_dependency_tree( $wanted, { select => 1 } );
        for my $ref (@$wanted) {
            my @also = map { short_ref_name($_) } @{ $dep->depends($ref) };
            next if not @also;
            warn '  '
                . short_ref_name($ref)
                . ' --> '
                . join( ', ', @also ) . "\n";
        }
        die "\nPlease change the promotion list and try again\n";
    }

    die "Exiting promotion because of missing dependencies\n";
}

# given an arrayref of wanted refs, returns an Algorithm::Dependency::Ordered
# object representing all the dependencies.
sub build_ref_dependency_tree {
    my ( $wanted, $args ) = @_;
    our $target;

    warn "Calculating changeset dependency tree\n";
    my %dependencies;
    my @outstanding_refs = @$wanted;
    while ( my $ref = shift @outstanding_refs ) {
        next if $dependencies{$ref};
        my @refs =
            grep { $_ ne $ref }
            map  { full_changeset_name($_) }
            unpromoted( $ref, "origin/$target" );
        push @outstanding_refs, @refs;
        $dependencies{$ref} = [ @refs ];  # copy the list of dependencies
    }

    # build the object
    require Algorithm::Dependency::Ordered;
    require Algorithm::Dependency::Source::HoA;
    my $source = Algorithm::Dependency::Source::HoA->new(\%dependencies);
    return Algorithm::Dependency::Ordered->new(
        source   => $source,
        $args->{select} ? ( selected => $wanted ) : (),
    );
}



( run in 1.406 second using v1.01-cache-2.11-cpan-6aa56a78535 )