Module: Hoe::Mercurial

Includes:
MercurialHelpers, RakeHelpers
Defined in:
lib/hoe/mercurial.rb

Overview

Hoe plugin module

Constant Summary collapse

VERSION =
'1.4.0'
COMMIT_MSG_FILE =

The name of the file to edit for the commit message

'commit-msg.txt'

Constants included from RakeHelpers

RakeHelpers::ANSI_ATTRIBUTES, RakeHelpers::CLEAR_CURRENT_LINE, RakeHelpers::CLEAR_TO_EOL, RakeHelpers::DEFAULT_EDITOR, RakeHelpers::MULTILINE_PROMPT

Constants included from MercurialHelpers

Hoe::MercurialHelpers::IGNORE_FILE

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from RakeHelpers

ansi_code, ask_for_confirmation, colorize, edit, error_message, get_target_args, humanize_file_list, log, make_prompt_string, prompt, prompt_for_multiple_values, prompt_with_default, quotelist, read_command_output, run, trace

Methods included from MercurialHelpers

#delete_extra_files, #edit_commit_log, #get_current_rev, #get_manifest, #get_numeric_rev, #get_repo_paths, #get_tags, #get_tip_info, #get_uncommitted_files, #get_unknown_files, #hg_ignore_files, #make_changelog, #make_commit_log

Instance Attribute Details

#check_history_on_releaseObject

Returns the value of attribute check_history_on_release.



448
449
450
# File 'lib/hoe/mercurial.rb', line 448

def check_history_on_release
  @check_history_on_release
end

#hg_release_tag_prefixObject

Returns the value of attribute hg_release_tag_prefix.



446
447
448
# File 'lib/hoe/mercurial.rb', line 446

def hg_release_tag_prefix
  @hg_release_tag_prefix
end

#hg_sign_tagsObject

Returns the value of attribute hg_sign_tags.



447
448
449
# File 'lib/hoe/mercurial.rb', line 447

def hg_sign_tags
  @hg_sign_tags
end

Instance Method Details

#define_mercurial_tasksObject

Hoe hook – Define Rake tasks when the plugin is loaded.



486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
# File 'lib/hoe/mercurial.rb', line 486

