From 768727f37afa6fbb5082833a4c14c8134ec42122 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 6 Aug 2020 23:32:13 +0300 Subject: Add implementation --- .gitattributes | 19 ++ AUTHORS | 7 + CONTRIBUTING.md | 16 ++ INSTALL | 6 + LICENSE | 21 ++ NEWS | 1 + README | 20 ++ bdep-util/.gitignore | 3 + bdep-util/buildfile | 38 ++++ bdep-util/git-hooks/.gitignore | 1 + bdep-util/git-hooks/pre-commit.in | 23 +++ bdep-util/git-pre-commit-copyright-check.in | 73 +++++++ bdep-util/git-pre-commit-version-check.in | 220 ++++++++++++++++++++ bdep-util/git-pre-commit.in | 17 ++ build/.gitignore | 3 + build/bootstrap.build | 10 + build/export.build | 19 ++ build/root.build | 6 + buildfile | 9 + manifest | 21 ++ repositories.manifest | 6 + tests/.gitignore | 2 + tests/build/.gitignore | 3 + tests/build/bootstrap.build | 8 + tests/build/root.build | 12 ++ tests/buildfile | 24 +++ tests/git-common.testscript | 17 ++ tests/git-pre-commit-common.testscript | 13 ++ tests/git-pre-commit-copyright-check.testscript | 25 +++ tests/git-pre-commit-version-check.testscript | 263 ++++++++++++++++++++++++ tests/git-pre-commit.testscript | 42 ++++ 31 files changed, 948 insertions(+) create mode 100644 .gitattributes create mode 100644 AUTHORS create mode 100644 CONTRIBUTING.md create mode 100644 INSTALL create mode 100644 LICENSE create mode 100644 NEWS create mode 100644 README create mode 100644 bdep-util/.gitignore create mode 100644 bdep-util/buildfile create mode 100644 bdep-util/git-hooks/.gitignore create mode 100644 bdep-util/git-hooks/pre-commit.in create mode 100644 bdep-util/git-pre-commit-copyright-check.in create mode 100644 bdep-util/git-pre-commit-version-check.in create mode 100644 bdep-util/git-pre-commit.in create mode 100644 build/.gitignore create mode 100644 build/bootstrap.build create mode 100644 build/export.build create mode 100644 build/root.build create mode 100644 buildfile create mode 100644 manifest create mode 100644 repositories.manifest create mode 100644 tests/.gitignore create mode 100644 tests/build/.gitignore create mode 100644 tests/build/bootstrap.build create mode 100644 tests/build/root.build create mode 100644 tests/buildfile create mode 100644 tests/git-common.testscript create mode 100644 tests/git-pre-commit-common.testscript create mode 100644 tests/git-pre-commit-copyright-check.testscript create mode 100644 tests/git-pre-commit-version-check.testscript create mode 100644 tests/git-pre-commit.testscript diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1631641 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,19 @@ +# This is a good default: files that are auto-detected by git to be text are +# converted to the platform-native line ending (LF on Unix, CRLF on Windows) +# in the working tree and to LF in the repository. +# +* text=auto + +# Use `eol=crlf` for files that should have the CRLF line ending both in the +# working tree (even on Unix) and in the repository. +# +#*.bat text eol=crlf + +# Use `eol=lf` for files that should have the LF line ending both in the +# working tree (even on Windows) and in the repository. +# +#*.sh text eol=lf + +# Use `binary` to make sure certain files are never auto-detected as text. +# +#*.png binary diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..9780708 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,7 @@ +This file contains information about the build2 authors for copyright +purposes. + +The copyright for the code is held by the contributors of the code. The +revision history in the version control system is the primary source of +authorship information for copyright purposes. Contributors that have +requested to also be noted explicitly in this file are listed below: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6bfc34f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,16 @@ +This project is part of the `build2` toolchain; see its +[Community](https://build2.org/community.xhtml) page for various ways to +contribute. + +The copyright for the code is held by the contributors of the code (see the +`AUTHORS` file). The code is licensed under permissive open source licensing +terms (see the `LICENSE` file). When you contribute code to this project, you +license it under these terms. Before contributing please make sure that these +terms are acceptable to you (and to your employer(s), if they have rights to +intellectual property that you create) and that the code being contributed is +your original creation. + +The revision history in the version control system is the primary source of +authorship information for copyright purposes. If, however, you would like +to also be noted explicitly, please include the appropriate change to the +`AUTHORS` file along with your contribution. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..79e0d75 --- /dev/null +++ b/INSTALL @@ -0,0 +1,6 @@ +The easiest way to build this package is with the bpkg package manager: + +$ bpkg build bdep-util + +But if you don't want to use the package manager, then you can also build it +manually using the standard build2 build system. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2cf3738 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2014-2020 the build2 authors (see the AUTHORS file). + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..926155a --- /dev/null +++ b/NEWS @@ -0,0 +1 @@ +See https://git.build2.org/cgit/bdep-util/log/ for the change log. diff --git a/README b/README new file mode 100644 index 0000000..005fd92 --- /dev/null +++ b/README @@ -0,0 +1,20 @@ +This package contains extra build2 project management utilities. + +build2 is an open source, cross-platform toolchain for building and packaging +C++ code. Its aim is a modern build system and dependency manager for the C++ +language that provide a consistent, out of the box interface across multiple +platforms and compilers. For more information see: + +https://build2.org/ + +See the NEWS file for the user-visible changes from the previous release. + +See the LICENSE file for the distribution conditions. + +See the INSTALL file for the prerequisites and installation instructions. + +See the doc/ directory for documentation. + +Send questions, bug reports, or any other feedback to the users@build2.org +mailing list. You can post without subscribing. See https://lists.build2.org +for searchable archives, posting guidelines, etc. diff --git a/bdep-util/.gitignore b/bdep-util/.gitignore new file mode 100644 index 0000000..7ecc5ca --- /dev/null +++ b/bdep-util/.gitignore @@ -0,0 +1,3 @@ +bdep-git-pre-commit +bdep-git-pre-commit-version-check +bdep-git-pre-commit-copyright-check diff --git a/bdep-util/buildfile b/bdep-util/buildfile new file mode 100644 index 0000000..5fc25c8 --- /dev/null +++ b/bdep-util/buildfile @@ -0,0 +1,38 @@ +# file : bdep-util/buildfile +# license : MIT; see accompanying LICENSE file + +import mods = libbutl.bash%bash{manifest-parser} +import mods += libbutl.bash%bash{standard-version} + +# @@ TMP Note that git-hooks/pre-commit, bdep-git-pre-commit, and +# bdep-git-pre-commit-copyright-check have no dependencies on any bash +# module. However, we add such dependencies for the bash module rule to +# match. Eventually, there will be a better way to achieve that (hints). +# + +# Note that git-hooks/pre-commit script just sources bdep-git-pre-commit. The +# reason to have both scripts is to be able to configure git's pre-commit hook +# via the core.hooksPath configuration value (should refer, for example, to +# the /usr/local/bin/bdep-git-hooks directory) and to import +# bdep-git-pre-commit, for example, for testing the installed hook. +# +git-hooks/ +{ + exe{pre-commit}: in{pre-commit} ../exe{bdep-git-pre-commit} $mods +} + +exe{bdep-git-pre-commit}: in{git-pre-commit} \ + exe{bdep-git-pre-commit-version-check \ + bdep-git-pre-commit-copyright-check} \ + $mods + +exe{bdep-git-pre-commit-version-check}: in{git-pre-commit-version-check} \ + $mods + +exe{bdep-git-pre-commit-copyright-check}: in{git-pre-commit-copyright-check} \ + $mods + +# Install the git pre-commit hook into bdep-git-hooks/ subdirectory of, say, +# /usr/bin/. +# +git-hooks/exe{pre-commit}: install = bin/bdep-git-hooks/ diff --git a/bdep-util/git-hooks/.gitignore b/bdep-util/git-hooks/.gitignore new file mode 100644 index 0000000..416634f --- /dev/null +++ b/bdep-util/git-hooks/.gitignore @@ -0,0 +1 @@ +pre-commit diff --git a/bdep-util/git-hooks/pre-commit.in b/bdep-util/git-hooks/pre-commit.in new file mode 100644 index 0000000..3339187 --- /dev/null +++ b/bdep-util/git-hooks/pre-commit.in @@ -0,0 +1,23 @@ +#! /usr/bin/env bash + +# file : bdep-util/git-hooks/pre-commit.in +# license : MIT; see accompanying LICENSE file + +# Forward the execution to the pre-commit script implementation. +# +# To enable the hooks globally run, for example: +# +# $ git config --global core.hooksPath /usr/local/bin/bdep-git-hooks +# +# Notes: +# +# - git passes no parameters to this kind of hooks. +# +# - git changes CWD to the git repository root directory for the hook process. +# +# - git command running from inside the hook sees files that should be +# auto-staged due to the -a git-commit option or similar as already staged. +# +trap 'exit 1' ERR + +source "$(dirname "$(realpath "${BASH_SOURCE[0]}")")/../bdep-git-pre-commit" diff --git a/bdep-util/git-pre-commit-copyright-check.in b/bdep-util/git-pre-commit-copyright-check.in new file mode 100644 index 0000000..2e0f982 --- /dev/null +++ b/bdep-util/git-pre-commit-copyright-check.in @@ -0,0 +1,73 @@ +#! /usr/bin/env bash + +# file : bdep-util/git-pre-commit-copyright-check.in +# license : MIT; see accompanying LICENSE file + +# Check copyright notices in the COPYRIGHT and LICENSE files and issue a +# warning if they don't include the current year. +# +# Specifically, look first for COPYRIGHT and then LICENSE in the root +# directory and all subdirectories in a project. +# +# Then in each file look for the first line matching the: +# +# ^Copyright (\([cC]\))? ... +# +# Regex, where "..." matches various year lists/ranges (e.g., "2010", "2010, +# 2011", "2010-2011", and their combinations; see the pattern below for +# details). Specifically, we don't consider Copyright notices that: +# +# - don't start at the very beginning of a line (indented, etc) +# - contain something other than years prior to the last year (names, etc) +# - wrap over multiple lines (long year list, etc) +# +# Note also that the current year is obtained in the UTC timezone. +# +trap 'exit 1' ERR +set -o errtrace # Trap in functions. + +function info () { echo "$*" 1>&2; } +function error () { info "$*"; exit 1; } + +# Recursively collect the COPYRIGHT and LICENSE files, skipping the LICENSE +# files in directories that contain the COPYRIGHT file. +# +# @@ Note that for now we assume that there are no spaces in the project file +# and directory names. +# +files=() + +fs=($(find . \( -type f -o -type l \) -name COPYRIGHT)) + +for f in "${fs[@]}"; do + files+=("$f") +done + +fs=($(find . \( -type f -o -type l \) -name LICENSE)) + +for f in "${fs[@]}"; do + d="$(dirname "$f")" + + if [ ! -f "$d/COPYRIGHT" ]; then + files+=("$f") + fi +done + +# Grep for the Copyright notice in the collected files and issue the warning +# if it is present and is outdated. +# +# @@ We should probably skip the COPYRIGHT/LICENSE files whose parent +# directories don't (recursively) contain staged files (think of projects +# with multiple packages, bundled third-party code, etc). Note that we can +# obtain the staged file list with the `git diff --name-only --cached` +# command. +# +current_year="$(date -u +'%Y')" + +for f in "${files[@]}"; do + year="$(sed -n -re 's%^Copyright( +\([cC]\))?[ 0-9,-]*[ ,-]([0-9]{4}).*$%\2%p' "$f" | head -n 1)" + + if [ -n "$year" -a "$year" != "$current_year" ]; then + info "WARNING: last copyright year in '${f#./}' is $year" + fi +done diff --git a/bdep-util/git-pre-commit-version-check.in b/bdep-util/git-pre-commit-version-check.in new file mode 100644 index 0000000..20cd4b0 --- /dev/null +++ b/bdep-util/git-pre-commit-version-check.in @@ -0,0 +1,220 @@ +#!/usr/bin/env bash + +# file : bdep-util/git-pre-commit-version-check.in +# license : MIT; see accompanying LICENSE file + +# Check that the changes being commited are compatible with the version state +# of the package(s). +# +# Specifically, fail if there are any changes staged for the released packages +# (the version is final or a stub) unless an appropriate version change is +# also staged. +# +# To achieve this, extract and compare versions corresponding to two states: +# the latest revision in the current branch (committed) and the potential +# result of the forthcoming commit (staged). +# +trap "{ exit 1; }" ERR +set -o errtrace # Trap ERR in functions. + +function info () { echo "$*" 1>&2; } +function error () { info "$*"; exit 1; } + +@import libbutl/manifest-parser@ +@import libbutl/standard-version@ + +# Note that here and below a file in the existing repository revision is +# referred to as ':' (for example 'HEAD:manifest') and in the +# staged revision as just ':', where the path is relative to the project +# root directory (see gitrevisions(7) for details). + +# Return 0 if the specified file revision exists and 1 otherwise. +# +function file_exists () # []: +{ + local f="$1" + + if git cat-file -e "$f" 2>/dev/null; then # Repository object exists? + local t + t="$(git cat-file -t "$f")" + + if [ "$t" == "blob" ]; then + return 0 + fi + fi + + return 1 +} + +# Wrap libbutl manifest parsing functions to parse manifest revisions and to +# shorten names. Assumes that the specified manifest revision exists (for +# example, this is checked with the above file_exists() function). +# +function manifest_parser_start () # []: +{ + butl_manifest_parser_start < <(git cat-file -p "$1") + manifest_parser_ofd="$butl_manifest_parser_ofd" +} + +function manifest_parser_finish () +{ + butl_manifest_parser_finish +} + +# Find packages in the repository revision saving them into the specified by +# name associative array (needs to be declared prior to the function call) +# mapping the package names to the version/path pairs (for example "libfoo" -> +# "1.2.3 lib/foo"). Optionally, return only released packages. +# +# Note that the repository revisions can be in arbitrary states and the +# package manifests may not be necessarily present or valid. Thus, we consider +# a package to be present in the repository revision if its manifest +# (potentially referred to via the packages.manifest file) exists and contains +# a non-empty package name and the valid package version. Otherwise, for the +# staged revision, if it looks like it should be a package but something is +# missing, we warn. +# +function find_packages () # [] +{ + local rev="$1" + local -n r="$2" + local rel="$3" + + # Collect the potential package directories. + # + local ds=() + local n v + if file_exists "$rev:packages.manifest"; then + manifest_parser_start "$rev:packages.manifest" + + while IFS=: read -ru "$manifest_parser_ofd" -d '' n v; do + if [ "$n" == "location" ]; then + ds+=("${v%/}") + fi + done + + manifest_parser_finish + else + ds+=(.) + fi + + # Fill the resulting package map. + # + local d + for d in "${ds[@]}"; do + local m="$d/manifest" + local mr="$rev:$m" + + if ! file_exists "$mr"; then + + # Don't warn about absence of the root package manifest file, since this + # git repository may well not be a build2 package. + # + if [ -z "$rev" -a "$d" != "." ]; then + info "warning: package manifest file $m does not exist" + fi + continue + fi + + local name= + local version= + + manifest_parser_start "$mr" + + while IFS=: read -ru "$manifest_parser_ofd" -d '' n v; do + case "$n" in + name) name="$v" ;; + version) version="$v" ;; + esac + done + + manifest_parser_finish + + # Check if a non-empty package name is present. + # + if [ -z "$name" ]; then + if [ -z "$rev" ]; then + info "warning: package name is missing in $m" + fi + continue + fi + + # Check if a non-empty package version is present. + # + if [ -z "$version" ]; then + if [ -z "$rev" ]; then + info "warning: package version is missing in $m" + fi + continue + fi + + # Check if the package version is a valid standard version. + # + if ! butl_standard_version --is-version --is-not-earliest "$version"; then + if [ -z "$rev" ]; then + info "warning: package version '$version' in $m is not a valid standard version" + fi + continue + fi + + # Optionally, skip the unreleased version. + # + if [ ! $rel ] || butl_standard_version --is-not-snapshot "$version"; then + r["$name"]="$version $d" + fi + done +} + +# Collect the commited released packages. +# +declare -A committed_packages +find_packages 'HEAD' committed_packages true + +# Collect all the staged packages. +# +# Note that while we could bail out if there are no committed released +# packages, we will still collect the staged packages to potentially issue +# warnings about some of the manifest errors (empty package name, etc). +# +declare -A staged_packages +find_packages '' staged_packages + +# Iterate through the committed released packages and fail if there is a +# change but no version change staged for this package. +# +for p in "${!committed_packages[@]}"; do + read cv cd <<<"${committed_packages[$p]}" + + # Check if this is still a package in the staged revision. + # + if [[ -v staged_packages["$p"] ]]; then + read sv sd <<<"${staged_packages[$p]}" + + # If the package version didn't change, then check for any package changes + # and fail if there are any. + # + if [ "$sv" == "$cv" ]; then + + # Check that the package directory didn't change. + # + # If the package is moved, then detecting its changes becomes too + # complicated and we don't want to miss any. Let's keep it simple and + # deny moving the released packages (the user can always suppress the + # verification with --no-verify anyway). + # + if [ "$sd" != "$cd" ]; then + info "error: moving released package $p $cv" + info " info: use --no-verify git option to suppress" + exit 1 + fi + + # Check if the package has some staged changes in its directory. + # + if ! git diff-index --cached --quiet HEAD -- "$sd"; then + info "error: changing released package $p $cv without version increment" + info " info: use --no-verify git option to suppress" + exit 1 + fi + fi + fi +done diff --git a/bdep-util/git-pre-commit.in b/bdep-util/git-pre-commit.in new file mode 100644 index 0000000..27e76f3 --- /dev/null +++ b/bdep-util/git-pre-commit.in @@ -0,0 +1,17 @@ +#! /usr/bin/env bash + +# file : bdep-util/git-pre-commit.in +# license : MIT; see accompanying LICENSE file + +# Execute various pre-commit scripts in a git repository. +# +trap 'exit 1' ERR + +scr_dir="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" + +# Run each hook checking the exit status and bailing out if unsuccessful. We +# can just exec the last one. +# +"$scr_dir/bdep-git-pre-commit-version-check" + +exec "$scr_dir/bdep-git-pre-commit-copyright-check" diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 0000000..4a730a3 --- /dev/null +++ b/build/.gitignore @@ -0,0 +1,3 @@ +config.build +root/ +bootstrap/ diff --git a/build/bootstrap.build b/build/bootstrap.build new file mode 100644 index 0000000..8416065 --- /dev/null +++ b/build/bootstrap.build @@ -0,0 +1,10 @@ +# file : build/bootstrap.build +# license : MIT; see accompanying LICENSE file + +project = bdep-util + +using version +using config +using dist +using test +using install diff --git a/build/export.build b/build/export.build new file mode 100644 index 0000000..54f91e8 --- /dev/null +++ b/build/export.build @@ -0,0 +1,19 @@ +# file : build/export.build +# license : MIT; see accompanying LICENSE file + +$out_root/ +{ + include bdep-util/ +} + +switch $import.target +{ + case exe{bdep-git-pre-commit} + export $out_root/bdep-util/exe{bdep-git-pre-commit} + + case exe{bdep-git-pre-commit-version-check} + export $out_root/bdep-util/exe{bdep-git-pre-commit-version-check} + + case exe{bdep-git-pre-commit-copyright-check} + export $out_root/bdep-util/exe{bdep-git-pre-commit-copyright-check} +} diff --git a/build/root.build b/build/root.build new file mode 100644 index 0000000..122be6a --- /dev/null +++ b/build/root.build @@ -0,0 +1,6 @@ +# file : build/root.build +# license : MIT; see accompanying LICENSE file + +# Bash. +# +using bash diff --git a/buildfile b/buildfile new file mode 100644 index 0000000..efb049e --- /dev/null +++ b/buildfile @@ -0,0 +1,9 @@ +# file : buildfile +# license : MIT; see accompanying LICENSE file + +./: {*/ -build/} doc{INSTALL NEWS README} legal{LICENSE AUTHORS} manifest + +# Don't install tests or the INSTALL file. +# +tests/: install = false +doc{INSTALL}@./: install = false diff --git a/manifest b/manifest new file mode 100644 index 0000000..ba271a5 --- /dev/null +++ b/manifest @@ -0,0 +1,21 @@ +: 1 +name: bdep-util +version: 0.14.0-a.0.z +project: build2 +summary: extra build2 project management utilities +license: MIT +topics: project dependency management, build toolchain +description-file: README +changes-file: NEWS +url: https://build2.org +doc-url: https://build2.org/doc.xhtml +src-url: https://git.build2.org/cgit/bdep-util/tree/ +email: users@build2.org +build-warning-email: builds@build2.org +builds: all +builds: -windows ; Requires bash. +builds: -macos ; Requires bash >= 4.3. +requires: bash >= 4.3 +depends: * build2 >= 0.13.0 +depends: * bpkg >= 0.13.0 +depends: libbutl.bash [0.14.0-a.0.1 0.14.0-a.1) diff --git a/repositories.manifest b/repositories.manifest new file mode 100644 index 0000000..8f3604c --- /dev/null +++ b/repositories.manifest @@ -0,0 +1,6 @@ +: 1 +summary: extra build2 project management utilities + +: +role: prerequisite +location: ../libbutl.bash.git##HEAD diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..35ec43f --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,2 @@ +test/ +test-*/ diff --git a/tests/build/.gitignore b/tests/build/.gitignore new file mode 100644 index 0000000..4a730a3 --- /dev/null +++ b/tests/build/.gitignore @@ -0,0 +1,3 @@ +config.build +root/ +bootstrap/ diff --git a/tests/build/bootstrap.build b/tests/build/bootstrap.build new file mode 100644 index 0000000..c9187a6 --- /dev/null +++ b/tests/build/bootstrap.build @@ -0,0 +1,8 @@ +# file : tests/build/bootstrap.build +# license : MIT; see accompanying LICENSE file + +project = # Unnamed subproject. + +using config +using dist +using test diff --git a/tests/build/root.build b/tests/build/root.build new file mode 100644 index 0000000..90257ce --- /dev/null +++ b/tests/build/root.build @@ -0,0 +1,12 @@ +# file : tests/build/root.build +# license : MIT; see accompanying LICENSE file + +# Setup the targets that we are testing. +# +import git_pre_commit = bdep-util%exe{bdep-git-pre-commit} + +import git_pre_commit_version_check = \ + bdep-util%exe{bdep-git-pre-commit-version-check} + +import git_pre_commit_copyright_check = \ + bdep-util%exe{bdep-git-pre-commit-copyright-check} diff --git a/tests/buildfile b/tests/buildfile new file mode 100644 index 0000000..fb17c95 --- /dev/null +++ b/tests/buildfile @@ -0,0 +1,24 @@ +# file : tests/buildfile +# license : MIT; see accompanying LICENSE file + +define common: file +common{*}: extension = testscript + +commons = git-common git-pre-commit-common + +./: testscript{* -{$commons}} common{$commons} + +testscript{git-pre-commit}@./: $git_pre_commit +{ + test = $git_pre_commit +} + +testscript{git-pre-commit-version-check}@./: $git_pre_commit_version_check +{ + test = $git_pre_commit_version_check +} + +testscript{git-pre-commit-copyright-check}@./: $git_pre_commit_copyright_check +{ + test = $git_pre_commit_copyright_check +} diff --git a/tests/git-common.testscript b/tests/git-common.testscript new file mode 100644 index 0000000..aa90f3d --- /dev/null +++ b/tests/git-common.testscript @@ -0,0 +1,17 @@ +# file : tests/git-common.testscript +# license : MIT; see accompanying LICENSE file + +# Set commonly-used variables and create an empty git repository that will be +# copied by subsequent tests and scope setup commands. +# +g = git >! 2>&1 +gp = $g -C prj +ga = $gp add +gr = $gp rm + ++$g init prj &prj/*** + ++$gp config user.name 'Test Script' ++$gp config user.email 'testscript@example.com' + +clone_prj = cp --no-cleanup -r ../prj ./ &prj/*** diff --git a/tests/git-pre-commit-common.testscript b/tests/git-pre-commit-common.testscript new file mode 100644 index 0000000..ae8b9d4 --- /dev/null +++ b/tests/git-pre-commit-common.testscript @@ -0,0 +1,13 @@ +# file : tests/git-pre-commit-common.testscript +# license : MIT; see accompanying LICENSE file + +# Set commonly-used variables and configure git to call the hook being tested. +# Assume that git-common.testscript is already included. +# +gc = $gp commit -a --allow-empty-message -m '' + +hooks_dir=$~/hooks ++mkdir $hooks_dir ++$gp config core.hooksPath $hooks_dir + ++ln -s $0 $hooks_dir/pre-commit diff --git a/tests/git-pre-commit-copyright-check.testscript b/tests/git-pre-commit-copyright-check.testscript new file mode 100644 index 0000000..f8e51f5 --- /dev/null +++ b/tests/git-pre-commit-copyright-check.testscript @@ -0,0 +1,25 @@ +# file : tests/git-pre-commit-copyright-check.testscript +# license : MIT; see accompanying LICENSE file + +.include git-common.testscript git-pre-commit-common.testscript + +: basic +: +{ + $clone_prj; + + cat <=prj/LICENSE; + Copyright (c) 2014-2019 the build2 authors. + EOI + $ga .; + + $gc 2>>EOE; + WARNING: last copyright year in 'LICENSE' is 2019 + EOE + + date +"%Y" | set year; + cat <<"EOI" >=prj/LICENSE; + Copyright (c) 2014-$year the build2 authors. + EOI + $gc +} diff --git a/tests/git-pre-commit-version-check.testscript b/tests/git-pre-commit-version-check.testscript new file mode 100644 index 0000000..28e4efc --- /dev/null +++ b/tests/git-pre-commit-version-check.testscript @@ -0,0 +1,263 @@ +# file : tests/git-pre-commit-version-check.testscript +# license : MIT; see accompanying LICENSE file + +.include git-common.testscript git-pre-commit-common.testscript + ++bash --version >&2 2>! # For troubleshooting. + +: multi-package-project +: +{ + $clone_prj; + + touch prj/TODO; + $ga .; + $gc; # Initial commit. + + echo '@@' >=prj/TODO; + $gc; # No committed packages.manifest. + + cat <=prj/packages.manifest; + : 1 + location: libfoo/ + : + location: libbar/ + : + location: libbaz/ + EOI + $ga .; + + $gc 2>>EOE; # packages.manifest is staged. + warning: package manifest file libfoo/manifest does not exist + warning: package manifest file libbar/manifest does not exist + warning: package manifest file libbaz/manifest does not exist + EOE + + echo '@@ todo' >=prj/TODO; + + # packages.manifest is committed but there are no package manifests. + # + $gc 2>>EOE; + warning: package manifest file libfoo/manifest does not exist + warning: package manifest file libbar/manifest does not exist + warning: package manifest file libbaz/manifest does not exist + EOE + + mkdir prj/libfoo prj/libbar prj/libbaz; + cat <=prj/libfoo/manifest; + : 1 + name: libfoo + version: 1.2.3-a.1.z + summary: Foo + EOI + cat <=prj/libbar/manifest; + : 1 + name: libbar + version: 1.2.3 + summary: Bar + EOI + cat <=prj/libbaz/manifest; + : 1 + name: libbaz + version: 0+1 + summary: Baz + EOI + $ga .; + + $gc; # Same as above plus the package manifests are + # staged. + + echo '@@ TODO' >=prj/TODO; + + $gc; # Packages are committed but the staged change + # goes outside the package directories. + + touch prj/libfoo/TODO prj/libbar/TODO prj/libbaz/TODO; + $ga libfoo/TODO; + + $gc; # Package with an open version (snapshot) is + # changed. + + $ga libbar/TODO; + + $gc 2>>EOE != 0; # Package with a final version is changed. + error: changing released package libbar 1.2.3 without version increment + info: use --no-verify git option to suppress + EOE + + sed -i -e 's/^(version:).+$/\1 1.2.4-a.1.z/' prj/libbar/manifest; + + $gc; # Open package development circle. + + echo '@@' >=prj/libbar/TODO; + + $gc; # Development cycle is open. + + $ga libbaz/TODO; + + $gc 2>>EOE != 0; # Package with a stub version is changed. + error: changing released package libbaz 0+1 without version increment + info: use --no-verify git option to suppress + EOE + + sed -i -e 's/^(version:).+$/\1 0+2/' prj/libbaz/manifest; + + $gc; # Release the stub package revision. + + sed -i -e 's/^(version:).+$/\1 1.2.3/' prj/libfoo/manifest; + + $gc; # Release new version. + + echo '@@ todo' >=prj/libfoo/TODO; + + $gc 2>>EOE != 0; # Package with a final version is changed. + error: changing released package libfoo 1.2.3 without version increment + info: use --no-verify git option to suppress + EOE + + $gr libfoo/manifest &!prj/libfoo/manifest; + + $gc 2>>EOE; # The manifest removal is staged (not a package now). + warning: package manifest file libfoo/manifest does not exist + EOE + + sed -i -e 's/^(version:).+$/\1 1.2.4/' prj/libbar/manifest; + + $gc 2>>EOE; # Release new version. + warning: package manifest file libfoo/manifest does not exist + EOE + + echo '@@ todo' >=prj/libbar/TODO; + + $gc 2>>EOE != 0; # Package with a final version is changed. + warning: package manifest file libfoo/manifest does not exist + error: changing released package libbar 1.2.4 without version increment + info: use --no-verify git option to suppress + EOE + + cat <=prj/packages.manifest; + : 1 + location: libbaz/ + EOI + + $gc; # The package removal from packages.manifest is + # staged, so it's not a package anymore. + + cat <=prj/packages.manifest; + : 1 + location: lib/baz/ + EOI + mkdir prj/lib; + mv prj/libbaz prj/lib/baz; + $ga .; + + $gc 2>>EOE != 0; # Package with a stub version is moved. + error: moving released package libbaz 0+2 + info: use --no-verify git option to suppress + EOE + + sed -i -e 's/^(version:).+$/\1 0+3/' prj/lib/baz/manifest; + + $gc # Release the stub package revision. +} + +: single-package-project +: +{ + $clone_prj; + + cat <=prj/manifest; + : 1 + name: foo + version: 1.2.3 + summary: Foo + EOI + touch prj/TODO; + $ga .; + + $gc 2>|; # No committed manifest. + + echo '@@' >=prj/TODO; + + $gc 2>>EOE != 0; # Package with a final version is changed. + error: changing released package foo 1.2.3 without version increment + info: use --no-verify git option to suppress + EOE + + sed -i -e 's/^(version:).+$/\1 1.2.4-a.1.123/' prj/manifest; + + $gc; # Open package development circle. + + echo '@@ todo' >=prj/TODO; + + $gc; # Development cycle is open. + + sed -i -e 's/^(version:).+$/\1 1.2.4/' prj/manifest; + + $gc; # Release new version. + + echo '@@ TODO' >=prj/TODO; + + $gc 2>>EOE != 0; # Package with a final version is changed. + error: changing released package foo 1.2.4 without version increment + info: use --no-verify git option to suppress + EOE + + $gr manifest &!prj/manifest; + + # Make sure there is no warning. + # + $gc 2>:'' # The manifest removal is staged, so it's not a + # package anymore. +} + +: warnings +: +{ + +$clone_prj + + : no-name + : + { + $clone_prj; + + cat <=prj/manifest; + : 1 + summary: Foo + EOI + $ga .; + + $gc 2>"warning: package name is missing in ./manifest" + } + + : no-version + : + { + $clone_prj; + + cat <=prj/manifest; + : 1 + name: libfoo + summary: Foo + EOI + $ga .; + + $gc 2>"warning: package version is missing in ./manifest" + } + + : invalid-version + : + { + $clone_prj; + + cat <=prj/manifest; + : 1 + name: libfoo + version: abc + summary: Foo + EOI + $ga .; + + $gc 2>"warning: package version 'abc' in ./manifest is not a valid standard version" + } +} diff --git a/tests/git-pre-commit.testscript b/tests/git-pre-commit.testscript new file mode 100644 index 0000000..8b8f140 --- /dev/null +++ b/tests/git-pre-commit.testscript @@ -0,0 +1,42 @@ +# file : tests/git-pre-commit.testscript +# license : MIT; see accompanying LICENSE file + +.include git-common.testscript git-pre-commit-common.testscript + +: version-check +: +{ + $clone_prj; + + cat <=prj/manifest; + : 1 + name: foo + version: 1.2.3 + summary: Foo + EOI + touch prj/TODO; + $ga .; + $gc; # No committed manifest. + + echo '@@' >=prj/TODO; + + $gc 2>>EOE != 0 # Package with a final version is changed. + error: changing released package foo 1.2.3 without version increment + info: use --no-verify git option to suppress + EOE +} + +: copyright-check +: +{ + $clone_prj; + + cat <=prj/LICENSE; + Copyright (c) 2014-2019 the build2 authors. + EOI + $ga .; + + $gc 2>>EOE + WARNING: last copyright year in 'LICENSE' is 2019 + EOE +} -- cgit v1.1