{ pkgs ? import <nixpkgs> {}, inputs, phps, lib, config, modulesPath, ... }: { # https://devenv.sh/packages/ packages = with pkgs; [ inputs.version.defaultPackage."${builtins.currentSystem}" appimage-run blackbox blackbox-terminal coreutils-full dbeaver dbeaver delve dialog drill eza fd fd feh gcc12 gdlv git glab gnugrep gnumake gnused go-licenses gosec go-task gum httpie hurl jq libffi logrotate meld memcached netcat nixfmt nodePackages.mermaid-cli openssh procps ranger unixtools.xxd unzip util-linux wget zlib ]; # https://devenv.sh/languages/ # languages.nix.enable = true; languages = { go = { enable = true; }; }; difftastic.enable = true; scripts.run-sshd.exec = '' set -x cd ${config.devenv.root}/docker/sftp-server ${pkgs.docker-client}/bin/docker docker build -t jobqueue-sftp-server . cd - ${pkgs.coreutils}/bin/chmod 700 ${config.devenv.root}/.config/temp_rsa_key ${pkgs.coreutils}/bin/chmod 700 ${config.devenv.root}/.config/temp_ed25518_key ${pkgs.coreutils}/bin/mkdir -p ${config.devenv.root}/.devenv/chroot/home/demo/.ssh ${pkgs.coreutils}/bin/cat ${config.devenv.root}/.config/demo_ssh_key.pub > ${config.devenv.root}/.devenv/chroot/home/demo/.ssh/authorized_keys ${pkgs.coreutils}/bin/chmod 700 ${config.devenv.root}/.devenv/chroot/home/demo/.ssh ${pkgs.coreutils}/bin/chmod 600 ${config.devenv.root}/.devenv/chroot/home/demo/.ssh/authorized_keys ${pkgs.coreutils}/bin/cat <<EOF > ${config.devenv.root}/.config/sshd_config AuthorizedKeysCommand ${pkgs.coreutils}/bin/cat ${config.devenv.root}/.devenv/chroot/home/demo/.ssh/authorized_keys AuthorizedKeysCommandUser nobody Match User root ChrootDirectory ${config.devenv.root}/.devenv/chroot ForceCommand internal-sftp PasswordAuthentication no PermitTunnel no AllowAgentForwarding no AllowTcpForwarding no X11Forwarding no PermitRootLogin no AllowUsers demo root EOF ${pkgs.openssh}/bin/sshd -D -e -o \ HostKey=${config.devenv.root}/.config/temp_rsa_key \ -f ${config.devenv.root}/.config/sshd_config \ -o HostKey=${config.devenv.root}/.config/temp_ed25518_key \ -o Port=''${1:-2222} \ -o AuthorizedKeysFile=${config.devenv.root}/.devenv/chroot/home/demo/.ssh/authorized_keys \ -o PidFile=${config.devenv.root}/.devenv/sshd.pid ''; scripts.draw-graph.exec = '' echo -e "Enter Meirmaid graph definition. ''${RED}End with Ctrl+D''${RESET}\n" diagram=$(${pkgs.gum}/bin/gum write --placeholder "Enter Meirmaid graph definition. End with Ctrl+D") tmpOutput=$(mktemp).png echo "$diagram" | ${pkgs.nodePackages.mermaid-cli}/bin/mmdc -i - -o "$tmpOutput" ${pkgs.feh}/bin/feh $tmpOutput # should delte the file, but does not work ask with gum ${pkgs.gum}/bin/gum confirm "Delete temporary file?" if [ $? -eq 0 ]; then rm "$tmpOutput" else echo "not deleting; file is at $tmpOutput" fi ''; scripts.get-go-default-packages.exec = '' #!${pkgs.bash}/bin/bash echo $(awk -F ' ' '/^module / { print $2 }' go.mod) ''; # This script is executed when the app is built # You can use it to build the app scripts.test-lib.exec = '' #!${pkgs.bash}/bin/bash set -x ${pkgs.gosec}/bin/gosec ${config.devenv.root} ${pkgs.go}/bin/go test -tags=runOnTask -cover -v ${config.devenv.root} ${pkgs.go}/bin/go test -tags=runOnTask -bench -v ${config.devenv.root} ${pkgs.go}/bin/go test -tags=runOnTask -race -v ${config.devenv.root} ''; # This scritp is used to deploy the app to the gitlab registry # It is used by the gitlab-ci.yml file # The environment variables are set in the gitlab project settings scripts.deploy-lib.exec = '' #!${pkgs.bash}/bin/bash PATH="''${PATH}":${pkgs.coreutils}/bin PATH="''${PATH}":${pkgs.jq}/bin/ PATH="''${PATH}":${pkgs.curl}/bin/ PATH="''${PATH}":${pkgs.moreutils}/bin/ PATH="''${PATH}":${pkgs.gnutar}/bin PATH="''${PATH}":${pkgs.gzip}/bin/ PATH="''${PATH}":${pkgs.eza}/bin/ PATH="''${PATH}":${pkgs.git}/bin/ PATH="''${PATH}":${ inputs.version.defaultPackage."${builtins.currentSystem}" }/bin/ export PATH if [[ -f .env-gitlab-ci ]]; then source .env-gitlab-ci rm .env-gitlab-ci fi set -x ## if $HOME not set, set it to current directory if [[ -z "''${HOME}" ]]; then HOME=$(pwd) fi export HOME git config user.email "''${GITLAB_USER_EMAIL}" git config user.name "''${GITLAB_USER_NAME:-"Gitlab CI"}" git config pull.rebase true git config http.sslVerify "false" git remote set-url origin https://pad:''${GITLAB_TOKEN}@''${CI_REPOSITORY_URL#*@} git fetch --all --tags --unshallow git reset --hard origin/master git checkout $CI_COMMIT_REF_NAME git pull origin $CI_COMMIT_REF_NAME if [ ! -z "''${CI_PROJECT_DIR}" ]; then echo "CI_PROJECT_DIR is set, using it as project root." project_root=$(realpath "''${CI_PROJECT_DIR}")/ elif [ ! -z "''${DEVENV_ROOT}" ]; then echo "DEVENV_ROOT is set, using it as project root." project_root=$(realpath "''${DEVENV_ROOT}")/ else echo "Error: DEVENV_ROOT or CI_PROJECT_DIR environment variables are not set." exit 1 fi if [ ! -d "''${project_root}" ]; then echo "Error: Project root directory does not seem to be valid." echo "Check the DEVENV_ROOT or CI_PROJECT_DIR environment variables." exit 1 fi if [ -z "'CI_JOB_TOKEN" ]; then echo "Error: CI_JOB_TOKEN variable is not set." exit 1 fi git --no-pager log --decorate=short --pretty=oneline gitVersion=v$(version predict) git tag -a $gitVersion -m"chore: bump version" git --no-pager log --decorate=short --pretty=oneline git push -o ci.skip origin ''${CI_COMMIT_REF_NAME} --tags echo "done" ''; enterShell = '' cat <<'EOF' > CONTRIBUTING.md # Contributing to schukai GmbH Projects ## Code of Conduct Be a human, not an asshole. Common sense and basic human decency apply. ## Getting Started ### Setting up the Project 1. Fork the project on GitLab. 2. Clone your fork locally. Replace `[your-username]` with your GitLab username and `[project-name]` with the actual project name: ```bash git clone $(git config --get remote.origin.url) ``` 3. Add the upstream repository. Replace `[original-username]` and `[project-name]` with the original repository's username and project name: ```bash git remote add upstream https://gitlab.schukai.com/[original-username]/[project-name].git ``` ### Making Changes 1. Create a new branch: ```bash git checkout -b new-feature-branch ``` 2. Make your changes. 3. Commit your changes: ```bash git commit -m "Description of change" ``` ### Submitting a Merge Request 1. Push your changes to your fork: ```bash git push origin new-feature-branch ``` 2. Navigate to the original project repository on `gitlab.schukai.com`. 3. Open a Merge Request and provide a clear description of the changes. ## Coding Guidelines - Follow the coding style used in the project. - Write unit tests for new features. - Ensure that all tests pass before submitting a Merge Request. ## Reporting Issues If you find an issue, please create a new issue on `gitlab.schukai.com`. ## Additional Resources - [GitLab Flow](https://docs.gitlab.com/ee/topics/gitlab_flow.html) - [GitLab Merge Request Guidelines](https://docs.gitlab.com/ee/user/project/merge_requests/) Thank you for your contribution! EOF cat <<'EOF' > LICENSE Copyright (C) 2023 schukai GmbH This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. EOF cat <<'EOF' > Taskfile.yml # THIS FILE IS AUTOGENERATED BY THE DEVENVSHELL # DO NOT EDIT THIS FILE MANUALLY # INSTEAD EDIT THE DEVENVSHELL CONFIGURATION FILE devenv.nix # AND OPEN A SHELL WITH THE COMMAND devenv shell # # Information about the task runner can be found here: # https://taskfile.dev version: '3' tasks: default: cmds: - task --list silent: true test: desc: Execute unit tests in Go. env: TEST_BY_TASK: true cmds: - docker pull atmoz/sftp:alpine - docker pull axllent/mailpit - echo "Execute unit tests in Go." - test-lib test-fuzz: desc: Conduct fuzzing tests.# env: TEST_BY_TASK: true cmds: - echo "Conduct fuzzing tests." - go test -tags=runOnTask -v -fuzztime=30s -fuzz=Fuzz ./... add-licenses: desc: Attach license headers to Go files. cmds: - echo "Attach license headers to Go files." - go install github.com/google/addlicense@latest - addlicense -c "schukai GmbH" -s -l "AGPL-3.0" ./*.go silent: true check-licenses: desc: Check license headers of Go files. silent: true cmds: - go-licenses save "$(get-go-default-packages)" --ignore "gitlab.schukai.com" --force --save_path ''${DEVENV_ROOT}/licenses/ check: desc: Confirm repository status. cmds: - git diff-index --quiet HEAD || (echo "There are uncommitted changes after running make. Please commit or stash them before running make."; exit 1) silent: true commit: desc: Commit changes to the repository. aliases: - c - ci - git-commit cmds: - do-git-commit EOF cat <<'EOF' > .gitlab-ci.yml # THIS FILE IS AUTOGENERATED BY THE DEVENVSHELL # DO NOT EDIT THIS FILE MANUALLY # INSTEAD EDIT THE DEVENVSHELL CONFIGURATION FILE devenv.nix # AND OPEN A SHELL WITH THE COMMAND devenv shell # image: docker-registry.schukai.com:443/nixos-ci-devenv:latest # services: # - docker:dind variables: # The repo name as used in # https://github.com/nix-community/NUR/blob/master/repos.json NIXOS_VERSION: "23.05" NIXPKGS_ALLOW_UNFREE: "1" NIXPKGS_ALLOW_INSECURE: "1" GIT_DEPTH: 10 stages: - test - deploy before_script: - echo > .env-gitlab-ci - variables=("HOME=$HOME" "CI_COMMIT_REF_NAME=$CI_COMMIT_REF_NAME" "CI_REPOSITORY_URL=$CI_REPOSITORY_URL" "GITLAB_TOKEN=$GITLAB_TOKEN" "CI_JOB_TOKEN=$CI_JOB_TOKEN" "GITLAB_USER_EMAIL=$GITLAB_USER_EMAIL" "GITLAB_USER_NAME=\"$GITLAB_USER_NAME\"" "CI_REGISTRY_USER=$CI_REGISTRY_USER" "CI_PROJECT_ID=$CI_PROJECT_ID" "CI_PROJECT_DIR=$CI_PROJECT_DIR" "CI_API_V4_URL=$CI_API_V4_URL" "CI_PROJECT_NAME=$CI_PROJECT_NAME" "CI_COMMIT_SHORT_SHA=$CI_COMMIT_SHORT_SHA"); for var in "''${variables[@]}"; do echo "$var" >> .env-gitlab-ci; done - cat .env-gitlab-ci - env - nix shell nixpkgs#docker-client -c docker info after_script: - if [ -f .env-gitlab-ci ]; then rm .env-gitlab-ci; fi test: stage: test tags: - nixos script: - devenv shell test-lib cache: - key: nixos paths: - /nix/store artifacts: paths: - dist deploy: stage: deploy tags: - nixos script: - devenv shell -c deploy-lib when: on_success cache: - key: nixos paths: - /nix/store EOF ''; scripts.do-git-commit.exec = '' #!/usr/bin/env bash # Define colors if the terminal supports it if [ -t 1 ]; then RED='\033[0;31m' GREEN='\033[0;32m' RESET='\033[0m' BOLD='\033[1m' else RED="" GREEN="" RESET="" fi step=1 reset clear # create random log file LOGFILE="$(mktemp)" if [ $? -ne 0 ]; then echo -e "''${RED}✖ Could not create temporary log file. Exiting.''${RESET}" exit 1 fi log_and_display() { echo -e "''${GREEN}==> $step. $1''${RESET}" | tee -a $LOGFILE step=$((step + 1)) } log_error_and_display() { echo -e "''${RED}==> $step. $1''${RESET}" | tee -a $LOGFILE } printLogfileAndExit() { exit_code=$1 echo -e "\n\n========================================\n\n\n" echo -e "\n\n''${BOLD}Git and GitLab Automation Script''${RESET}\n\nI have performed the following actions:\n\n" cat "$LOGFILE" # Optional: Remove log file rm -f "$LOGFILE" if [ $exit_code -eq 0 ]; then echo -e "\n''${GREEN}✔''${RESET} All actions were successful" | tee -a $LOGFILE elif [ $exit_code -eq -1 ]; then echo -e "\n''${RED}✖''${RESET} The script was manually cancelled" | tee -a $LOGFILE exit_code=0 else echo -e "\n''${RED}✖''${RESET} Some actions failed" | tee -a $LOGFILE fi exit $exit_code } print_headline() { local title=$1 local underline=$(printf '─%.0s' $(seq 1 ''${#title})) echo -e "\n\n''${BOLD}''${title}\n''${underline}''${RESET}\n" } do_cancel() { echo -e "''${RED}==> ✖ Cancelled.''${RESET}" | tee -a $LOGFILE printLogfileAndExit -1 } # Function for unified logging and display log_action() { if [ $? -eq 0 ]; then echo -e " ''${GREEN}✔''${RESET} $1: Successful" | tee -a $LOGFILE else echo -e " ''${RED}✖''${RESET} $1: Failed" | tee -a $LOGFILE printLogfileAndExit 1 fi } print_what_to_do() { echo -e "\n\nWhat do you want to do?\n" } git_status=$(git status --porcelain) if [[ -z "$git_status" ]]; then log_error_and_display "No changes to commit. Exiting." printLogfileAndExit 0 fi print_headline "Choose commit type" selection=$(gum choose "feat: (new feature for the user, not a new feature for build script)" "fix: (bug fix for the user, not a fix to a build script)" "chore: (updating grunt tasks etc.; no production code change)" "docs: (changes to the documentation)" "style: (formatting, missing semi colons, etc; no production code change)" "refactor: (refactoring production code, eg. renaming a variable)" "test: (adding missing tests, refactoring tests; no production code change)" "Cancel") commit_type=$(echo "$selection" | awk -F':' '{print $1}') if [[ "$commit_type" == "Cancel" ]]; then do_cancel fi log_and_display "You chose the commit type: $commit_type" # NEXT STEP ISSUE HANDLING ############################################################################################################ #log_and_display "Issue handling" gitlabIssues=() while IFS= read -r line; do if [[ $line =~ ^# ]]; then id=$(echo "$line" | awk '{print substr($1, 2)}') title=$(echo "$line" | awk -F'about' '{print $1}' | awk '{$1=$2=""; print substr($0, 3)}') gitlabIssues+=("$id > $title") fi done < <(gum spin --spinner dot --show-output --title "Ask gitlab ..." -- glab issue list --output-format=details) ## if issues are available, ask if user wants to use an existing issue or create a new one createOption="Create new issue" existingOption="Use existing issue" cancelOption="Cancel" print_headline "Choose issue handling" if [ ''${#gitlabIssues[@]} -eq 0 ]; then log_and_display "There are no issues available." print_what_to_do choice=$(gum choose "$createOption" "$cancelOption") else log_and_display "There are ''${#gitlabIssues[@]} issues available." print_what_to_do choice=$(gum choose "$createOption" "$existingOption" "$cancelOption") fi if [[ "$choice" == "$cancelOption" ]]; then do_cancel fi ## array of issue ids work_on_issue_ids=() issue_text="" if [[ "$choice" == "$createOption" ]]; then print_headline "Create new issue" issue_text=$(gum input --placeholder "Enter issue title") echo -e "Enter issue description. ''${RED}End with Ctrl+D''${RESET}\n" issue_description=$(gum write --placeholder "Enter issue description. End with Ctrl+D") if [[ -z "$issue_text" ]]; then log_error_and_display "Issue title is empty. Exiting." printLogfileAndExit 1 fi log_and_display "You entered the issue title: $issue_text" log_and_display "You entered the issue description: $issue_description" echo -e "\n" gum confirm "Do you want to create this issue?" # gum confirm exits with status 0 if confirmed and status 1 if cancelled. if [ $? -eq 1 ]; then do_cancel fi issue_output=$(glab issue create -t"$issue_text" --no-editor --description "$issue_description") issue_id=$(echo "$issue_output" | grep -oP '(?<=/issues/)\d+') work_on_issue_ids+=("$issue_id") log_action "glab issue with id $issue_id created" else print_headline "Use existing issue" echo -e "Select issue with arrow keys and press tab or space to select. Press enter to confirm.\n" issue_ids=$(gum choose --no-limit "''${gitlabIssues[@]}") # assign issue_ids to work_on_issue_ids. iterate over lines and take integer from beginning of line while IFS= read -r line; do work_on_issue_ids+=($(echo "$line" | grep -oP '^\d+')) done <<<"$issue_ids" fi if [ ''${#work_on_issue_ids[@]} -eq 0 ]; then log_and_display "No issue selected. Exiting." printLogfileAndExit 0 fi # NEXT STEP COMMIT MESSAGE ############################################################################################################ # print work_on_issue_ids work_on_issue_ids_string="" for i in "''${work_on_issue_ids[@]}"; do work_on_issue_ids_string+="#$i " done log_and_display "You chose to work on the following issues: ''${work_on_issue_ids_string}" print_headline "Check for changes to commit" # ' ' = unmodified # M = modified # T = file type changed (regular file, symbolic link or submodule) # A = added # D = deleted # R = renamed # C = copied (if config option status.renames is set to "copies") # U = updated but unmerged # https://man.freebsd.org/cgi/man.cgi?query=git-status&sektion=1&manpath=freebsd-release-ports count_all_changes=$(echo "$git_status" | wc -l) count_staged_changes=$(echo "$git_status" | grep -c '^M') count_new_staged_files=$(echo "$git_status" | grep -c '^A') count_staged_changes=$((count_staged_changes + count_new_staged_files)) git_options_all="All $count_all_changes changes" git_options_staged="Only the $count_staged_changes staged changes" git_options_select_files="Select files" git_options_cancel="Cancel" git_options_array=() if [[ $count_all_changes -gt 0 ]]; then git_options_array+=("$git_options_all") fi if [[ $count_staged_changes -gt 0 ]]; then git_options_array+=("$git_options_staged") fi git_options_array+=( "$git_options_select_files" ) git_options_array+=( "$git_options_cancel" ) selection=$(gum choose "''${git_options_array[@]}") if [[ "$selection" == "$git_options_cancel" ]]; then do_cancel fi if [[ "$selection" == "$git_options_all" ]]; then git add -A echo "1" elif [[ "$selection" == "$git_options_select_files" ]]; then files=() while IFS= read -r line; do files+=("$line") done <<<"$git_status" selected_files=$(gum choose --no-limit "''${files[@]}") # no files selected if [[ -z "$selected_files" ]]; then log_and_display "No files selected. Exiting." printLogfileAndExit 0 fi # add selected files while IFS= read -r line; do ## git proclimne could have letter, ? or ! at the beginning of the line file=$(echo "$line" | awk '{print $2}') if [[ -z "$file" || ! -f "$file" ]]; then log_and_display "No file found in line: $line" continue fi git add "$file" done <<<"$selected_files" fi ## count staged changes again and print count_staged_changes=$(echo "$git_status" | grep -c '^M') count_new_staged_files=$(echo "$git_status" | grep -c '^A') count_staged_changes=$((count_staged_changes + count_new_staged_files)) log_and_display "You have $count_staged_changes staged changes to commit." # NEXT STEP COMMIT MESSAGE ############################################################################################################ print_headline "Enter commit message" commit_message=$(gum input --placeholder "Enter commit message" --value "$commit_type: $issue_text $work_on_issue_ids_string") if [[ -z "$commit_message" ]]; then log_error_and_display "Commit message is empty. Exiting." printLogfileAndExit 1 fi log_and_display "You entered the commit message: $commit_message" gum confirm "Do you want to commit with this message?" if [ $? -eq 1 ]; then do_cancel fi # NEXT STEP COMMIT #################################################################################################################### print_headline "Committing changes" if ! git commit -m "$commit_message" ; then log_error_and_display "Commit failed. Exiting." printLogfileAndExit 1 fi log_and_display "Commit successful." # NEXT STEP PUSH ###################################################################################################################### print_headline "Pushing changes" if ! git push ; then log_error_and_display "Push failed. Exiting." printLogfileAndExit 1 fi log_and_display "Push successful." # Close issue ###################################################################################################################### print_headline "Closing issues" for issue_id in "''${work_on_issue_ids[@]}"; do gum confirm "Do you want to close issue #$issue_id?" if [ $? -eq 1 ]; then continue fi if ! glab issue close "$issue_id" ; then log_error_and_display "Closing issue $issue_id failed. Exiting." else log_and_display "Closing issue $issue_id successful." fi done printLogfileAndExit 0 ''; }