Compare commits

...

10 commits

11 changed files with 216 additions and 34 deletions

2
.env
View file

@ -1,2 +0,0 @@
API_KEY=""
ENDPOINT="https://projets.cohabit.fr/redmine"

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Julien Oculi
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.

46
README.md Normal file
View file

@ -0,0 +1,46 @@
# Redmine CSV loader
Create Redmine users from CSV and add users to a group.
⚠️ This project is only a draft, it's working but not intended to be use widely ⚠️
Binaries are placed in `dist/` for x64.
- "*": linux
- "*.exe": windows
Script can be run directly with `deno task start` for other architectures or
compile with `deno task compile` using [deno](https://deno.com/).
### Requirements
The users CSV file must be in utf-8 using "," or ";" as separator. The required
headers must be exactly "firstname", "lastname" and "mail" in any order (all
other header will be skipped).
```csv
firstname;lastname;mail
jean;dupont;jean.dupont@example.com
alice;coger;alice.coger@example.com
bob;parraut;bob.parraut@example.com
```
## Usage
### Get help
```sh
./dist/redmine-csv-loader --help
```
### Create users
```sh
./dist/redmine-csv-loader ./path/to/csv -k "my_api_key"
```
### Add existing users to a group
```sh
./dist/redmine-csv-loader ./path/to/csv -k "my_api_key" -a -g "my_group"
```

View file

@ -1,4 +1,10 @@
{
"tasks": {
"start": "deno run --allow-read --allow-net ./main.ts",
"compile": "deno task compile:linux && deno task compile:windows",
"compile:linux": "deno compile --allow-read --allow-net --target=x86_64-unknown-linux-gnu -o=dist/redmine-csv-loader ./main.ts",
"compile:windows": "deno compile --allow-read --allow-net --target=x86_64-pc-windows-msvc -o=dist/redmine-csv-loader.exe ./main.ts"
},
"fmt": {
"singleQuote": true,
"semiColons": false,
@ -7,6 +13,7 @@
},
"imports": {
"std:csv": "https://deno.land/std@0.212.0/csv/mod.ts",
"bluemine": "https://deno.land/x/bluemine@0.1.4/mod.ts"
"bluemine": "https://deno.land/x/bluemine@0.1.4/mod.ts",
"cliffy": "https://deno.land/x/cliffy@v1.0.0-rc.3/command/mod.ts"
}
}

99
deno.lock Normal file
View file

@ -0,0 +1,99 @@
{
"version": "3",
"remote": {
"https://deno.land/std@0.196.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee",
"https://deno.land/std@0.196.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56",
"https://deno.land/std@0.196.0/console/_data.json": "cf2cc9d039a192b3adbfe64627167c7e6212704c888c25c769fc8f1709e1e1b8",
"https://deno.land/std@0.196.0/console/_rle.ts": "56668d5c44f964f1b4ff93f21c9896df42d6ee4394e814db52d6d13f5bb247c7",
"https://deno.land/std@0.196.0/console/unicode_width.ts": "10661c0f2eeab802d16b8b85ed8825bbc573991bbfb6affed32dc1ff994f54f9",
"https://deno.land/std@0.196.0/fmt/colors.ts": "a7eecffdf3d1d54db890723b303847b6e0a1ab4b528ba6958b8f2e754cf1b3bc",
"https://deno.land/std@0.212.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5",
"https://deno.land/std@0.212.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8",
"https://deno.land/std@0.212.0/csv/_io.ts": "568718b7eb4cf3ba140b0690a00ef5a8416ceae9a4116f386114c83717bd8a9e",
"https://deno.land/std@0.212.0/csv/csv_parse_stream.ts": "f06696ed1fbda5cb75426dff735b9cc91227eb0fa5367591b98bf88b99ae3048",
"https://deno.land/std@0.212.0/csv/csv_stringify_stream.ts": "8ea98e9e9c9e0517e34353ab30eb420d87f5e8ed0bc2094d1a8957ed17ed533c",
"https://deno.land/std@0.212.0/csv/mod.ts": "289ecf79b3609f63dfc1d39a7c791f8f14b73b29fb65bbb6b3e3e2bd0cddc75d",
"https://deno.land/std@0.212.0/csv/parse.ts": "472e51f936eca4f825154cf068789a378399d7ee76209a170db0e0a11c93b31f",
"https://deno.land/std@0.212.0/csv/stringify.ts": "f116dd2f0dfed19e363c528f2db9f270efd91801175332b0d29efd0794c5594f",
"https://deno.land/std@0.212.0/json/_common.ts": "6444c6ea166514eb379f778d9216c1d8eb159f97c753aeeb1fc44cd091e30544",
"https://deno.land/std@0.212.0/json/common.ts": "33f1a4f39a45e2f9f357823fd0b5cf88b63fb4784b8c9a28f8120f70a20b23e9",
"https://deno.land/std@0.212.0/json/concatenated_json_parse_stream.ts": "13a707615e03e5ea93ac81e5f00420e3b7764c4e3fa88043e63bbac87ebe62ce",
"https://deno.land/std@0.212.0/json/json_parse_stream.ts": "400d9a52a720e2f309bdfafea7a7d0fc87b9204a8cc8618d05382b3f1e781ffb",
"https://deno.land/std@0.212.0/json/json_stringify_stream.ts": "d5bcb9bd759c6e07c4fb2f0687641b76298bbf4b85dc6dbf4b8ea0483feb0f49",
"https://deno.land/std@0.212.0/json/mod.ts": "acd3e39a6c68c70ee7fa93991a8a8f02d799f7394db3cef09594e2dd8fd69814",
"https://deno.land/std@0.212.0/streams/_common.ts": "4f9f2958d853b9a456be033631dabb7519daa68ee4d02caf53e2ecbffaf5805f",
"https://deno.land/std@0.212.0/streams/text_delimiter_stream.ts": "ef0d7898cea4a9fff850173ed9f3d2cf9e42ba858d8175bd89fe851c8dfa6a6e",
"https://deno.land/std@0.212.0/streams/to_transform_stream.ts": "4c4836455ef89bab9ece55975ee3a819f07d3d8b0e43101ec7f4ed033c8a2b61",
"https://deno.land/x/bluemine@0.1.4/deps.ts": "4eb6e85ef950fc4fd1c3acab613b8b44fb507baf3e25a27d2369c5d8b53cca7e",
"https://deno.land/x/bluemine@0.1.4/mod.ts": "8e6e3a81a2f32f3a4a81cf9f2f859e8455e9c0d912b7c4042bd6fd0653b6ab00",
"https://deno.land/x/bluemine@0.1.4/src/redmine.ts": "8f0b63974a4a08b2512d9513feea3c8e8ddc952064ef78e7946b4cc497b76b04",
"https://deno.land/x/bluemine@0.1.4/src/routes/groups.ts": "5723d9ae2ca1b47362c36dc89446f2fb34c2783cb1845cb209f752319584e18b",
"https://deno.land/x/bluemine@0.1.4/src/routes/users/mod.ts": "90963a996bf490e764819e110da7fadb15cae9317c8a521c69e4bb3e814aef3b",
"https://deno.land/x/bluemine@0.1.4/src/routes/users/src/create.ts": "d6a675f3634774a8cf2a074fbc77966828a46cda230cbe503b4b0288eec335ce",
"https://deno.land/x/bluemine@0.1.4/src/routes/users/src/delete.ts": "e0ebf14796221be967c13304376b7bce5dd215b1e4aead9d7449a321e0b06108",
"https://deno.land/x/bluemine@0.1.4/src/routes/users/src/get.ts": "2721800a44c4634f67b87a692251a50d1c37dbd7df39f9b95317894d84208b14",
"https://deno.land/x/bluemine@0.1.4/src/routes/users/src/list.ts": "ce9d0eca292764f57ba3037f8b2d18ce18a5ef091c0de66cdacefc4c5b14a2c9",
"https://deno.land/x/bluemine@0.1.4/src/routes/users/src/update.ts": "f6758c381a2b95cd297060f1d437460583df659a929465b25cd04e99b2d505c3",
"https://deno.land/x/bluemine@0.1.4/types.ts": "90b4e4860059ae61a4047d76a06a31b1c4b50ebf13b22a7403a7651a2d7a6572",
"https://deno.land/x/bluemine@0.1.4/utils.ts": "2ca8e5f9adb02420f0b25e82c5a165e34f9eca4df160d7728e833678e6ee962f",
"https://deno.land/x/cliffy@v1.0.0-rc.3/_utils/distance.ts": "02af166952c7c358ac83beae397aa2fbca4ad630aecfcd38d92edb1ea429f004",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/_argument_types.ts": "ab269dacea2030f865a07c2a1e953ec437a64419a05bad1f1ddaab3f99752ead",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/_errors.ts": "12d513ff401020287a344e0830e1297ce1c80c077ecb91e0ac5db44d04a6019c",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/_spread.ts": "0cc6eb70a6df97b5d7d26008822d39f3e8a1232ee0a27f395aa19e68de738245",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/_type_utils.ts": "820004a59bc858e355b11f80e5b3ff1be2c87e66f31f53f253610170795602f0",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/_utils.ts": "3c88ff4f36eba298beb07de08068fdce5e5cb7b9d82c8a319f09596d8279be64",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/command.ts": "ae690745759524082776b7f271f66d5b93933170b1b132f888bd4ac12e9fdd7d",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/_bash_completions_generator.ts": "0c6cb1df4d378d22f001155781d97a9c3519fd10c48187a198fef2cc63b0f84a",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/_fish_completions_generator.ts": "8ba4455f7f76a756e05c3db4ce35332b2951af65a2891f2750b530e06880f495",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/_zsh_completions_generator.ts": "c74525feaf570fe8c14433c30d192622c25603f1fc64694ef69f2a218b41f230",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/bash.ts": "53fe78994eb2359110dc4fa79235bdd86800a38c1d6b1c4fe673c81756f3a0e2",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/complete.ts": "58df61caa5e6220ff2768636a69337923ad9d4b8c1932aeb27165081c4d07d8b",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/completions_command.ts": "506f97f1c6b0b1c3e9956e5069070028b818942310600d4157f64c9b644d3c49",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/fish.ts": "6f0b44b4067740b2931c9ec8863b6619b1d3410fea0c5a3988525a4c53059197",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/mod.ts": "8dda715ca25f3f66d5ec232b76d7c9a96dd4c64b5029feff91738cc0c9586fb1",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/zsh.ts": "f1263c3946975e090d4aadc8681db811d86b52a8ae680f246e03248025885c21",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/deprecated.ts": "bbe6670f1d645b773d04b725b8b8e7814c862c9f1afba460c4d599ffe9d4983c",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/deps.ts": "7473ebd5625bf901becd7ff80afdde3b8a50ae5d1bbfa2f43805cfacf4559d5a",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/help/_help_generator.ts": "532dd4a928baab8b45ce46bb6d20e2ebacfdf3da141ce9d12da796652b1de478",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/help/help_command.ts": "fbbf0c0827dd21d3cec7bcc68c00c20b55f53e2b621032891b9d23ac4191231c",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/help/mod.ts": "8369b292761dcc9ddaf41f2d34bfb06fb6800b69efe80da4fc9752c3b890275b",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/mod.ts": "4b708df1b97152522bee0e3828f06abbbc1d2250168910e5cf454950d7b7404b",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/type.ts": "f588f5d9635b79100044e62aced4b00e510e75b83801f9b089c40c2d98674de2",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/types.ts": "bc9ff7459b9cc1079eeb95ff101690a51b4b4afa4af5623340076ee361d08dbb",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/action_list.ts": "33c98d449617c7a563a535c9ceb3741bde9f6363353fd492f90a74570c611c27",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/boolean.ts": "3879ec16092b4b5b1a0acb8675f8c9250c0b8a972e1e4c7adfba8335bd2263ed",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/child_command.ts": "f1fca390c7fbfa7a713ca15ef55c2c7656bcbb394d50e8ef54085bdf6dc22559",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/command.ts": "325d0382e383b725fd8d0ef34ebaeae082c5b76a1f6f2e843fee5dbb1a4fe3ac",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/enum.ts": "8a7cd2898e03089234083bb78c8b1d9b7172254c53c32d4710321638165a48ec",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/file.ts": "8618f16ac9015c8589cbd946b3de1988cc4899b90ea251f3325c93c46745140e",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/integer.ts": "29864725fd48738579d18123d7ee78fed37515e6dc62146c7544c98a82f1778d",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/number.ts": "aeba96e6f470309317a16b308c82e0e4138a830ec79c9877e4622c682012bc1f",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/string.ts": "e4dadb08a11795474871c7967beab954593813bb53d9f69ea5f9b734e43dc0e0",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/_check_version.ts": "6cfa7dc26bc0dc46381500e8d4b130fb224f4c5456152dada15bd3793edca89b",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/mod.ts": "4eff69c489467be17dea27fb95a795396111ee385d170ac0cbcc82f0ea38156c",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/provider.ts": "c23253334097dc4b8a147ccdeb3aa44f5a95aa953a6386cb5396f830d95d77a5",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/provider/deno_land.ts": "24f8d82e38c51e09be989f30f8ad21f9dd41ac1bb1973b443a13883e8ba06d6d",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/provider/github.ts": "99e1b133dd446c6aa79f69e69c46eb8bc1c968dd331c2a7d4064514a317c7b59",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/provider/nest_land.ts": "0e07936cea04fa41ac9297f32d87f39152ea873970c54cb5b4934b12fee1885e",
"https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/upgrade_command.ts": "3640a287d914190241ea1e636774b1b4b0e1828fa75119971dd5304784061e05",
"https://deno.land/x/cliffy@v1.0.0-rc.3/flags/_errors.ts": "f1fbb6bfa009e7950508c9d491cfb4a5551027d9f453389606adb3f2327d048f",
"https://deno.land/x/cliffy@v1.0.0-rc.3/flags/_utils.ts": "340d3ecab43cde9489187e1f176504d2c58485df6652d1cdd907c0e9c3ce4cc2",
"https://deno.land/x/cliffy@v1.0.0-rc.3/flags/_validate_flags.ts": "e60b9038c0136ab7e6bd1baf0e993a07bf23f18afbfb6e12c59adf665a622957",
"https://deno.land/x/cliffy@v1.0.0-rc.3/flags/deprecated.ts": "a72a35de3cc7314e5ebea605ca23d08385b218ef171c32a3f135fb4318b08126",
"https://deno.land/x/cliffy@v1.0.0-rc.3/flags/flags.ts": "3e62c4a9756b5705aada29e7e94847001356b3a83cd18ad56f4207387a71cf51",
"https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types.ts": "9e2f75edff2217d972fc711a21676a59dfd88378da2f1ace440ea84c07db1dcc",
"https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types/boolean.ts": "4c026dd66ec9c5436860dc6d0241427bdb8d8e07337ad71b33c08193428a2236",
"https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types/integer.ts": "b60d4d590f309ddddf066782d43e4dc3799f0e7d08e5ede7dc62a5ee94b9a6d9",
"https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types/number.ts": "610936e2d29de7c8c304b65489a75ebae17b005c6122c24e791fbed12444d51e",
"https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types/string.ts": "e89b6a5ce322f65a894edecdc48b44956ec246a1d881f03e97bbda90dd8638c5",
"https://deno.land/x/cliffy@v1.0.0-rc.3/table/_layout.ts": "e4a518da28333de95ad791208b9930025987c8b93d5f8b7f30b377b3e26b24e1",
"https://deno.land/x/cliffy@v1.0.0-rc.3/table/_utils.ts": "fd48d1a524a42e72aa3ad2eec858a92f5a00728d306c7e8436fba6c34314fee6",
"https://deno.land/x/cliffy@v1.0.0-rc.3/table/border.ts": "5c6e9ef5078c6930169aacb668b274bdbb498461c724a7693ac9270fe9d3f5d5",
"https://deno.land/x/cliffy@v1.0.0-rc.3/table/cell.ts": "1ffabd43b6b7fddfac9625cb0d015532e144702a9bfed03b358b79375115d06b",
"https://deno.land/x/cliffy@v1.0.0-rc.3/table/column.ts": "cf14009f2cb14bad156f879946186c1893acdc6a2fee6845db152edddb6a2714",
"https://deno.land/x/cliffy@v1.0.0-rc.3/table/consume_words.ts": "456e75755fdf6966abdefb8b783df2855e2a8bad6ddbdf21bd748547c5fc1d4b",
"https://deno.land/x/cliffy@v1.0.0-rc.3/table/deps.ts": "1226c4d39d53edc81d7c3e661fb8a79f2e704937c276c60355cd4947a0fe9153",
"https://deno.land/x/cliffy@v1.0.0-rc.3/table/row.ts": "79eb1468aafdd951e5963898cdafe0752d4ab4c519d5f847f3d8ecb8fe857d4f",
"https://deno.land/x/cliffy@v1.0.0-rc.3/table/table.ts": "298671e72e61f1ab18b42ae36643181993f79e29b39dc411fdc6ffd53aa04684"
}
}

BIN
dist/redmine-csv-loader vendored Normal file

Binary file not shown.

BIN
dist/redmine-csv-loader.exe vendored Normal file

Binary file not shown.

40
main.ts Normal file
View file

@ -0,0 +1,40 @@
import { Redmine } from 'bluemine'
import * as CSV from 'std:csv'
import { CsvEntry } from './type.ts'
import { createUsers } from './src/create_users.ts'
import { appendToGroup } from './src/append_to_group.ts'
import { Command } from 'cliffy'
await new Command()
.name('redmine-csv-loader')
.description('Create Redmine users from CSV and add users to a group.')
.version('0.1.0')
.option('-g, --group <group:string>', 'Name of the group to add users in.')
.option(
'-a, --only-add [only-add:boolean]',
"Don't create users, only add them to a group",
)
.option('-d, --endpoint <endpoint:string>', 'Redmine server address.', {
default: 'https://projets.cohabit.fr/redmine',
})
.option(
'-k, --api-key <api-key:string>',
'Your Redmine API Key (see: https://www.redmine.org/boards/2/topics/53956/).',
{ required: true },
)
.arguments('<csv:file>')
.action(async ({ group, endpoint, apiKey, onlyAdd }, domain) => {
const redmine = new Redmine({ endpoint, apiKey })
const file = await Deno.readTextFile(domain)
const csv = CSV.parse(file.replaceAll(';', ','), {
skipFirstRow: true,
}) as CsvEntry[]
if (!onlyAdd) createUsers(redmine, csv)
if (group) {
appendToGroup(redmine, csv, prompt('Enter a group name ?: ') ?? '')
}
})
.parse()

29
mod.ts
View file

@ -1,29 +0,0 @@
import { Redmine } from 'bluemine'
import * as CSV from 'std:csv'
import { CsvEntry } from './type.ts'
if (import.meta.main) {
const endpoint = Deno.env.get('ENDPOINT')
const apiKey = Deno.env.get('API_KEY')
if (apiKey === undefined) {
throw new Error(
'Redmine REST API key is missing, please define API_KEY',
)
}
if (endpoint === undefined) {
throw new Error(
'Redmine REST endpoint is missing, please define ENDPOINT',
)
}
const redmine = new Redmine({ endpoint, apiKey })
const file = await Deno.readTextFile(
prompt('Full path of the CSV file ?:') ?? '',
)
const csv = CSV.parse(file.replaceAll(';', ','), {
skipFirstRow: true,
}) as CsvEntry[]
}

View file

@ -2,7 +2,7 @@ import { Redmine } from 'bluemine'
import { CsvEntry } from '../type.ts'
import { log, toLogin } from '../utils.ts'
async function addUsersToGroup(
export async function appendToGroup(
redmine: Redmine,
csv: CsvEntry[],
groupName: string,

View file

@ -2,7 +2,7 @@ import { Redmine } from 'bluemine'
import { CsvEntry } from '../type.ts'
import { capitalize, log, sanitize, toLogin } from '../utils.ts'
async function createUsers(
export async function createUsers(
redmine: Redmine,
csv: CsvEntry[],
) {