diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 607e4ab7..c7dfbdc3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -47,7 +47,7 @@ repos: - id: insert-license name: Insert license headers (shell-style comments) files: '(?:^|/)(?:.*\.(?:py|sh|toml|ya?ml|cfg|ini)|Dockerfile|Makefile|nginx.conf)$' - exclude: '(?:^|/)\..+|^docs/Makefile$' + exclude: '(?:^|/)\..+|^docs/Makefile$|^base/hooks/\+pre-commit.sh$' args: - --detect-license-in-X-top-lines=15 - --license-filepath diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 00000000..89de3547 --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,17 @@ +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/Makefile b/Makefile index 287791eb..2b9e9709 100644 --- a/Makefile +++ b/Makefile @@ -310,6 +310,7 @@ run-jupyter-notebook: jupyter-notebook run-capella/remote: capella/remote docker run $(DOCKER_RUN_FLAGS) \ + -v $$(pwd)/volumes/workspace:/workspace \ -e RMT_PASSWORD=$(RMT_PASSWORD) \ -p $(RDP_PORT):3389 \ -p $(METRICS_PORT):9118 \ diff --git a/base/Dockerfile b/base/Dockerfile index cbfea8d3..ade6d679 100644 --- a/base/Dockerfile +++ b/base/Dockerfile @@ -42,19 +42,32 @@ RUN useradd -l -m -u $UID techuser && \ && chown techuser /home/techuser ENV HOME=/home/techuser - # This in analogous to the virtualenv activate script # To allow deactivation of the virtualenv, we need to save the old PATH ENV _OLD_VIRTUAL_PATH="$PATH" ENV VIRTUAL_ENV=/opt/.venv ENV PATH="$VIRTUAL_ENV/bin:$PATH" +COPY --chmod=755 hooks/* /opt/git/global-hooks/ + +WORKDIR /opt/git/global-hooks + RUN ln -s "$(which python3.11)" /usr/bin/python && \ ln -sf "$(which python3.11)" /usr/bin/python3 && \ ln -sf "$(which pip3.11)" /usr/local/bin/pip && \ ln -sf "$(which pip3.11)" /usr/local/bin/pip3 && \ python -m venv /opt/.venv && \ - chmod -R 777 /opt/.venv/bin/ && \ - chmod -R 777 /opt/.venv/lib/python3.11/site-packages + # Configure pre-commit + pip install pre-commit==3.4.0 --no-cache-dir && \ + echo "commit-msg post-rewrite pre-commit pre-merge-commit pre-rebase prepare-commit-msg" | xargs -n 1 cp /opt/git/global-hooks/+pre-commit-only.sh && \ + echo "pre-push post-checkout post-commit post-merge" | xargs -n 1 cp /opt/git/global-hooks/+pre-commit-and-lfs.sh && \ + git config --global core.hooksPath /opt/git/global-hooks && \ + chmod -R 755 /opt/git/global-hooks && \ + chown -R techuser /opt/.venv/bin/ /opt/.venv/lib/python3.11/site-packages + +# Make pre-commit cache persistent +ENV PRE_COMMIT_HOME=/workspace/.pre-commit + +WORKDIR /workspace USER techuser diff --git a/base/hooks/+pre-commit-and-lfs.sh b/base/hooks/+pre-commit-and-lfs.sh new file mode 100755 index 00000000..0d781073 --- /dev/null +++ b/base/hooks/+pre-commit-and-lfs.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors +# SPDX-License-Identifier: Apache-2.0 + +STAGE=$(basename "$0") + +exec /opt/git/global-hooks/+pre-commit.sh $STAGE "$@" +exec git lfs $STAGE "${@:2}" diff --git a/base/hooks/+pre-commit-only.sh b/base/hooks/+pre-commit-only.sh new file mode 100755 index 00000000..916fa16a --- /dev/null +++ b/base/hooks/+pre-commit-only.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors +# SPDX-License-Identifier: Apache-2.0 + +exec /opt/git/global-hooks/+pre-commit.sh $(basename "$0") "$@" diff --git a/base/hooks/+pre-commit.sh b/base/hooks/+pre-commit.sh new file mode 100755 index 00000000..d79f4466 --- /dev/null +++ b/base/hooks/+pre-commit.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# SPDX-FileCopyrightText: Copyright (c) 2014 pre-commit dev team: Anthony Sottile, Ken Struys +# SPDX-License-Identifier: MIT + +# File generated by pre-commit: https://pre-commit.com +# Modified by the Capella Docker images maintainers. + +STAGE=$1 + +# Skip pre-commit when running in the pre-commit cache directory. +# Otherwise, it will lead to a deadlock. +# pre-commit locks the cache directory, then clones the required repositories in the cache directory. +# This triggers the post-checkout hook of the repository, which tries to acquire the pre-commit lock. +[[ $PWD != /workspace/.pre-commit/* ]] || exit 0 + +# start templated +INSTALL_PYTHON=/opt/.venv/bin/python +ARGS=(hook-impl --config=.pre-commit-config.yaml --hook-type=$STAGE --skip-on-missing-config) +# end templated + +HERE="$(cd "$(dirname "$0")" && pwd)" +ARGS+=(--hook-dir "$HERE" -- "${@:2}") + +if [ -x "$INSTALL_PYTHON" ]; then + exec "$INSTALL_PYTHON" -mpre_commit "${ARGS[@]}" +elif command -v pre-commit > /dev/null; then + exec pre-commit "${ARGS[@]}" +else + echo '`pre-commit` not found. Please report this error: https://github.com/DSD-DBS/capella-dockerimages/issues' 1>&2 + exit 1 +fi diff --git a/capella/Dockerfile b/capella/Dockerfile index 08004296..a2749667 100644 --- a/capella/Dockerfile +++ b/capella/Dockerfile @@ -133,7 +133,7 @@ RUN mkdir -p /opt/capella/configuration/.settings; \ ## Do not show WORKSPACE_SELECTION_DIALOG echo "SHOW_WORKSPACE_SELECTION_DIALOG=false" >> /opt/capella/configuration/.settings/org.eclipse.ui.ide.prefs; \ # Setup workspace - mkdir /workspace; \ + mkdir -p /workspace; \ ## Disable Welcome Screen mkdir -p /workspace/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs; \ # Set workspace permissions diff --git a/docs/docs/git-hooks/egit-failed-git-hook.png b/docs/docs/git-hooks/egit-failed-git-hook.png new file mode 100644 index 00000000..f7b36297 Binary files /dev/null and b/docs/docs/git-hooks/egit-failed-git-hook.png differ diff --git a/docs/docs/git-hooks/egit-failed-git-hook.png.license b/docs/docs/git-hooks/egit-failed-git-hook.png.license new file mode 100644 index 00000000..a990c045 --- /dev/null +++ b/docs/docs/git-hooks/egit-failed-git-hook.png.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors +SPDX-License-Identifier: Apache-2.0 diff --git a/docs/docs/git-hooks/git-hooks.md b/docs/docs/git-hooks/git-hooks.md new file mode 100644 index 00000000..70df336f --- /dev/null +++ b/docs/docs/git-hooks/git-hooks.md @@ -0,0 +1,55 @@ + + +# Support for Git Hooks + +To support Git hooks, we have decided to utilize the [pre-commit](https://pre-commit.com/) framework. This framework allows for automatic fetching and updating of hooks from external sources, providing users with a high level of flexibility and adaptability. Additionally, it effectively decouples the development process of Git hooks from our Docker image release lifecycle. + +The implementation was tested with the official Git CLI and JGit/EGit (in Eclipse). + +## Project-Specific Hooks + +Project-specific hooks can be defined separately for each Git repository. The defined Git hooks will not be auto-updated by us. Instead, the responsibility falls on the repository owners to keep them up-to-date and maintain them. + +### Installation + +To install Git hooks, add a `.pre-commit-config.yaml` file to the root of your repository. Simply follow the official pre-commit instructions: [Add a pre-commit configuration](https://pre-commit.com/#2-add-a-pre-commit-configuration). Commit the file after making changes. Git will automatically detect it, eliminating the need to explicitly install the hooks via `pre-commit install`. + + +!!! info + `pre-commit` is installed for all stages by default. This means that your pre-commit hooks will run at every stage. + If you want to limit the hooks to specific stages, for example, to run hooks only at the `pre-commit` stage, add the following to your `.pre-commit-config.yaml` file: + + ```yaml + default_stages: [pre-commit] + ``` + + Alternatively, specify stages for each hook individually: + + ```yaml + - repo: local + hooks: + - id: my-hook + stages: [pre-commit] + ``` + + For more information, refer to the `pre-commit` documentation: [Confining hooks to run at certain stages](https://pre-commit.com/#confining-hooks-to-run-at-certain-stages). + +### Updates + +To auto-update Git hooks, update the versions in your repository's `.pre-commit-config.yaml` file. Refer to the official documentation for [updating hooks automatically](https://pre-commit.com/#updating-hooks-automatically). + +## Technical Background + +To facilitate this implementation, we have globally set the `core.hooksPath` configuration option in Git to `/opt/git/global-hooks`. We initialize the pre-commit framework in this directory. This ensures that the hook is registered as `/opt/git/global-hooks/pre-commit`. Since the initialization of Git hooks with the pre-commit framework can be slow, we maintain a cache of the pre-commit environment and store it in the persistent `/workspace` directory. + +## Troubleshooting + + +!!! warning "Error Message in Eclipse with EGit" + If you receive an error message in Eclipse (as shown below) while committing, your pre-commit has failed. + ![Empty error message in Eclipse with EGit](./egit-failed-git-hook.png) + + Please check the Capella logs, located at `/var/logs`. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index f29d6bf0..81fbbfb8 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -13,6 +13,7 @@ theme: nav: - Introduction: index.md - Base: base.md + - Git hooks (pre-commit): git-hooks/git-hooks.md - CI/CD templates: - Index: ci-templates/index.md - Gitlab: diff --git a/eclipse/Dockerfile b/eclipse/Dockerfile index 1b9b0cd8..744ff320 100644 --- a/eclipse/Dockerfile +++ b/eclipse/Dockerfile @@ -35,7 +35,7 @@ RUN tar -xf eclipse.tar.gz && \ ARG MEMORY_LIMIT=5500m -RUN mkdir /workspace; \ +RUN mkdir -p /workspace; \ # Disable Welcome Screen mkdir -p /workspace/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs; \ # Set workspace permissions diff --git a/papyrus/Dockerfile b/papyrus/Dockerfile index b8bb78c5..6e230cea 100644 --- a/papyrus/Dockerfile +++ b/papyrus/Dockerfile @@ -19,7 +19,7 @@ RUN tar -xf papyrus.tar.gz && \ ARG MEMORY_LIMIT=5500m -RUN mkdir /workspace; \ +RUN mkdir -p /workspace; \ # Disable Welcome Screen mkdir -p /workspace/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs; \ # Set workspace permissions