diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 24b86d5..aeacc75 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,5 +13,7 @@ jobs: - uses: actions/checkout@v3 with: submodules: true - - name: Run BATS tests + - name: Run rsync-antora-reference BATS tests run: ./rsync-antora-reference/test/bats/bin/bats ./rsync-antora-reference/test/ + - name: Run rsync-schema BATS tests + run: ./rsync-schema/test/bats/bin/bats ./rsync-schema/test/ diff --git a/rsync-schema/action.yml b/rsync-schema/action.yml new file mode 100644 index 0000000..3636e6f --- /dev/null +++ b/rsync-schema/action.yml @@ -0,0 +1,42 @@ +name: rsync Antora Docs +description: A GitHub action that syncs Antora reference documentation using rsync with support for syncing a single version. It deploys to the docs server using the github repository in the path. +branding: + icon: 'copy' + color: 'green' +inputs: + docs-username: + description: The username to connect to the docs server + required: true + docs-host: + description: The host of the docs server + required: true + docs-ssh-key: + description: The ssh key used to connect to the docs-host + required: true + docs-ssh-host-key: + description: The docs ssh host key used to connect to docs-host + required: true + dry-run: + description: Set to false if should perform the sync, else a dry run is performed + default: false + required: false + site-path: + description: The path to the schema that should be synced + default: build/schema + required: false + version: + description: The schema version being published + required: true + +runs: + using: 'composite' + steps: + - id: publish-docs + shell: bash + run: | + PATH=$PATH:${{ github.action_path }}/src + flag_options='' + if [ -z "${{ inputs.dry-run }}" ]; then + flag_options="${flag_options} --dry-run" + fi + ${{ github.action_path }}/src/action.sh --docs-username "${{ inputs.docs-username }}" --docs-host "${{ inputs.docs-host }}" --docs-ssh-key "${{ inputs.docs-ssh-key }}" --docs-ssh-host-key "${{ inputs.docs-ssh-host-key }}" --site-path "${{ inputs.site-path }}" --version "${{ inputs.version }}" --github-repository "${{ github.repository }}" $flag_options diff --git a/rsync-schema/src/action.sh b/rsync-schema/src/action.sh new file mode 100755 index 0000000..242b217 --- /dev/null +++ b/rsync-schema/src/action.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +__action_usage() { + echo "usage: action.sh [OPTION]... + + --docs-username=USERNAME the username used to connect to ssh + --docs-host=HOST the host to connect to ssh + --docs-ssh-key=KEY the private key used to connect to ssh + --docs-ssh-host-key=HOST_KEY the host key used to connect to ssh + --dry-run signals that rsync should be in dry run mode + --site-path=PATH the local directory path to sync to the server. Default build/schema + --version=VERSION the release version for the schema + --github-repository=GH_REPO the github repository (e.g. spring-projects/spring-security) +" +} + +__action_usage_error() { + echo "Error: $1" >&2 + __action_usage + exit 1 +} + +__action() { + local docs_username docs_host docs_ssh_key docs_ssh_host_key site_path version github_repository valid_args + local rsync_flag_options='' + valid_args=$(getopt --options '' --long docs-username:,docs-host:,docs-ssh-key:,docs-ssh-host-key:,dry-run,site-path:,version:,github-repository: -- "$@") + if [[ $? -ne 0 ]]; then + __action_usage + exit 1; + fi + + eval set -- "$valid_args" + + while [ : ]; do + case "$1" in + --docs-username) + docs_username="$2" + shift 2 + ;; + --docs-host) + docs_host="$2" + shift 2 + ;; + --docs-ssh-key) + docs_ssh_key="$2" + shift 2 + ;; + --docs-ssh-host-key) + docs_ssh_host_key="$2" + shift 2 + ;; + --dry-run) + rsync_flag_options="${rsync_flag_options} --dry-run" + shift + ;; + --site-path) + site_path="$2" + shift 2 + ;; + --version) + version="$2" + shift 2 + ;; + --github-repository) + github_repository="$2" + shift 2 + ;; + --) shift; + break + ;; + *) + __action_usage_error "Invalid argument $1 $2" + ;; + esac + done + + if [ -z "$docs_username" ]; then + __action_usage_error "Missing option '--docs-username'" + fi + if [ -z "$docs_host" ]; then + __action_usage_error "Missing option '--docs-host'" + fi + if [ -z "$docs_ssh_key" ]; then + __action_usage_error "Missing option '--docs-ssh-key'" + fi + if [ -z "$docs_ssh_host_key" ]; then + __action_usage_error "Missing option '--docs-ssh-host-key'" + fi + if [ -z "$site_path" ]; then + site_path="build/schema" + fi + if [ -z "$version" ]; then + __action_usage_error "Missing option '--version'" + fi + if [ -z "$github_repository" ]; then + __action_usage_error "Missing option '--github-repository'" + fi + + + ## Extract repository_name from the owner/repository_name + local github_repository_name="$(echo ${github_repository} | cut -d '/' -f 2)" + local ssh_private_key_path="$HOME/.ssh/${github_repository:-publish-docs}" + local ssh_host="${docs_username}@${docs_host}" + + ( + set -e + set -f + + local ssh_host_path="/var/www/domains/spring.io/docs/htdocs/autorepo/schema/$github_repository_name/$version/" + local pwd="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" + setup_ssh.sh --ssh-private-key-path "$ssh_private_key_path" --ssh-private-key "$docs_ssh_key" --ssh-known-host "$docs_ssh_host_key" + rsync_schema.sh --ssh-host "$ssh_host" --ssh-host-path "$ssh_host_path" --local-path "$site_path" --ssh-private-key-path "$ssh_private_key_path" $rsync_flag_options + ) + exit_code=$? + + cleanup_ssh.sh --ssh-private-key-path "$ssh_private_key_path" + + exit $exit_code +} + + +__action "$@" \ No newline at end of file diff --git a/rsync-schema/src/check_github_repository_owner.sh b/rsync-schema/src/check_github_repository_owner.sh new file mode 100755 index 0000000..b19da48 --- /dev/null +++ b/rsync-schema/src/check_github_repository_owner.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +__check_github_repository_owner_usage() { + echo "usage: check_github_repository_owner.sh [OPTION]... + + --github-repository=REPO the github repository (e.g. spring-projects/spring-security) + --ssh-docs-path=PATH the full path that the docs will be deployed to (e.g. https://docs.spring.io/spring-security/reference/ is \${HTTP_DOCS}/spring-security/reference) +" +} + +__check_github_repository_owner_usage_error() { + echo "Error: $1" >&2 + __check_github_repository_owner_usage + exit 1 +} + +__check_github_repository_owner() { + local github_repository ssh_docs_path valid_args + valid_args=$(getopt --options '' --long ,github-repository:,ssh-docs-path: -- "$@") + if [[ $? -ne 0 ]]; then + __check_github_repository_owner_usage + exit 1; + fi + + eval set -- "$valid_args" + + while [ : ]; do + case "$1" in + --github-repository) + github_repository="$2" + shift 2 + ;; + --ssh-docs-path) + ssh_docs_path="$2" + shift 2 + ;; + --) shift; + break + ;; + *) + __check_github_repository_owner_usage_error "Invalid argument $1 $2" + ;; + esac + done + + if ! [[ "$github_repository" =~ .+/.+ ]]; then + __check_github_repository_owner_usage_error " '--github-repository' must be in the form of / but got '$github_repository'" + fi + if ! [[ "$ssh_docs_path" =~ ^/.+ ]]; then + __check_github_repository_owner_usage_error " '--ssh-docs-path' must start with and not equal / but got '$ssh_docs_path'" + fi + + local marker_file="${ssh_docs_path}/.github-repository" + + if [ -d "$ssh_docs_path" ]; then + # The path exists so ensure the marker file contents contain github_repository + local marker_file_content="" + if [ -f "$marker_file" ]; then + marker_file_content="$(cat $marker_file)" + fi + if [ "$marker_file_content" == "$github_repository" ]; then + echo "Owner is verified" + exit 0 + else + echo "Failed to verify that $ssh_docs_path is owned by $github_repository because the file $marker_file contains $marker_file_content" >&2 + exit 2 + fi + else + # The path does not yet exist so create the folder and add the marker file + echo "Directory $ssh_docs_path does not exist. Marking as owned by $github_repository" + mkdir -p "$ssh_docs_path" + echo -n "$github_repository" >$marker_file + exit 0 + fi + +} + +__check_github_repository_owner "$@" \ No newline at end of file diff --git a/rsync-schema/src/cleanup_ssh.sh b/rsync-schema/src/cleanup_ssh.sh new file mode 100755 index 0000000..1a1d017 --- /dev/null +++ b/rsync-schema/src/cleanup_ssh.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +__cleanup_ssh_usage() { + echo "usage: cleanup_ssh.sh [OPTION]... + + --ssh-private-key-path=PATH the path to the private key to use +" +} + +__cleanup_ssh_usage_error() { + echo "Error: $1" >&2 + usage + exit 1 +} + +__cleanup_ssh() { + local ssh_private_key_path valid_args + valid_args=$(getopt --options '' --long ssh-private-key-path: -- "$@") + if [[ $? -ne 0 ]]; then + usage + exit 1; + fi + + eval set -- "$valid_args" + + while [ : ]; do + case "$1" in + --ssh-private-key-path) + ssh_private_key_path="$2" + shift 2 + ;; + --) shift; + break + ;; + *) + __cleanup_ssh_usage_error "Invalid argument $1 $2" + ;; + esac + done + + rm -f "$ssh_private_key_path" +} + +__cleanup_ssh "$@" \ No newline at end of file diff --git a/rsync-schema/src/rsync_schema.sh b/rsync-schema/src/rsync_schema.sh new file mode 100755 index 0000000..85965e2 --- /dev/null +++ b/rsync-schema/src/rsync_schema.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +__rsync_schema_usage() { + echo "usage: rsync_schema.sh [OPTION]... + + --ssh-host=SSH_HOST the ssh host in the format USER@HOST to connect to ssh + --ssh-private-key-path=KEY_PATH the path to the private key used to connect to ssh + --ssh-host-path=HOST_PATH the path of the ssh server to sync the documentation to + --dry-run signals that rsync should be in dry run mode + --local-path=PATH the local directory path to sync to the server +" +} + +__rsync_schema_usage_error() { + echo "Error: $1" >&2 + __rsync_schema_usage + exit 1 +} + +__rsync_schema() { + local ssh_host ssh_host_path local_path ssh_private_key_path + local dry_run="false" + valid_args=$(getopt --options '' --long ssh-host:,ssh-host-path:,dry-run,local-path:,ssh-private-key-path: -- "$@") + if [[ $? -ne 0 ]]; then + __rsync_schema_usage + exit 1; + fi + + eval set -- "$valid_args" + + while [ : ]; do + case "$1" in + --ssh-host) + ssh_host="$2" + shift 2 + ;; + --ssh-host-path) + ssh_host_path="$2" + shift 2 + ;; + --local-path) + local_path="$2" + shift 2 + ;; + --ssh-private-key-path) + ssh_private_key_path="$2" + shift 2 + ;; + --dry-run) + dry_run=true + shift + ;; + --) shift; + break + ;; + *) + __rsync_schema_usage_error "Invalid argument $1 $2" + ;; + esac + done + + if [ -z "$ssh_host" ]; then + __rsync_schema_usage_error "Missing option '--ssh-host'" + fi + if [ -z "$ssh_host_path" ]; then + __rsync_schema_usage_error "Missing option '--ssh-host-path'" + fi + if [ -z "$local_path" ]; then + __rsync_schema_usage_error "Missing option '--local-path'" + fi + if [ -z "$ssh_private_key_path" ]; then + __rsync_schema_usage_error "Missing option '--ssh-private-key-path'" + fi + + local rsync_opts='-avz --delete ' + if [ "$dry_run" != "false" ]; then + rsync_opts="$rsync_opts --dry-run " + fi + if [ -f "$local_path/.htaccess" ]; then + rsync_opts="$rsync_opts --include /.htaccess " + fi + if [ -d "$local_path/.cache" ]; then + rsync_opts="$rsync_opts$(find $local_path/.cache -printf ' --include /.cache/%P')" + fi + rsync_opts="$rsync_opts --exclude /.github-repository --exclude /.cache --exclude /.cache/* " + # Disable filename expansion (globbing) + # https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html + ( + set -f + rsync $rsync_opts -e "ssh -i $ssh_private_key_path" $local_path/ "$ssh_host:$ssh_host_path" + ) +} + + +__rsync_schema "$@" \ No newline at end of file diff --git a/rsync-schema/src/setup_ssh.sh b/rsync-schema/src/setup_ssh.sh new file mode 100755 index 0000000..497abcc --- /dev/null +++ b/rsync-schema/src/setup_ssh.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +__setup_ssh_usage() { + echo "usage: setup_ssh.sh [OPTION]... + + --ssh-private-key-path=PATH the path to the private key to use + --ssh-private-key=KEY the private key to use which will be written to ssh-private-key-path + --ssh-known-host=KNOWN_HOST the known host to add to known_hosts file +" +} + +__setup_ssh_usage_error() { + echo "Error: $1" >&2 + __setup_ssh_usage + exit 1 +} + +__setup_ssh() { + local ssh_private_key_path ssh_private_key ssh_known_host valid_args + VALID_ARGS=$(getopt --options '' --long ssh-private-key-path:,ssh-private-key:,ssh-known-host: -- "$@") + if [[ $? -ne 0 ]]; then + __setup_ssh_usage + exit 1; + fi + + eval set -- "$VALID_ARGS" + + while [ : ]; do + case "$1" in + --ssh-private-key-path) + ssh_private_key_path="$2" + shift 2 + ;; + --ssh-private-key) + ssh_private_key="$2" + shift 2 + ;; + --ssh-known-host) + ssh_known_host="$2" + shift 2 + ;; + --) shift; + break + ;; + *) + usage_error "Invalid argument $1 $2" + ;; + esac + done + + install -m 600 -D /dev/null "$ssh_private_key_path" + echo "$ssh_private_key" > "$ssh_private_key_path" + if [ "$ssh_known_host" != "#" ]; then + echo "$ssh_known_host" > ~/.ssh/known_hosts + fi +} + +__setup_ssh "$@" \ No newline at end of file diff --git a/rsync-schema/test/bats b/rsync-schema/test/bats new file mode 120000 index 0000000..44d3c3c --- /dev/null +++ b/rsync-schema/test/bats @@ -0,0 +1 @@ +../../bats-submodules/test/bats \ No newline at end of file diff --git a/rsync-schema/test/docker/bin/setup-docker.sh b/rsync-schema/test/docker/bin/setup-docker.sh new file mode 100755 index 0000000..c5fef0d --- /dev/null +++ b/rsync-schema/test/docker/bin/setup-docker.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +sudo apt-get update +sudo apt-get install ca-certificates curl gnupg +# GPG key +sudo install -m 0755 -d /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg +sudo chmod a+r /etc/apt/keyrings/docker.gpg +# Add repository +echo \ + "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ + "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +# Update +sudo apt-get update +# Install +sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin +wget https://desktop.docker.com/linux/main/amd64/docker-desktop-4.22.1-amd64.deb?utm_source=docker&utm_medium=webreferral&utm_campaign=docs-driven-download-linux-amd64&_gl=1*11pxwe2*_ga*MTI0MzY5MDc5Mi4xNjkzNDk1MDU5*_ga_XJWPQMJYHQ*MTY5MzQ5NTA1OC4xLjEuMTY5MzQ5NjE3Ni42MC4wLjA. + +# Launch Desktop +systemctl --user start docker-desktop \ No newline at end of file diff --git a/rsync-schema/test/docker/compose.yml b/rsync-schema/test/docker/compose.yml new file mode 100644 index 0000000..30a893e --- /dev/null +++ b/rsync-schema/test/docker/compose.yml @@ -0,0 +1,25 @@ +--- +version: "2.1" +services: + openssh-server: + image: lscr.io/linuxserver/openssh-server:latest + container_name: openssh-server + hostname: openssh-server #optional + environment: + - PUID=1000 + - PGID=1000 + - TZ=Etc/UTC + - PUBLIC_KEY="ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAD+VmfHsc/In4dBGOwKP6KMrHBhqhzXavYmqcJg6eZMUnR+dWIdouNHleuRtljGoumiNwQhQps5HfVEqzcnrpn8LwB0rC7466f81Hl6NDL33yXIj7SF6FckhggmL7cyXHzjSiWp76aAO5K2nIddX6SJSCt3+eUHpVXHwcXqPiS3mHFXDw== root@c14705ad04fb" +# - PUBLIC_KEY_FILE=/path/to/file #optional +# - PUBLIC_KEY_DIR=/path/to/directory/containing/_only_/pubkeys #optional +# - PUBLIC_KEY_URL=https://github.com/username.keys #optional +# - SUDO_ACCESS=false #optional +# - PASSWORD_ACCESS=false #optional +# - USER_PASSWORD=password #optional +# - USER_PASSWORD_FILE=/path/to/file #optional + - USER_NAME=user + volumes: + - ./volume/httdocs/:/opt/www/domains/spring.io/docs/htdocs/ + ports: + - 2222:2222 + restart: unless-stopped \ No newline at end of file diff --git a/rsync-schema/test/helpers b/rsync-schema/test/helpers new file mode 120000 index 0000000..b92037a --- /dev/null +++ b/rsync-schema/test/helpers @@ -0,0 +1 @@ +../../bats-submodules/test/helpers \ No newline at end of file diff --git a/rsync-schema/test/resources/test-check_github_repository_owner.bats/antora/.github-repository b/rsync-schema/test/resources/test-check_github_repository_owner.bats/antora/.github-repository new file mode 100644 index 0000000..3233eee --- /dev/null +++ b/rsync-schema/test/resources/test-check_github_repository_owner.bats/antora/.github-repository @@ -0,0 +1 @@ +spring-projects/spring-security \ No newline at end of file diff --git a/rsync-schema/test/resources/test-check_github_repository_owner.bats/no-reference/api/keep.txt b/rsync-schema/test/resources/test-check_github_repository_owner.bats/no-reference/api/keep.txt new file mode 100644 index 0000000..e69de29 diff --git a/rsync-schema/test/resources/test-check_github_repository_owner.bats/no-reference/other.txt b/rsync-schema/test/resources/test-check_github_repository_owner.bats/no-reference/other.txt new file mode 100644 index 0000000..e69de29 diff --git a/rsync-schema/test/resources/test-check_github_repository_owner.bats/spring-security/reference/.github-repository b/rsync-schema/test/resources/test-check_github_repository_owner.bats/spring-security/reference/.github-repository new file mode 100644 index 0000000..3233eee --- /dev/null +++ b/rsync-schema/test/resources/test-check_github_repository_owner.bats/spring-security/reference/.github-repository @@ -0,0 +1 @@ +spring-projects/spring-security \ No newline at end of file diff --git a/rsync-schema/test/resources/test-rsync_schema.bats/htaccess/.htaccess b/rsync-schema/test/resources/test-rsync_schema.bats/htaccess/.htaccess new file mode 100644 index 0000000..e69de29 diff --git a/rsync-schema/test/test-action.bats b/rsync-schema/test/test-action.bats new file mode 100644 index 0000000..8680293 --- /dev/null +++ b/rsync-schema/test/test-action.bats @@ -0,0 +1,187 @@ +setup () { + load 'test_helper/common-setup' + _common_setup +} + +# executed after each test +teardown() { + _common_teardown +} + +@test "no arguments" { + run action.sh + assert [ "$status" -eq 1 ] + assert_regex "${lines[0]}" 'Error: Missing option .*' + assert [ "${lines[1]}" = 'usage: action.sh [OPTION]...' ] +} + +@test "usage" { + run action.sh + assert [ "$status" -eq 1 ] + assert [ "${output}" = "Error: Missing option '--docs-username' +usage: action.sh [OPTION]... + + --docs-username=USERNAME the username used to connect to ssh + --docs-host=HOST the host to connect to ssh + --docs-ssh-key=KEY the private key used to connect to ssh + --docs-ssh-host-key=HOST_KEY the host key used to connect to ssh + --dry-run signals that rsync should be in dry run mode + --site-path=PATH the local directory path to sync to the server. Default build/schema + --version=VERSION the release version for the schema + --github-repository=GH_REPO the github repository (e.g. spring-projects/spring-security)" ] +} + +@test "invalid long option" { + run action.sh --invalid + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "getopt: unrecognized option '--invalid'" ] + assert [ "${lines[1]}" = 'usage: action.sh [OPTION]...' ] +} + +# --docs-username USER --docs-host HOST --docs-ssh-key KEY --docs-ssh-host-key HOST_KEY --site-path SITE_PATH --github-repository spring-projects/spring-security +@test "missing docs-username" { + run action.sh --docs-host HOST --docs-ssh-key KEY --docs-ssh-host-key HOST_KEY --site-path SITE_PATH --github-repository spring-projects/spring-security + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: Missing option '--docs-username'" ] + assert [ "${lines[1]}" = 'usage: action.sh [OPTION]...' ] +} + +@test "missing docs-host" { + run action.sh --docs-username USER --docs-ssh-key KEY --docs-ssh-host-key HOST_KEY --site-path SITE_PATH --github-repository spring-projects/spring-security + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: Missing option '--docs-host'" ] + assert [ "${lines[1]}" = 'usage: action.sh [OPTION]...' ] +} + +@test "missing docs-ssh-key" { + run action.sh --docs-username USER --docs-host HOST --docs-ssh-host-key HOST_KEY --site-path SITE_PATH --github-repository spring-projects/spring-security + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: Missing option '--docs-ssh-key'" ] + assert [ "${lines[1]}" = 'usage: action.sh [OPTION]...' ] +} + +@test "docs-ssh-key with space" { + stub setup_ssh.sh "$(capture_program_args "setup_ssh")" + stub rsync_schema.sh "$(capture_program_args "rsync_schema")" + stub cleanup_ssh.sh "$(capture_program_args "cleanup_ssh")" + + run action.sh --docs-username USER --docs-host HOST --docs-ssh-key 'SSH KEY' --docs-ssh-host-key HOST_KEY --site-path SITE_PATH --github-repository spring-projects/spring-security --version VERSION + + assert_success + assert_output "" # No warnings due to spaces + assert_program_args "setup_ssh" "--ssh-private-key-path $HOME/.ssh/spring-projects/spring-security --ssh-private-key SSH KEY --ssh-known-host HOST_KEY" + assert_program_args "rsync_schema" "--ssh-host USER@HOST --ssh-host-path /var/www/domains/spring.io/docs/htdocs/autorepo/schema/spring-security/VERSION/ --local-path SITE_PATH --ssh-private-key-path $HOME/.ssh/spring-projects/spring-security" + assert_program_args "cleanup_ssh" "--ssh-private-key-path $HOME/.ssh/spring-projects/spring-security" + + unstub --allow-missing setup_ssh.sh + unstub rsync_schema.sh + unstub cleanup_ssh.sh +} + +@test "missing docs-ssh-host-key" { + run action.sh --docs-username USER --docs-host HOST --docs-ssh-key KEY --site-path SITE_PATH --github-repository spring-projects/spring-security --version VERSION + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: Missing option '--docs-ssh-host-key'" ] + assert [ "${lines[1]}" = 'usage: action.sh [OPTION]...' ] +} + +@test "docs-ssh-host-key with space" { + stub setup_ssh.sh "$(capture_program_args "setup_ssh")" + stub rsync_schema.sh "$(capture_program_args "rsync_schema")" + stub cleanup_ssh.sh "$(capture_program_args "cleanup_ssh")" + + run action.sh --docs-username USER --docs-host HOST --docs-ssh-key 'SSH_KEY' --docs-ssh-host-key 'HOST KEY' --site-path SITE_PATH --github-repository spring-projects/spring-security --version VERSION + + assert_success + assert_output "" # No warnings due to spaces + assert_program_args "setup_ssh" "--ssh-private-key-path $HOME/.ssh/spring-projects/spring-security --ssh-private-key SSH_KEY --ssh-known-host HOST KEY" + assert_program_args "rsync_schema" "--ssh-host USER@HOST --ssh-host-path /var/www/domains/spring.io/docs/htdocs/autorepo/schema/spring-security/VERSION/ --local-path SITE_PATH --ssh-private-key-path $HOME/.ssh/spring-projects/spring-security" + assert_program_args "cleanup_ssh" "--ssh-private-key-path $HOME/.ssh/spring-projects/spring-security" + + unstub --allow-missing setup_ssh.sh + unstub rsync_schema.sh + unstub cleanup_ssh.sh +} + +@test "missing version" { + run action.sh --docs-username USER --docs-host HOST --docs-ssh-key KEY --docs-ssh-host-key HOST_KEY --site-path SITE_PATH --github-repository spring-projects/spring-security + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: Missing option '--version'" ] + assert [ "${lines[1]}" = 'usage: action.sh [OPTION]...' ] +} + +@test "missing github-repository" { + run action.sh --docs-username USER --docs-host HOST --docs-ssh-key KEY --docs-ssh-host-key HOST_KEY --site-path SITE_PATH --version VERSION + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: Missing option '--github-repository'" ] + assert [ "${lines[1]}" = 'usage: action.sh [OPTION]...' ] +} + +@test "valid arguments" { + stub setup_ssh.sh "$(capture_program_args "setup_ssh")" + stub rsync_schema.sh "$(capture_program_args "rsync_schema")" + stub cleanup_ssh.sh "$(capture_program_args "cleanup_ssh")" + + run action.sh --docs-username USER --docs-host HOST --docs-ssh-key KEY --docs-ssh-host-key HOST_KEY --site-path SITE_PATH --github-repository spring-projects/spring-security --version VERSION + + assert_success + assert_program_args "setup_ssh" "--ssh-private-key-path $HOME/.ssh/spring-projects/spring-security --ssh-private-key KEY --ssh-known-host HOST_KEY" + assert_program_args "rsync_schema" "--ssh-host USER@HOST --ssh-host-path /var/www/domains/spring.io/docs/htdocs/autorepo/schema/spring-security/VERSION/ --local-path SITE_PATH --ssh-private-key-path $HOME/.ssh/spring-projects/spring-security" + assert_program_args "cleanup_ssh" "--ssh-private-key-path $HOME/.ssh/spring-projects/spring-security" + + unstub --allow-missing setup_ssh.sh + unstub rsync_schema.sh + unstub cleanup_ssh.sh +} + +@test "missing site-path defaults build/site" { + stub setup_ssh.sh "$(capture_program_args "setup_ssh")" + stub rsync_schema.sh "$(capture_program_args "rsync_schema")" + stub cleanup_ssh.sh "$(capture_program_args "cleanup_ssh")" + + run action.sh --docs-username USER --docs-host HOST --docs-ssh-key KEY --docs-ssh-host-key HOST_KEY --github-repository spring-projects/spring-security --version VERSION + + assert_success + assert_program_args "setup_ssh" "--ssh-private-key-path $HOME/.ssh/spring-projects/spring-security --ssh-private-key KEY --ssh-known-host HOST_KEY" + assert_program_args "rsync_schema" "--ssh-host USER@HOST --ssh-host-path /var/www/domains/spring.io/docs/htdocs/autorepo/schema/spring-security/VERSION/ --local-path build/schema --ssh-private-key-path $HOME/.ssh/spring-projects/spring-security" + assert_program_args "cleanup_ssh" "--ssh-private-key-path $HOME/.ssh/spring-projects/spring-security" + + unstub --allow-missing setup_ssh.sh + unstub rsync_schema.sh + unstub cleanup_ssh.sh +} + +# had a bug using -e instead of -z +@test "site-path where path exists does not default build/site" { + stub setup_ssh.sh "$(capture_program_args "setup_ssh")" + stub rsync_schema.sh "$(capture_program_args "rsync_schema")" + stub cleanup_ssh.sh "$(capture_program_args "cleanup_ssh")" + + run action.sh --docs-username USER --docs-host HOST --site-path "$BATS_TEMP_DIR" --docs-ssh-key KEY --docs-ssh-host-key HOST_KEY --github-repository spring-projects/spring-security --version VERSION + + assert_success + assert_program_args "setup_ssh" "--ssh-private-key-path $HOME/.ssh/spring-projects/spring-security --ssh-private-key KEY --ssh-known-host HOST_KEY" + assert_program_args "rsync_schema" "--ssh-host USER@HOST --ssh-host-path /var/www/domains/spring.io/docs/htdocs/autorepo/schema/spring-security/VERSION/ --local-path $BATS_TEMP_DIR --ssh-private-key-path $HOME/.ssh/spring-projects/spring-security" + assert_program_args "cleanup_ssh" "--ssh-private-key-path $HOME/.ssh/spring-projects/spring-security" + + unstub --allow-missing setup_ssh.sh + unstub rsync_schema.sh + unstub cleanup_ssh.sh +} + +@test "dry-run=true" { + stub setup_ssh.sh "$(capture_program_args "setup_ssh")" + stub rsync_schema.sh "$(capture_program_args "rsync_schema")" + stub cleanup_ssh.sh "$(capture_program_args "cleanup_ssh")" + + run action.sh --docs-username USER --docs-host HOST --docs-ssh-key KEY --docs-ssh-host-key HOST_KEY --site-path SITE_PATH --github-repository spring-projects/spring-security --version VERSION --dry-run + + assert_success + assert_program_args "setup_ssh" "--ssh-private-key-path $HOME/.ssh/spring-projects/spring-security --ssh-private-key KEY --ssh-known-host HOST_KEY" + assert_program_args "rsync_schema" "--ssh-host USER@HOST --ssh-host-path /var/www/domains/spring.io/docs/htdocs/autorepo/schema/spring-security/VERSION/ --local-path SITE_PATH --ssh-private-key-path $HOME/.ssh/spring-projects/spring-security --dry-run" + assert_program_args "cleanup_ssh" "--ssh-private-key-path $HOME/.ssh/spring-projects/spring-security" + + unstub --allow-missing setup_ssh.sh + unstub rsync_schema.sh + unstub cleanup_ssh.sh +} diff --git a/rsync-schema/test/test-check_github_repository_owner.bats b/rsync-schema/test/test-check_github_repository_owner.bats new file mode 100644 index 0000000..6aa88fc --- /dev/null +++ b/rsync-schema/test/test-check_github_repository_owner.bats @@ -0,0 +1,100 @@ +setup () { + load 'test_helper/common-setup' + _common_setup +} + +# executed after each test +teardown() { + _common_teardown +} + +@test "no arguments" { + run check_github_repository_owner.sh + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: '--github-repository' must be in the form of / but got ''" ] + assert [ "${lines[1]}" = 'usage: check_github_repository_owner.sh [OPTION]...' ] +} + +@test "usage" { + run check_github_repository_owner.sh + assert [ "$status" -eq 1 ] + assert [ "${output}" = "Error: '--github-repository' must be in the form of / but got '' +usage: check_github_repository_owner.sh [OPTION]... + + --github-repository=REPO the github repository (e.g. spring-projects/spring-security) + --ssh-docs-path=PATH the full path that the docs will be deployed to (e.g. https://docs.spring.io/spring-security/reference/ is \${HTTP_DOCS}/spring-security/reference)" ] +} + +@test "invalid long option" { + run check_github_repository_owner.sh --invalid + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "getopt: unrecognized option '--invalid'" ] + assert [ "${lines[1]}" = 'usage: check_github_repository_owner.sh [OPTION]...' ] +} + +# --github-repository spring-projects/spring-security --ssh-docs-path /spring-security/reference +@test "missing github-repository" { + run check_github_repository_owner.sh --ssh-docs-path /spring-security/reference + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: '--github-repository' must be in the form of / but got ''" ] + assert [ "${lines[1]}" = 'usage: check_github_repository_owner.sh [OPTION]...' ] +} + +@test "invalid github-repository REPO" { + run check_github_repository_owner.sh --github-repository REPO --ssh-docs-path /spring-security/reference + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: '--github-repository' must be in the form of / but got 'REPO'" ] + assert [ "${lines[1]}" = 'usage: check_github_repository_owner.sh [OPTION]...' ] +} + +@test "missing ssh-docs-path" { + run check_github_repository_owner.sh --github-repository spring-projects/spring-security + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: '--ssh-docs-path' must start with and not equal / but got ''" ] + assert [ "${lines[1]}" = 'usage: check_github_repository_owner.sh [OPTION]...' ] +} + +@test "invalid ssh-docs-path spring-security/reference" { + run check_github_repository_owner.sh --github-repository spring-projects/spring-security --ssh-docs-path spring-security/reference + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: '--ssh-docs-path' must start with and not equal / but got 'spring-security/reference'" ] + assert [ "${lines[1]}" = 'usage: check_github_repository_owner.sh [OPTION]...' ] +} + +# https://github.com/spring-io/spring-doc-actions/issues/20 +@test "Allow httpdocs-path that does not end in /reference" { + local dir="${BATS_RESOURCE_TEMP_DIR}/antora" + run check_github_repository_owner.sh --github-repository spring-projects/spring-security --ssh-docs-path "$dir" + assert_success + assert_output "Owner is verified" +} + +@test "existing project with valid marker file" { + local dir="${BATS_RESOURCE_TEMP_DIR}/spring-security/reference" + run check_github_repository_owner.sh --github-repository spring-projects/spring-security --ssh-docs-path "$dir" + assert_success + assert_output "Owner is verified" +} + +@test "existing project with invalid marker file" { + local dir="${BATS_RESOURCE_TEMP_DIR}/spring-security/reference" + run check_github_repository_owner.sh --github-repository spring-projects/spring-security2 --ssh-docs-path "$dir" + assert_failure + assert_output "Failed to verify that $dir is owned by spring-projects/spring-security2 because the file $dir/.github-repository contains spring-projects/spring-security" +} + +@test "new-project" { + local dir="${BATS_RESOURCE_TEMP_DIR}/new-project/reference" + run check_github_repository_owner.sh --github-repository spring-projects/new-project --ssh-docs-path "$dir" + assert_success + assert_output "Directory $dir does not exist. Marking as owned by spring-projects/new-project" + assert [ "spring-projects/new-project" = "$(cat $dir/.github-repository)" ] +} + +@test "no-reference" { + local dir="${BATS_RESOURCE_TEMP_DIR}/no-reference/reference" + run check_github_repository_owner.sh --github-repository spring-projects/no-reference --ssh-docs-path "$dir" + assert_success + assert_output "Directory $dir does not exist. Marking as owned by spring-projects/no-reference" + assert [ "spring-projects/no-reference" = "$(cat $dir/.github-repository)" ] +} \ No newline at end of file diff --git a/rsync-schema/test/test-rsync_schema.bats b/rsync-schema/test/test-rsync_schema.bats new file mode 100644 index 0000000..67c7d2a --- /dev/null +++ b/rsync-schema/test/test-rsync_schema.bats @@ -0,0 +1,99 @@ +setup () { + load 'test_helper/common-setup' + _common_setup +} + +# executed after each test +teardown() { + _common_teardown +} + +@test "no arguments" { + run rsync_schema.sh + assert [ "$status" -eq 1 ] + assert_regex "${lines[0]}" 'Error: Missing option .*' + assert [ "${lines[1]}" = 'usage: rsync_schema.sh [OPTION]...' ] +} + +@test "usage" { + run rsync_schema.sh + assert [ "$status" -eq 1 ] + assert [ "${output}" = "Error: Missing option '--ssh-host' +usage: rsync_schema.sh [OPTION]... + + --ssh-host=SSH_HOST the ssh host in the format USER@HOST to connect to ssh + --ssh-private-key-path=KEY_PATH the path to the private key used to connect to ssh + --ssh-host-path=HOST_PATH the path of the ssh server to sync the documentation to + --dry-run signals that rsync should be in dry run mode + --local-path=PATH the local directory path to sync to the server" ] +} + +@test "invalid long option" { + run rsync_schema.sh --invalid + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "getopt: unrecognized option '--invalid'" ] + assert [ "${lines[1]}" = 'usage: rsync_schema.sh [OPTION]...' ] +} + +# --ssh-host HOST --ssh-host-path HOST_PATH --local-path LOCAL_PATH --ssh-private-key-path PRIVATE_KEY_PATH +@test "missing ssh-host" { + run rsync_schema.sh --ssh-host-path HOST_PATH --local-path LOCAL_PATH --ssh-private-key-path PRIVATE_KEY_PATH + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: Missing option '--ssh-host'" ] + assert [ "${lines[1]}" = 'usage: rsync_schema.sh [OPTION]...' ] +} + +@test "missing ssh-host-path" { + run rsync_schema.sh --ssh-host HOST --local-path LOCAL_PATH --ssh-private-key-path PRIVATE_KEY_PATH + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: Missing option '--ssh-host-path'" ] + assert [ "${lines[1]}" = 'usage: rsync_schema.sh [OPTION]...' ] +} + +@test "missing local-path" { + run rsync_schema.sh --ssh-host HOST --ssh-host-path HOST_PATH --ssh-private-key-path PRIVATE_KEY_PATH + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: Missing option '--local-path'" ] + assert [ "${lines[1]}" = 'usage: rsync_schema.sh [OPTION]...' ] +} + +@test "missing ssh-private-key-path" { + run rsync_schema.sh --ssh-host HOST --ssh-host-path HOST_PATH --local-path LOCAL_PATH + assert [ "$status" -eq 1 ] + assert [ "${lines[0]}" = "Error: Missing option '--ssh-private-key-path'" ] + assert [ "${lines[1]}" = 'usage: rsync_schema.sh [OPTION]...' ] +} + +@test "when exists .htaccess included before any excludes" { + local dir="${BATS_RESOURCE_TEMP_DIR}/htaccess" + stub rsync "$(capture_program_args "rsync")" + + run rsync_schema.sh --ssh-host HOST --ssh-host-path HOST_PATH --ssh-private-key-path PRIVATE_KEY_PATH --local-path "$dir" + + local rsync_args=$(get_program_args "rsync") + assert_success + assert_regex "$rsync_args" "^-avz --delete --include /.htaccess " + unstub rsync +} + +@test "when does not exists .htaccess not included" { + local dir="${BATS_RESOURCE_TEMP_DIR}/no-htaccess" + stub rsync "$(capture_program_args "rsync")" + + run rsync_schema.sh --ssh-host HOST --ssh-host-path HOST_PATH --ssh-private-key-path PRIVATE_KEY_PATH --local-path "$dir" + + local rsync_args=$(get_program_args "rsync") + assert_success + refute_regex "$rsync_args" " --include /.htaccess " + unstub rsync +} + +@test "when rsync fails script returns non-zero" { + local dir="${BATS_RESOURCE_TEMP_DIR}/no-htaccess" + stub rsync "exit 1" + + run rsync_schema.sh --ssh-host HOST --ssh-host-path HOST_PATH --ssh-private-key-path PRIVATE_KEY_PATH --local-path "$dir" + + assert_failure + unstub rsync +} \ No newline at end of file diff --git a/rsync-schema/test/test_helper b/rsync-schema/test/test_helper new file mode 120000 index 0000000..207111b --- /dev/null +++ b/rsync-schema/test/test_helper @@ -0,0 +1 @@ +../../bats-submodules/test/test_helper \ No newline at end of file