def define_mercurial_tasks
	return unless File.exist?( ".hg" ) &&
		!Rake::Task.task_defined?( 'hg:checkin' )

	file COMMIT_MSG_FILE do |task|
		edit_commit_log( task.name )
	end

	namespace :hg do

		desc "Prepare for a new release"
		task :prep_release do
			uncommitted_files = get_uncommitted_files()
			unless uncommitted_files.empty?
				log "Uncommitted files:\n",
					*uncommitted_files.map {|fn| "	#{fn}\n" }
				ask_for_confirmation( "\nRelease anyway?", true ) do
					log "Okay, releasing with uncommitted versions."
				end
			end

			tags = get_tags()
			rev = get_current_rev()
			pkg_version_tag = "#{hg_release_tag_prefix}#{version}"

			# Look for a tag for the current release version, and if it exists abort
			if tags.include?( pkg_version_tag )
				error "Version #{version} already has a tag."
				fail
			end

			# Ensure that the History file contains an entry for every release
			Rake::Task[ 'check_history' ].invoke if self.check_history_on_release

			# Sign the current rev
			if self.hg_sign_tags
				log "Signing rev #{rev}"
				run 'hg', 'sign'
			end

			# Tag the current rev
			log "Tagging rev #{rev} as #{pkg_version_tag}"
			run 'hg', 'tag', pkg_version_tag

			# Offer to push
			Rake::Task['hg:push'].invoke
		end


		desc "Check for new files and offer to add/ignore/delete them."
		task :newfiles do
			log "Checking for new files..."

			entries = get_unknown_files()

			unless entries.empty?
				files_to_add = []
				files_to_ignore = []
				files_to_delete = []

				entries.each do |entry|
					action = prompt_with_default( "	 #{entry}: (a)dd, (i)gnore, (s)kip (d)elete", 's' )
					case action
					when 'a'
						files_to_add << entry
					when 'i'
						files_to_ignore << entry
					when 'd'
						files_to_delete << entry
					end
				end

				unless files_to_add.empty?
					run 'hg', 'add', *files_to_add
				end

				unless files_to_ignore.empty?
					hg_ignore_files( *files_to_ignore )
				end

				unless files_to_delete.empty?
					delete_extra_files( files_to_delete )
				end
			end
		end
		task :add => :newfiles


		desc "Pull and update from the default repo"
		task :pull do
			paths = get_repo_paths()
			if origin_url = paths['default']
				ask_for_confirmation( "Pull and update from '#{origin_url}'?", false ) do
					Rake::Task['hg:pull_without_confirmation'].invoke
				end
			else
				trace "Skipping pull: No 'default' path."
			end
		end


		desc "Pull and update without confirmation"
		task :pull_without_confirmation do
			run 'hg', 'pull', '-u'
		end


		desc "Update to tip"
		task :update do
			run 'hg', 'update'
		end


		desc "Clobber all changes (hg up -C)"
		task :update_and_clobber do
			run 'hg', 'update', '-C'
		end


		task :precheckin do
			trace "Pre-checkin hooks"
		end


		desc "Check the current code in if tests pass"
		task :checkin => [:pull, :newfiles, :precheckin, COMMIT_MSG_FILE] do
			targets = get_target_args()
			$stderr.puts '---', File.read( COMMIT_MSG_FILE ), '---'
			ask_for_confirmation( "Continue with checkin?" ) do
				run 'hg', 'ci', '-l', COMMIT_MSG_FILE, targets
				rm_f COMMIT_MSG_FILE
			end
			Rake::Task['hg:push'].invoke
		end
		task :commit => :checkin
		task :ci => :checkin

		CLEAN.include( COMMIT_MSG_FILE )

		desc "Push to the default origin repo (if there is one)"
		task :push do
			paths = get_repo_paths()
			if origin_url = paths['default']
				ask_for_confirmation( "Push to '#{origin_url}'?", false ) do
					Rake::Task['hg:push_without_confirmation'].invoke
				end
			else
				trace "Skipping push: No 'default' path."
			end
		end

		desc "Push to the default repo without confirmation"
		task :push_without_confirmation do
			run 'hg', 'push'
		end
	end

	# Add a top-level 'ci' task for checkin
	desc "Check in your changes"
	task :ci => 'hg:checkin'

	# Hook the release task and prep the repo first
	task :prerelease => 'hg:prep_release'

	desc "Check the history file to ensure it contains an entry for each release tag"
	task :check_history do
		log "Checking history..."
		missing_tags = get_unhistoried_version_tags()

		unless missing_tags.empty?
			abort "%s needs updating; missing entries for tags: %p" %
				[ self.history_file, missing_tags ]
		end
	end

rescue ::Exception => err
	$stderr.puts "%s while defining Mercurial tasks: %s" % [ err.class.name, err.message ]
	raise
end

#get_unhistoried_version_tags(include_pkg_version = true) ⇒ Object

Read the list of tags and return any that don’t have a corresponding section in the history file.



465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/hoe/mercurial.rb', line 465

def get_unhistoried_version_tags( include_pkg_version=true )
	prefix = self.hg_release_tag_prefix
	tag_pattern = /#{prefix}\d+(\.\d+)+/
	release_tags = get_tags().grep( /^#{tag_pattern}$/ )

	release_tags.unshift( "#{prefix}#{version}" ) if include_pkg_version

	IO.readlines( self.history_file ).each do |line|
		if line =~ /^(?:h\d\.|#+|=+)\s+(#{tag_pattern})\s+/
			trace "  found an entry for tag %p: %p" % [ $1, line ]
			release_tags.delete( $1 )
		else
			trace "  no tag on line %p" % [ line ]
		end
	end

	return release_tags
end

#initialize_mercurialObject

Set up defaults



452
453
454
455
456
457
458
459
460
# File 'lib/hoe/mercurial.rb', line 452

def initialize_mercurial
	# Follow semantic versioning tagging specification (http://semver.org/)
	self.hg_release_tag_prefix    = "v"
	self.hg_sign_tags             = false
	self.check_history_on_release = false

	self.dependency( 'hoe-mercurial', "~> #{VERSION}", :developer ) unless
		self.name == 'hoe-mercurial'
end