From ce1e5f5b36f7e7f49f803d7d8f7cea3e362b33a0 Mon Sep 17 00:00:00 2001 From: Donatas Navidonskis Date: Fri, 1 Mar 2024 14:23:22 +0200 Subject: [PATCH 1/9] chore: add .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e8f16b9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# ignore goreleaser files +/dist/ From f9f37e683ce9ba7cc4de25cb5201b235e2f7ca92 Mon Sep 17 00:00:00 2001 From: Donatas Navidonskis Date: Fri, 1 Mar 2024 14:24:29 +0200 Subject: [PATCH 2/9] chore: adjust goreleaser config to use checksums and different name of snapshots --- .goreleaser.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 20fc66c..1986bbe 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -10,3 +10,9 @@ builds: # merged to the main branch. If this is a Go project, you can remove this section # and use the default configuration to release the packages within the new version. - skip: true + +checksum: + name_template: "checksums.txt" + +snapshot: + name_template: "{{ .Tag }}-next" From e4467279aceb4375b28dfa7214e84d4ad3d99360 Mon Sep 17 00:00:00 2001 From: Donatas Navidonskis Date: Fri, 1 Mar 2024 14:24:45 +0200 Subject: [PATCH 3/9] chore: add default config of .lefthook.yaml --- .lefthook.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .lefthook.yaml diff --git a/.lefthook.yaml b/.lefthook.yaml new file mode 100644 index 0000000..4394e24 --- /dev/null +++ b/.lefthook.yaml @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: Copyright Boozt Fashion, AB +# SPDX-License-Identifier: MIT + +extends: + # lint commit messages based by the conventional commits + - hooks/commitlint/.lefthook.yaml + # lint Dockerfiles + - hooks/hadolint/.lefthook.yaml + # lint shell scripts + - hooks/shellcheck/.lefthook.yaml From 7e67a36d0707ce89b7d9345c0790d6e3a2bbce1e Mon Sep 17 00:00:00 2001 From: Donatas Navidonskis Date: Fri, 1 Mar 2024 14:25:04 +0200 Subject: [PATCH 4/9] feat: automation of the hook creation --- Makefile | 38 +++++++++++++++++++++ add-hook.sh | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 Makefile create mode 100755 add-hook.sh diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1a56877 --- /dev/null +++ b/Makefile @@ -0,0 +1,38 @@ +# SPDX-FileCopyrightText: Copyright Boozt Fashion, AB +# SPDX-License-Identifier: MIT + +SHELL := /usr/bin/env bash +.DEFAULT_GOAL := build +NAME ?= "" +DOCKERFILE ?= "false" + +.PHONY: build +build: container_build container_scanning + +.PHONY: container_build +container_build: + @docker build \ + -t ${NAME} \ + --file "${PWD}/hooks/${NAME}/Dockerfile" \ + . + +.PHONY: container_run +run: container_run +container_run: + @docker run --rm -it \ + -v ${PWD}:/app \ + ${NAME} \ + bash + +.PHONY: container_scanning +scan: container_scanning +container_scanning: + @docker run --rm \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v ${HOME}/.trivy:/root/.cache/ \ + aquasec/trivy:0.38.3 \ + image --no-progress --exit-code 1 --severity CRITICAL ${NAME} + +.PHONY: add_hook +add_hook: + @NAME=$(NAME) DOCKERFILE=$(DOCKERFILE) $(PWD)/add-hook.sh diff --git a/add-hook.sh b/add-hook.sh new file mode 100755 index 0000000..e17e35c --- /dev/null +++ b/add-hook.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash + +# SPDX-FileCopyrightText: Copyright Boozt Fashion, AB +# SPDX-License-Identifier: MIT + +export NAME="${NAME:-""}" +export DOCKERFILE="${DOCKERFILE:-false}" + +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +HOOKS_DIR="hooks" +HOOKS_PATH="${SCRIPT_DIR}/${HOOKS_DIR}" + +# error message function printing in red color +# usage: error "message" +error() { + local message=${1:-""} + echo -e "\033[0;31m${message}\033[0m" +} + +# create hooks dir if not exists +if [ ! -d "${HOOKS_PATH}" ]; then + mkdir -p "${HOOKS_PATH}" +fi + +# check if the NAME environment variable is not empty +if [ -z "$NAME" ]; then + error "The NAME environment variable is empty" + exit 1 +fi + +# check if the given module name not yet exists to be able to create a new module +if [ -d "${HOOKS_PATH}/${NAME}" ]; then + error "The module ${NAME} already exists" + exit 1 +fi + +# create a new module directory +mkdir -p "${HOOKS_PATH}/${NAME}" + +# create .lefthook.yaml file with the SPDX license in it +cat > "${HOOKS_PATH}/${NAME}/.lefthook.yaml" < "${HOOKS_PATH}/${NAME}/Dockerfile" < Date: Fri, 1 Mar 2024 14:25:22 +0200 Subject: [PATCH 5/9] docs: updating contribution guide of creating a new hook --- docs/CONTRIBUTING.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index c4eff8c..9fed2ce 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -13,6 +13,7 @@ Thank you for considering contributing to our project! Your contributions are hi 1. [Updating Tests](#updating-tests) 1. [Updating Code](#updating-code) 1. [Creating a Pull Request](#creating-a-pull-request) +1. [Creating a new hook](#creating-a-new-hook) 1. [License Information](#license-information) 1. [Merging and Releasing](#merging-and-releasing) @@ -74,6 +75,29 @@ Once you've made your changes and are ready to contribute them back to the proje Be sure to follow the pull request template, if one is provided. +## Creating a new hook + +To create a new hook, follow these steps: + +1. Run `make add_hook [options]` (i.e. `make add_hook NAME=jslint`). Below are the available options you can pass: + +Name|Description|Required|Default| +---|---|---|---| +NAME|The name of the hook|Yes|| +DOCKERFILE|Boolean option to create an empty Dockerfile file in the hook folder with the license included|No|False| + +2. Add necessary files to your new hook. +3. Adjust the `.lefthook.yaml` file to execute your new hook. You can use either a script or Docker. It's recommended to use Docker unless it's a simple bash script or specific to a development niche (such as frontend - JavaScript, CSS, or backend - Go, Python). +4. Update the README.md documentation to include your new hook in the list of available hooks and provide a brief description. +5. If you requested to create a Dockerfile, the script will output the `yaml` options to add to the `.goreleaser.yaml` file. These options facilitate the creation of a Docker image for various OS architectures. +6. To run tests against your Docker image, you can use the following commands: + + - `make NAME=` or `make build NAME=`: This command builds the image and runs the security check. For example: `make NAME=jslint`. + - Alternatively, you can execute these commands individually: + - `make container_build NAME=`: Builds the Docker image. + - `make container_scan NAME=`: Performs a security scan on the Docker image. + - `make container_run NAME=`: Runs the Docker image. + ## License Information To ensure proper attribution and compliance with licensing terms, we require that all source code files include a [short-form SPDX ID][spdx-license-info] license comment block. This block should be added at the top of each source code file. From 1d4595a6083527775bb8fe775156f2314d279727 Mon Sep 17 00:00:00 2001 From: Donatas Navidonskis Date: Fri, 1 Mar 2024 14:26:44 +0200 Subject: [PATCH 6/9] docs: how to use it and available hooks sections, adjust the project info --- README.md | 56 ++++++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index f9d1505..762e8a4 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,42 @@ - [][homepage] -[![GitHub Tag (latest SemVer)](https://img.shields.io/github/v/tag/boozt-platform/quickstart-template.svg?label=latest&sort=semver)][releases] +[![GitHub Tag (latest SemVer)](https://img.shields.io/github/v/tag/boozt-platform/lefthook.svg?label=latest&sort=semver)][releases] [![license](https://img.shields.io/badge/license-mit-brightgreen.svg)][license] - -# quickstart-template +# lefthook -Quickstart template for GitHub repositories. You may use this template to create new repositories with a predefined structure. - +Various organizational hooks based on the [lefthook](https://github.com/evilmartians/lefthook) for development and continuous integration. Hooks enforce consistent practices across all commits and deployments. - ## Table of Contents - [How to Use It](#how-to-use-it) +- [Available Hooks](#available-hooks) - [About Boozt](#about-boozt) - [Reporting Issues](#reporting-issues) - [Contributing](#contributing) - [License](#license) - - ## How to Use It -This project is a template repository with various guidelines, the required CI release versioning pipeline, licenses, and more. You may use this project as a reference to start a new repository. Once you've created a new repository from this template, update the `README.md` file content according to your needs. +```yaml +remotes: + - git_url: git@github.com/boozt-platform/lefthook + ref: v1.0.0 + configs: + # lint commit messages based by the conventional commits + - hooks/commitlint/.lefthook.yaml + # lint Dockerfiles + - hooks/hadolint/.lefthook.yaml + # lint shell scripts + - hooks/shellcheck/.lefthook.yaml +``` + +## Available Hooks + + - [commitlint](./hooks/commitlint/) (**commit-msg**) - Lint commit messages based by the conventional commits + - [hadolint](./hooks/hadolint/) (**pre-commit**) - A smarter Dockerfile linter + - [shellcheck](./hooks/shellcheck/) (**pre-commit**) - a static analysis tool for shell scripts -It is necessary to maintain consistency and structure in this `README.md` file. Please follow the action items below and the comment blocks of this file (``): - -- [x] Create repository from this quickstart template. -- [ ] Update Title & Description -- [ ] Add extra header badges if needed. Please keep the License, SemVer badges, and Logo image the same as they were distributed within this file. -- [ ] Update body content according to your project. -- [ ] Update the Table of Contents (TOC) based on your updated body content. -- [ ] Please keep the footer the same as it was distributed within this file. -- [ ] Remove all comment blocks from this `README.md` file i.e. ` `. -- [ ] Remove this [How to Use It](#how-to-use-it) section. -- [ ] Update [docs/CODEOWNERS](docs/CODEOWNERS) file. -- [ ] Update [.goreleaser.yaml](.goreleaser.yaml) to your needs, this file and CI pipeline [.github/workflows/release.yml](.github/workflows/release.yml) are used to release new versions automatically once the PRs are merged to the main branch. - - - ## About Boozt Boozt is a leading and fast-growing Nordic technology company selling fashion and lifestyle online mainly through its multi-brand webstore [Boozt.com][boozt] and [Booztlet.com][booztlet]. @@ -68,14 +65,13 @@ Contributions are highly valued and very welcome! For the process of reviewing c This project is licensed under the MIT. Please see [LICENSE][license] for full details. -[homepage]: https://github.com/boozt-platform/quickstart-template -[releases]: https://github.com/boozt-platform/quickstart-template/releases -[issues]: https://github.com/boozt-platform/quickstart-template/issues -[pull-request]: https://github.com/boozt-platform/quickstart-template/pulls +[homepage]: https://github.com/boozt-platform/lefthook +[releases]: https://github.com/boozt-platform/lefthook/releases +[issues]: https://github.com/boozt-platform/lefthook/issues +[pull-request]: https://github.com/boozt-platform/lefthook/pulls [contributing]: ./docs/CONTRIBUTING.md [license]: ./LICENSE [boozt]: https://www.boozt.com/ [booztlet]: https://www.booztlet.com/ [blog]: https://medium.com/boozt-tech [careers]: https://careers.booztgroup.com/ - From 9872c9dceae88893e10d15e78b49f61468a93879 Mon Sep 17 00:00:00 2001 From: Donatas Navidonskis Date: Fri, 1 Mar 2024 14:27:02 +0200 Subject: [PATCH 7/9] feat: add linter for git commits --- hooks/commitlint/.lefthook.yaml | 10 ++++++ hooks/commitlint/commitlint.sh | 64 +++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 hooks/commitlint/.lefthook.yaml create mode 100755 hooks/commitlint/commitlint.sh diff --git a/hooks/commitlint/.lefthook.yaml b/hooks/commitlint/.lefthook.yaml new file mode 100644 index 0000000..9cdc998 --- /dev/null +++ b/hooks/commitlint/.lefthook.yaml @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: Copyright Boozt Fashion, AB +# SPDX-License-Identifier: MIT + +commit-msg: + parallel: true + commands: + # Lint commit messages based by the conventional commits + # https://www.conventionalcommits.org/en/v1.0.0/ + commitlint: + run: bash -c "hooks/commitlint/commitlint.sh {0}" diff --git a/hooks/commitlint/commitlint.sh b/hooks/commitlint/commitlint.sh new file mode 100755 index 0000000..e70cdfe --- /dev/null +++ b/hooks/commitlint/commitlint.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +# SPDX-FileCopyrightText: Copyright Boozt Fashion, AB +# SPDX-License-Identifier: MIT + +# Run commitlint.sh script to lint commit messages +# based on the conventional commits specification. +# https://www.conventionalcommits.org/en/v1.0.0/ +# +# Create a new .commitlint configuration environment file +# in the root project to override the default configuration. + +set -euo pipefail + +# error message function printing in red color +# usage: error "message" +error() { + local message=${1:-""} + echo -e "\033[0;31m${message}\033[0m" +} + +commitTitle=$(head -n1 "${1}") +configurationFile=".commitlint" + +# source configuration environment file if exists +if [ -f "$configurationFile" ]; then + # shellcheck source=/dev/null + source "$configurationFile" +fi + +# default values for environment variables +export MAX_COMMIT_MESSAGE_LENGTH=${MAX_COMMIT_MESSAGE_LENGTH:-80} +# valid commit prefix types for semantic versioning +export VALID_COMMIT_PREFIXES=${VALID_COMMIT_PREFIXES:-"build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test"} + +# check commit message length +if [ ${#commitTitle} -gt "${MAX_COMMIT_MESSAGE_LENGTH}" ]; then + error "Your commit message is too long: ${#commitTitle} characters" + exit 1 +fi + +# check if the commit message contains Merge Branch to skip the commit message check +if echo "$commitTitle" | grep -qE 'Merge branch'; then + echo "Skipping commit message check for merge commits" + exit 0 +fi + +# check if the commit message is valid for semantic versioning +if ! echo "$commitTitle" | grep -qE '^('"${VALID_COMMIT_PREFIXES}"')(\([a-z0-9\s\-\_\,]+\))?!?:\s\w'; then + error "Your commit message is not valid for semantic versioning: \"$commitTitle\"" + + echo + echo "Format: (): " + echo "Scope: optional" + echo "Example: feat(auth): add login feature" + echo + echo "Exclamation mark (!) is optional and can be used to indicate breaking changes." + echo "Use it before colon (:). i.e. feat(auth)!: add login feature" + echo + echo "Valid types: ${VALID_COMMIT_PREFIXES//|/,}" + echo + + exit 1 +fi From 51521eb341d0c7d726e31e0869ee95322d765ccc Mon Sep 17 00:00:00 2001 From: Donatas Navidonskis Date: Fri, 1 Mar 2024 14:27:20 +0200 Subject: [PATCH 8/9] feat: add hadolint to lint the dockerfiles --- hooks/hadolint/.lefthook.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 hooks/hadolint/.lefthook.yaml diff --git a/hooks/hadolint/.lefthook.yaml b/hooks/hadolint/.lefthook.yaml new file mode 100644 index 0000000..38fc40b --- /dev/null +++ b/hooks/hadolint/.lefthook.yaml @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: Copyright Boozt Fashion, AB +# SPDX-License-Identifier: MIT + +pre-commit: + parallel: true + commands: + hadolint: + glob: "Dockerfile*" + run: | + docker run --rm -it -v $(pwd):/app -w /app ghcr.io/hadolint/hadolint hadolint {staged_files} From a3f42f7f136c59fe43f919b14ff7e81a1f04c15b Mon Sep 17 00:00:00 2001 From: Donatas Navidonskis Date: Fri, 1 Mar 2024 14:27:32 +0200 Subject: [PATCH 9/9] feat: add shellcheck to lint shell scripts --- hooks/shellcheck/.lefthook.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 hooks/shellcheck/.lefthook.yaml diff --git a/hooks/shellcheck/.lefthook.yaml b/hooks/shellcheck/.lefthook.yaml new file mode 100644 index 0000000..88b5574 --- /dev/null +++ b/hooks/shellcheck/.lefthook.yaml @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: Copyright Boozt Fashion, AB +# SPDX-License-Identifier: MIT + +pre-commit: + parallel: true + commands: + shellcheck: + glob: "*.sh" + run: | + docker run --rm -v $(pwd):/mnt koalaman/shellcheck:stable {staged_files}