Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:

- uses: actions/setup-node@v2
with:
node-version: 16
node-version: 20
cache: npm
registry-url: https://registry.npmjs.org/

Expand Down Expand Up @@ -54,3 +54,42 @@ jobs:
body: Please refer to [CHANGELOG.md](https://github.com/studiometa/cli-test-redirection/blob/${{ github.ref_name }}/CHANGELOG.md) for details.
draft: false
prerelease: ${{ env.is_prerelease }}

push_to_registries:
name: Push Docker image to multiple registries
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Check out the repo
uses: actions/checkout@v4

- name: Log in to Docker Hub
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: |
my-docker-hub-namespace/my-docker-hub-repository
ghcr.io/${{ github.repository }}

- name: Build and push Docker images
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/dist/
/node_modules/
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

### Added

- Add a Docker image for advanced usage with host mocking ([#3](https://github.com/studiometa/cli-test-redirection/pull/3))
- Add `--replace-(from|to)-host` flags ([d738fc1](https://github.com/studiometa/cli-test-redirection/commit/d738fc1))

### Changed

- Improve logging ([3bbbc1e](https://github.com/studiometa/cli-test-redirection/commit/3bbbc1e))
- ⚠️ Bump Node version to >=20 ([#3](https://github.com/studiometa/cli-test-redirection/pull/3))

### Deleted

- ⚠️ Remove the `--password` parameter in favor of a single `--user user:pass` parameter ([#3](https://github.com/studiometa/cli-test-redirection/pull/3))

### Fixed

Expand Down
45 changes: 45 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Install Node dependencies
FROM node:20-alpine AS node_install

WORKDIR /app
COPY package.json .
COPY package-lock.json .
RUN npm install

# Build cli tool
FROM node:20-alpine AS node_builder

WORKDIR /app
COPY . .
COPY --from=node_install /app/node_modules /app/node_modules
RUN npm run build

# Build mkcert
FROM golang:alpine AS mkcert_builder

RUN apk add --update git
RUN cd \
&& git clone https://github.com/FiloSottile/mkcert \
&& cd mkcert \
&& go build -ldflags "-X main.Version=$(git describe --tags)" -o /usr/local/bin/mkcert

# Final context
FROM httpd:alpine
RUN mkdir -p /app
WORKDIR /app
RUN echo "" > /app/index.html

RUN apk add curl openssl

COPY --from=node_builder /app/dist/test-redirection /usr/local/bin/test-redirection

COPY ./docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
RUN chmod +x /usr/local/bin/docker-entrypoint

COPY --from=mkcert_builder /usr/local/bin/mkcert /usr/local/bin/mkcert
RUN mkcert -install

ENV DOMAINS='test.dev'
ENV DEBUG='false'

ENTRYPOINT ["/usr/local/bin/docker-entrypoint"]
72 changes: 37 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,43 @@

## Usage

You can directly use the CLI with `npx`:
You can directly use the CLI with `docker`:

```sh
npx @studiometa/cli-test-redirection path/to/config.json
docker run -it --rm -v $PWD:/app studiometa/test-redirection redirects.csv
```

Your `config.json` file sould contain an array of objects with both `from` and `to` properties describing the origin and the target to test. For example:

```json
[
{
"from": "http://fqdn.com",
"to": "https://www.fqdn.com",
"ignoreQueryParameters": false,
"method": "GET"
}
]
Or with `npx`:

```sh
npx @studiometa/cli-test-redirection redirects.csv
```

Or you can install it globally:

```sh
npm install -g @studiometa/cli-test-redirection
test-redirection redirects.csv
```

The `ignoreQueryParameters` property allow to ignore query parameters in the final URL before comparing it with the `to` URL as some redirection directives will keep them.
The `redirects.csv` file should have 2 columns: the first one is the original URL, the second is the redirected URL.

When working with simple "from → to" redirections, you can use a CSV file. The first column should be the "from" URL, the second the "to" URL. You can then use the `--parser csv` paramete:
### Mock hosts to test redirects before deploying

The Docker image can configure an Apache environment to test request against a mocked environment.

```sh
npx @studiometa/cli-test-redirection path/to/redirects.csv --parser csv
# Create your .htaccess file with redirections to test
vim .htaccess

# Create a CSV fiels containing from,to URLS
vim redirects.csv

# With a custom delimiter
npx @studiometa/cli-test-redirection path/to/redirects.csv --parser csv --csv-delimiter ';'
# Configure the temporary hosts referenced in your redirects, they will be configured in the Docker container
export DOMAINS='fqdn.com,www.fqdn.com'

# Run the Docker image by linking the current directy to /app
docker run -it --rm -v $PWD:/app -e DOMAINS studiometa/cli-test-redirection redirects.csv
```

## Parameters
Expand All @@ -42,8 +51,8 @@ Limit the number of tests running concurrently.

```bash
# Limit to 1 test
test-redirection --concurrency 1 path/to/config.json
test-redirection -c 1 path/to/config.json
test-redirection --concurrency 1 path/to/redirects.csv
test-redirection -c 1 path/to/redirects.csv
```

### `--delay [number]`
Expand All @@ -52,12 +61,12 @@ Add a delay in milliseconds between batch of tests.

```bash
# Wait for 1s between each batch of tests
test-redirection --delay 1000 path/to/config.json
test-redirection -d 1000 path/to/config.json
test-redirection --delay 1000 path/to/redirects.csv
test-redirection -d 1000 path/to/redirects.csv

# Wait for 1s between each tests
test-redirection --delay 1000 --concurrency 1 path/to/config.json
test-redirection -d 1000 -c 1 path/to/config.json
test-redirection --delay 1000 --concurrency 1 path/to/redirects.csv
test-redirection -d 1000 -c 1 path/to/redirects.csv
```

### `--ignore-query-parameters`
Expand All @@ -67,9 +76,10 @@ Ignore query parameters when comparing the final URL with the target URL defined
```bash
test-redirection --ignore-query-parameters path/to/config.json
```

### `--parser [json|csv]`

Define how the input file should be parsed.
Define how the input file should be parsed. The parser is inferred by the given file extension.

```bash
test-redirection path/to/file.csv --parser csv
Expand Down Expand Up @@ -101,16 +111,8 @@ test-redirection path/to/config.json -v --only-errors

### `--user`

Define basic auth user. Must be used with the `--password` parameter.

```bash
test-redirection path/to/config.json --user user --password pass
```

### `--password`

Define basic auth password. Must be used with the `--user` parameter.
Define basic auth user. This parameter is directly passed to the underlying `curl` command.

```bash
test-redirection path/to/config.json --password pass --user user
test-redirection path/to/config.json --user user:password
```
24 changes: 10 additions & 14 deletions bin/test-redirection.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
#!/usr/bin/env node
import { existsSync, readFileSync } from 'fs';
import { resolve } from 'path';
import { existsSync, readFileSync } from 'node:fs';
import { createRequire } from 'node:module';
import { resolve } from 'node:path';
import chalk from 'chalk';
import { cac } from 'cac';
import run from '../src/index.js';
import { importJson, importCsv } from '../src/utils.js';

const pkg = importJson('../package.json', import.meta.url);
const require = createRequire(import.meta.url);
const pkg = require('../package.json', import.meta.url);
const PKG_NAME = pkg.name;
const PKG_VERSION = pkg.version;
const CLI_NAME = 'test-redirection';

const cli = cac(PKG_NAME);

/**
* @todo add options:
* - batch length
* - wait between requests
*/
cli
.command('<configPath>', 'Test redirections.')
.option(
Expand All @@ -29,15 +26,14 @@ cli
default: 100,
})
.option('--ignore-query-parameters', 'Ignore query parameters in the final URL.')
.option('-p, --parser [parser]', 'Define which parser should be used: json or csv.', { default: 'json' })
.option('-p, --parser [parser]', 'Define which parser should be used: json or csv.', { default: null })
.option('--csv-delimiter [delimiter]', 'Define the delimiter of the input CSV file, can be a string or a RegExp.', { default: ',' })
.option('--replace-host <host>', 'Replace host for both the `from` and `to` parameters.')
.option('--replace-from-host <host>', 'Replace host for the `from` parameter.')
.option('--replace-to-host <host>', 'Replace host for the `to` parameter.')
.option('-v, --verbose', 'Log all redirections.')
.option('--only-errors', 'Log only errors.')
.option('--user <user>', 'Basic auth user.')
.option('--password <password>', 'Basic auth password.')
.option('-u, --user <user:password>', 'Basic auth user and password.')
.action((configPath, options) => {
const resolvedConfigPath = resolve(process.cwd(), configPath);

Expand All @@ -50,12 +46,12 @@ cli

let config;

if (options.parser === 'csv') {
config = importCsv(resolvedConfigPath, import.meta.url, {
if (options.parser === 'csv' || options.parser === null && resolvedConfigPath.endsWith('.csv')) {
config = importCsv(resolvedConfigPath, {
delimiter: new RegExp(options.csvDelimiter)
});
} else {
config = importJson(resolvedConfigPath, import.meta.url);
config = importJson(resolvedConfigPath);
}

run(config, options);
Expand Down
93 changes: 93 additions & 0 deletions docker/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/bin/sh

if [[ $DEBUG == "true" ]]
then
echo "Configuring vhost..."
fi

# Enable modules: rewrite, ssl
# sed -i "/LoadModule rewrite_module/s/^#//g" /usr/local/apache2/conf/httpd.conf
sed -i \
-e 's/^#\(LoadModule .*mod_rewrite.so\)/\1/' \
-e 's/^#\(Include .*httpd-ssl.conf\)/\1/' \
-e 's/^#\(LoadModule .*mod_ssl.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_socache_shmcb.so\)/\1/' \
/usr/local/apache2/conf/httpd.conf

# Include additional config
echo "IncludeOptional conf.d/*.conf" >> /usr/local/apache2/conf/httpd.conf

# Create additional config folder
mkdir -p /usr/local/apache2/conf.d

# Add domains to /etc/hosts
echo "127.0.0.1 ${DOMAINS}" >> /etc/hosts

# Create log folder
mkdir -p /var/log/apache2

CONFIG="<VirtualHost *:80>
ServerName localhost
ServerAlias ${DOMAINS}

DocumentRoot /app

<Directory /app>
Options -Indexes +ExecCGI
AllowOverride All
Require all granted
</Directory>

ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
</VirtualHost>

<VirtualHost *:443>
ServerName localhost
ServerAlias ${DOMAINS}

DocumentRoot /app

SSLEngine On
SSLCertificateFile /usr/local/apache2/conf/server.crt
SSLCertificateKeyFile /usr/local/apache2/conf/server.key

<Directory /app>
Options -Indexes +ExecCGI
AllowOverride All
Require all granted
</Directory>

ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
</VirtualHost>"

echo "$CONFIG" > /usr/local/apache2/conf.d/vhost.conf

# Create SSL certificates
mkcert -cert-file /usr/local/apache2/conf/server.crt -key-file /usr/local/apache2/conf/server.key localhost $DOMAINS &> /dev/null

if [[ $DEBUG == "true" ]]
then
echo "Starting Apache..."
fi
httpd -k start -E /tmp/null

if [[ $DEBUG == "true" ]]
then
echo "Testing domains..."
for DOMAIN in $(echo $DOMAINS)
do
echo "Testing ping for $DOMAIN..."
ping -c 1 $DOMAIN
echo ""
echo "Testing http://$DOMAIN..."
curl -sIL http://$DOMAIN
echo ""
echo "Testing https://$DOMAIN..."
curl -sIL https://$DOMAIN
echo ""
done
fi

test-redirection "$@"
Loading