wonderbird/malimo

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# malimo - Markdown Linked Images Mover

[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/wonderbird/malimo)
[![Build Status Badge](https://github.com/wonderbird/malimo/actions/workflows/build_wo_release.yml/badge.svg?branch=main)](https://github.com/wonderbird/malimo/actions?query=workflow%3A%22.NET%20build%20w/o%20release%22)
[![Test Coverage](https://img.shields.io/codeclimate/coverage-letter/wonderbird/malimo)](https://codeclimate.com/github/wonderbird/malimo/trends/test_coverage_total)
[![Code Maintainability](https://img.shields.io/codeclimate/maintainability-percentage/wonderbird/malimo)](https://codeclimate.com/github/wonderbird/malimo)
[![Issues in Code](https://img.shields.io/codeclimate/issues/wonderbird/malimo)](https://codeclimate.com/github/wonderbird/malimo/issues)
[![Technical Debt](https://img.shields.io/codeclimate/tech-debt/wonderbird/malimo)](https://codeclimate.com/github/wonderbird/malimo)

Move all images used by a markdown file into a folder.

## Motivation

During online conferences and workshops I take notes in markdown format using [Obsidian.md](https://obsidian.md). As a result I have a folder with many screenshots from different talks in the evening.

The Markdown Linked Images Mover "`malimo`" moves all images addressed by a markdown file into a separate folder.

This way I can separate screenshots by topic at the end of a conference or workshop day.

## Development and Support Status

I am developing during my spare time and use this project for learning purposes. Please assume that I will need some days to answer your questions. At some point I might lose interest in the project. Please keep this in mind when using this project in a production environment.

## Acknowledgements

The [application icon](assets/application-icon) is the `folder-document.png` from the "Tango harm-on-icons" icon set, which is published in the [Open Icon Library](https://sourceforge.net/projects/openiconlibrary/) using the [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/) license. Thanks to the author(s) for their work ❤️.


Many thanks to [JetBrains](https://www.jetbrains.com/?from=malimo) who provide
an [Open Source License](https://www.jetbrains.com/community/opensource/) for this project ❤️.

## Installation

### macOS

For macOS I am maintaining a [Homebrew](https://brew.sh) installer:

```shell
brew install wonderbird/tools/malimo
```

This creates a symlink named `malimo` in your `$(brew --prefix)/bin` directory.

The corresponding Homebrew cask is at [wonderbird / homebrew-tools / Casks / malimo.rb](https://github.com/wonderbird/homebrew-tools/blob/main/Casks/malimo.rb).

### Windows

#### Use the Chocolatey Package Manager

For Windows, the [release process](./.github/workflows/dotnet.yml) publishes a wrapper package to the
[Chocolatey Community Repository](https://community.chocolatey.org/packages). The package will download and install the release ZIP file from the [malimo GitHub release page](https://github.com/wonderbird/malimo/releases).

You can install malimo by:

```powershell
choco install malimo --pre
```

At the moment I consider the software a prerelease. This is why the `--pre` argument is required.

#### Manual Installation

If you do not manage your Windows software using [Chocolatey](https://community.chocolatey.org/), then

- download `malimo.win-x64.zip` from the latest [GitHub release](https://github.com/wonderbird/malimo/releases),
- extract the files into a folder
- add the folder to your PATH environment variable.

### Verification

After successful installation you can run the program and get help by entering

```shell
malimo --help
```

and you can check the version

```shell
malimo --version
```

The displayed version number contains 4 numbers separated by a ".", e.g. `0.1.7.178`. The first three numbers reflect the [semantic version](https://semver.org/spec/v2.0.0.html) of the release, here `0.1.7`. The last number is the [GitHub workflow run number](https://github.com/wonderbird/malimo/actions?query=workflow%3A%22.NET%22), during which the package was created, in the example case it was [run #178](https://github.com/wonderbird/malimo/actions/runs/4669300742).

## Usage Examples

The most basic usage is

```shell
malimo --file ./my-markdown-file.md --target-dir ./target
```

`malimo` will list the images linked in `./my-markdown-file.md`. It will ensure that every image exists in the same  directory `./`. Then it will move all linked images to the directory `./target`.

If you want to double check what would be moved before actually moving the files, then add the `--dry-run` option. This way, no file will be moved.

```shell
malimo --dry-run --file ./my-markdown-file.md --target-dir ./will-be-ignored
```

To get help, specify the `--help` option:

```shell
malimo --help
```

You can find elaborate usage examples in the `FeatureDocumentation` HTML file attached to each [release](https://github.com/wonderbird/malimo/releases) starting from 0.1.8-alpha.

## Development

### Architecture Overview

[docs/architecture.adoc](docs/architecture.adoc) gives an overview of the architecture. Section **8 Concepts** explains maintenance tasks.

### Quick-Start

Click
the [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/wonderbird/malimo)
badge (also above) to launch a web IDE.

If that does not work for you or if you'd like to have the project on your local machine, then continue reading.

### Prerequisites

To compile, test and run this project the latest [.NET SDK](https://dotnet.microsoft.com/download) is required on
your machine. For calculating code metrics I recommend [metrix++](https://github.com/metrixplusplus/metrixplusplus).
This requires python.

If you are interested in test coverage, then you'll need the following tools installed:

```shell
dotnet tool install --global coverlet.console --configfile NuGet-OfficialOnly.config
dotnet tool install --global dotnet-reportgenerator-globaltool --configfile NuGet-OfficialOnly.config
```

## Build, Test, Run

Run the following commands from the folder containing the `.sln` file in order to build and test.

### Build and Test the Solution

```sh
# Build the project
dotnet build

# Run the tests once
dotnet test
```

```shell
# Continuously watch the tests while changing code
dotnet watch -p ./malimo.Tests test
```

```shell
# Produce a coverage report and open it in the default browser
rm -r malimo.Tests/TestResults && \
  dotnet test --no-restore --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput='./TestResults/coverage.cobertura.xml' && \
  reportgenerator "-reports:malimo.Tests/TestResults/*.xml" "-targetdir:report" "-reporttypes:Html;lcov" "-title:DotnetStarter"
open report/index.html
```

### Run the Application

```shell
# Get help
dotnet run --project malimo/malimo.csproj -- --help
```

```shell
# Prepare test data to run the application
cp -Rv malimo.Tests/data/seed malimo.Tests/data/source
mkdir malimo.Tests/data/target
```

```shell
# Run the application
dotnet run --project malimo/malimo.csproj -- --dry-run --file malimo.Tests/data/source/Testfile.md --target-dir malimo.Tests/data/target
```

```shell
# Inspect the result
ls -la malimo.Tests/data/source
ls -la malimo.Tests/data/target
```

```shell
# Cleanup test data
rm -r malimo.Tests/data/source malimo.Tests/data/target
```

### Before Creating a Pull Request ...

#### Fix Static Code Analysis Warnings

... fix static code analysis warnings reported by [SonarLint](https://www.sonarsource.com/products/sonarlint/)
and by [CodeClimate](https://codeclimate.com/github/wonderbird/malimo/issues).

#### Apply Code Formatting Rules

```shell
# Install https://csharpier.io globally, once
dotnet tool install -g csharpier

# Format code
dotnet csharpier .
```

#### Check Code Metrics

... check code metrics using [metrix++](https://github.com/metrixplusplus/metrixplusplus)

- Configure the location of the cloned metrix++ scripts
  ```shell
  export METRIXPP=/path/to/metrixplusplus
  ```

- Collect metrics
  ```shell
  python "$METRIXPP/metrix++.py" collect --std.code.complexity.cyclomatic --std.code.lines.code --std.code.todo.comments --std.code.maintindex.simple -- .
  ```

- Get an overview
  ```shell
  python "$METRIXPP/metrix++.py" view --db-file=./metrixpp.db
  ```

- Apply thresholds
  ```shell
  python "$METRIXPP/metrix++.py" limit --db-file=./metrixpp.db --max-limit=std.code.complexity:cyclomatic:5 --max-limit=std.code.lines:code:25:function --max-limit=std.code.todo:comments:0 --max-limit=std.code.mi:simple:1
  ```

At the time of writing, I want to stay below the following thresholds:

```text
--max-limit=std.code.complexity:cyclomatic:5
--max-limit=std.code.lines:code:25:function
--max-limit=std.code.todo:comments:0
--max-limit=std.code.mi:simple:1
```

Finally, remove all code duplication. The next section describes how to detect code duplication.

#### Remove Code Duplication Where Appropriate

To detect duplicates I use the [CPD Copy Paste Detector](https://docs.pmd-code.org/latest/pmd_userdocs_cpd.html)
tool from the [PMD Source Code Analyzer Project](https://docs.pmd-code.org/latest/index.html).

If you have installed PMD by download & unzip, replace `pmd` by `./run.sh`.
The [homebrew pmd formula](https://formulae.brew.sh/formula/pmd) makes the `pmd` command globally available.

```sh
# Remove temporary and generated files
# 1. dry run
git clean -ndx
```

```shell
# 2. Remove the files shown by the dry run
git clean -fdx
```

```shell
# Identify duplicated code in files to push to GitHub
pmd cpd --minimum-tokens 50 --language cs --dir .
```