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
10 changes: 5 additions & 5 deletions scripts/check-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
# version that run found and without running the strategies
# With --dry-run: runs update-pkg.sh or publish-pkg.sh in dry-run mode
#
# Writes per-package status to .status/ directory for README generation
# and auto-issue creation.
# Writes per-package status to .status/ of the data root (AURTOMATOR_DATA_DIR)
# for README generation and auto-issue creation.

set -euo pipefail
# shellcheck source=lib.sh
Expand Down Expand Up @@ -99,7 +99,7 @@ done
# path.
if [[ "$MODE" == "verify" ]]; then
failed=0
for pkg_file in "${AURTOMATOR_DIR}"/packages/*.yml; do
for pkg_file in "${AURTOMATOR_DATA_DIR}"/packages/*.yml; do
[[ -f "$pkg_file" ]] || continue
pkg_name=$(pkg_get "$pkg_file" .name)
prepared="${WORK_DIR}/prepared/${pkg_name}"
Expand Down Expand Up @@ -141,7 +141,7 @@ if [[ "$MODE" == "verify" ]]; then
fi

# Status directory for per-package results
STATUS_DIR="${AURTOMATOR_DIR}/.status"
STATUS_DIR="${AURTOMATOR_DATA_DIR}/.status"

# --prepare and --publish take the statuses of the check run before them,
# read here before anything else runs, and run no strategy: --prepare runs
Expand Down Expand Up @@ -481,7 +481,7 @@ run_package() {
}

RECHECK=()
for pkg_file in "${AURTOMATOR_DIR}"/packages/*.yml; do
for pkg_file in "${AURTOMATOR_DATA_DIR}"/packages/*.yml; do
[[ -f "$pkg_file" ]] || continue
run_package "$pkg_file" 1
done
Expand Down
24 changes: 21 additions & 3 deletions scripts/lib/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,30 @@
#
# Usage: source "${SCRIPT_DIR}/../scripts/lib/common.sh"
# Requires: yq (https://github.com/mikefarah/yq)
#
# AURTOMATOR_DIR is the root of the checkout that holds this file.
# AURTOMATOR_DATA_DIR is the directory with the packages, .status/,
# .aurtomator.conf, README.md and the origin remote the badges read. It comes
# from the environment and defaults to the working directory.

set -euo pipefail

# Resolve project root
# Resolve project root. The scripts and lib/version.sh read it.
# shellcheck disable=SC2034
AURTOMATOR_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"

# Resolve the data root. The variable is set last, so the message names the
# value as the caller gave it.
resolve_data_dir() {
local dir
if ! dir="$(cd -- "${AURTOMATOR_DATA_DIR:-.}" 2>/dev/null && pwd)"; then
echo "AURTOMATOR_DATA_DIR is not a directory: ${AURTOMATOR_DATA_DIR}" >&2
exit 1
fi
AURTOMATOR_DATA_DIR="$dir"
}
resolve_data_dir

# =============================================================================
# DEPENDENCY CHECK
# =============================================================================
Expand Down Expand Up @@ -103,7 +121,7 @@ pkg_asset_var() {
# =============================================================================

load_config() {
local config="${AURTOMATOR_DIR}/.aurtomator.conf"
local config="${AURTOMATOR_DATA_DIR}/.aurtomator.conf"
if [[ -f "$config" ]]; then
# shellcheck source=/dev/null
source "$config"
Expand All @@ -118,7 +136,7 @@ load_config() {
# Usage: pkg_file my-package
pkg_file() {
local name="$1"
local file="${AURTOMATOR_DIR}/packages/${name}.yml"
local file="${AURTOMATOR_DATA_DIR}/packages/${name}.yml"
if [[ ! -f "$file" ]]; then
log_err "Package not found: $file"
return 1
Expand Down
46 changes: 30 additions & 16 deletions scripts/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
#
# setup.sh - First-time aurtomator configuration
#
# Usage:
# ./scripts/setup.sh # full setup (all steps)
# ./scripts/setup.sh identity # git author name/email only
# ./scripts/setup.sh ssh # SSH key for AUR only
# ./scripts/setup.sh gpg # GPG signing key only
# ./scripts/setup.sh secrets # GitHub Secrets only
# ./scripts/setup.sh verify # verify everything works
# Usage, from inside your packages repository:
# cd <your packages repository> && <clone of aurtomator>/scripts/setup.sh # full setup (all steps)
# setup.sh identity # git author name/email only
# setup.sh ssh # SSH key for AUR only
# setup.sh gpg # GPG signing key only
# setup.sh secrets # GitHub Secrets only
# setup.sh verify # verify everything works
#
# Options:
# --git-name <name> Git author name for AUR commits
Expand All @@ -21,7 +21,20 @@ set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
AURTOMATOR_DIR="${AURTOMATOR_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
CONFIG_FILE="${AURTOMATOR_DIR}/.aurtomator.conf"

# The data root, resolved as in lib/common.sh, which this script does not
# source. The variable is set last, so the message names the value as the
# caller gave it.
resolve_data_dir() {
local dir
if ! dir="$(cd -- "${AURTOMATOR_DATA_DIR:-.}" 2>/dev/null && pwd)"; then
echo "AURTOMATOR_DATA_DIR is not a directory: ${AURTOMATOR_DATA_DIR}" >&2
exit 1
fi
AURTOMATOR_DATA_DIR="$dir"
}
resolve_data_dir
CONFIG_FILE="${AURTOMATOR_DATA_DIR}/.aurtomator.conf"

# Defaults
GIT_AUTHOR_NAME=""
Expand Down Expand Up @@ -101,6 +114,7 @@ save_config() {

setup_identity() {
header "identity" "Who you are on AUR"
printf " Data directory: %s\n" "$AURTOMATOR_DATA_DIR"

# Detect defaults from git config
local default_name default_email
Expand Down Expand Up @@ -151,7 +165,7 @@ check_ssh_key() {
printf "\n CI uses the key without a prompt. Remove the passphrase from a copy:\n"
printf " cp %s %s-ci\n" "$AUR_SSH_KEY" "$AUR_SSH_KEY"
printf " ssh-keygen -p -N '' -f %s-ci\n" "$AUR_SSH_KEY"
printf " ./scripts/setup.sh ssh --ssh-key %s-ci\n\n" "$AUR_SSH_KEY"
printf " %s ssh --ssh-key %s-ci\n\n" "$0" "$AUR_SSH_KEY"
return 1
else
fail "Not a valid private key: $AUR_SSH_KEY"
Expand Down Expand Up @@ -362,7 +376,7 @@ setup_secrets() {
gpg_source="copy"
elif gpg_key_has_passphrase "$GPG_KEY_ID"; then
warn "GPG key $GPG_KEY_ID has a passphrase, GPG_SIGNING_KEY not set"
warn "Run ./scripts/setup.sh gpg secrets to make a passphrase-free copy"
warn "Run $0 gpg secrets to make a passphrase-free copy"
else
gpg_source="key"
fi
Expand All @@ -371,7 +385,7 @@ setup_secrets() {
if [[ "$has_gh" == "true" ]]; then
# Detect repo from origin remote (not upstream)
local gh_repo
gh_repo=$(git -C "$AURTOMATOR_DIR" remote get-url origin 2>/dev/null | sed 's|.*github.com[:/]||; s|\.git$||' || true)
gh_repo=$(git -C "$AURTOMATOR_DATA_DIR" remote get-url origin 2>/dev/null | sed 's|.*github.com[:/]||; s|\.git$||' || true)
if [[ -z "$gh_repo" ]]; then
gh_repo=$(ask "GitHub repo (owner/name)")
fi
Expand Down Expand Up @@ -479,7 +493,7 @@ verify_all() {
# Secrets
if command -v gh &>/dev/null && gh auth status &>/dev/null 2>&1; then
local gh_repo
gh_repo=$(git -C "$AURTOMATOR_DIR" remote get-url origin 2>/dev/null | sed 's|.*github.com[:/]||; s|\.git$||' || true)
gh_repo=$(git -C "$AURTOMATOR_DATA_DIR" remote get-url origin 2>/dev/null | sed 's|.*github.com[:/]||; s|\.git$||' || true)
local secret_list
secret_list=$(gh secret list -R "$gh_repo" 2>/dev/null || true)
local secret_count=0
Expand All @@ -503,10 +517,10 @@ verify_all() {

if [[ "$errors" -eq 0 ]]; then
printf "\n %s%sReady.%s Add your first package:\n" "$GREEN" "$BOLD" "$RESET"
printf " cp packages/example.yml.sample packages/<name>.yml\n\n"
printf " cp %s/packages/example.yml.sample %s/packages/<name>.yml\n\n" "$AURTOMATOR_DIR" "$AURTOMATOR_DATA_DIR"
else
printf "\n %s%s%d issue(s) found.%s Fix and re-run:\n" "$YELLOW" "$BOLD" "$errors" "$RESET"
printf " ./scripts/setup.sh verify\n\n"
printf " %s verify\n\n" "$0"
return 1
fi
}
Expand Down Expand Up @@ -549,7 +563,7 @@ while [[ $# -gt 0 ]]; do
exit 0
;;
*)
echo "Unknown option: $1 (see ./scripts/setup.sh --help)" >&2
echo "Unknown option: $1 (see $0 --help)" >&2
exit 1
;;
esac
Expand Down Expand Up @@ -580,5 +594,5 @@ for step in "${STEPS[@]}"; do
esac
save_config
done
ok "Config saved to .aurtomator.conf"
ok "Config saved to .aurtomator.conf in $AURTOMATOR_DATA_DIR"
exit "$EXIT_STATUS"
8 changes: 4 additions & 4 deletions scripts/update-readme.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ set -euo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
require_cmd yq

readonly README="${AURTOMATOR_DIR}/README.md"
readonly STATUS_DIR="${AURTOMATOR_DIR}/.status"
readonly README="${AURTOMATOR_DATA_DIR}/README.md"
readonly STATUS_DIR="${AURTOMATOR_DATA_DIR}/.status"

if [[ ! -f "$README" ]]; then
log_err "README.md not found"
Expand Down Expand Up @@ -67,7 +67,7 @@ fi
# Only a GitHub origin names the repo, so the URL of another remote, or a
# local path, never reaches the README
repo_url=""
origin_url=$(git -C "$AURTOMATOR_DIR" remote get-url origin 2>/dev/null || true)
origin_url=$(git -C "$AURTOMATOR_DATA_DIR" remote get-url origin 2>/dev/null || true)
if [[ "$origin_url" =~ [/@]github\.com[:/]([A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+) ]]; then
repo_url="${BASH_REMATCH[1]%.git}"
fi
Expand Down Expand Up @@ -136,7 +136,7 @@ table_header=$'<table>\n<tr><th>Package</th><th>Version</th><th>Strategy</th><th
pkg_count=0
pkg_ok=0
pkg_fail=0
for pkg_file in "${AURTOMATOR_DIR}"/packages/*.yml; do
for pkg_file in "${AURTOMATOR_DATA_DIR}"/packages/*.yml; do
[[ -f "$pkg_file" ]] || continue

name=$(pkg_get "$pkg_file" .name)
Expand Down
2 changes: 1 addition & 1 deletion scripts/validate-pkg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ validate_pkg() {
if [[ "${1:-}" == "--all" ]]; then
total=0
failed=0
for pkg_file in "${AURTOMATOR_DIR}"/packages/*.yml; do
for pkg_file in "${AURTOMATOR_DATA_DIR}"/packages/*.yml; do
[[ -f "$pkg_file" ]] || continue
((total++)) || true
if ! validate_pkg "$pkg_file"; then
Expand Down
4 changes: 3 additions & 1 deletion tests/helpers/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ setup_test_env() {
chmod +x "$MOCK_DIR/curl"
export PATH="$MOCK_DIR:$PATH"

# Override AURTOMATOR_DIR so all scripts use our temp workspace
# Override AURTOMATOR_DIR and AURTOMATOR_DATA_DIR so all scripts use our
# temp workspace
export AURTOMATOR_DIR="$TEST_TMPDIR"
export AURTOMATOR_DATA_DIR="$TEST_TMPDIR"

# No pause before an AUR clone, between attempts or before a second check
export AURTOMATOR_CLONE_DELAY=0 AURTOMATOR_RETRY_DELAY=0 AURTOMATOR_RECHECK_DELAY=0
Expand Down
9 changes: 9 additions & 0 deletions tests/publish.bats
Original file line number Diff line number Diff line change
Expand Up @@ -1983,6 +1983,15 @@ current: '1.0.0'"
[ "$(cat "$TEST_TMPDIR/verify-pkg.sh.args")" = "pkg $TEST_TMPDIR/out/prepared/pkg" ]
}

@test "check-all --verify: verifies the packages of AURTOMATOR_DATA_DIR" {
mkdir -p "$BATS_TEST_TMPDIR/data/packages" "$TEST_TMPDIR/out/prepared/pkg"
printf '%s\n' 'name: pkg' 'strategy: github-release' 'upstream:' ' project: owner/repo' "current: '1.0.0'" >"$BATS_TEST_TMPDIR/data/packages/pkg.yml"
stub_script verify-pkg.sh 0
AURTOMATOR_DATA_DIR="$BATS_TEST_TMPDIR/data" run "$TEST_TMPDIR/scripts/check-all.sh" --verify "$TEST_TMPDIR/out"
[ "$status" -eq 0 ]
[ "$(cat "$TEST_TMPDIR/verify-pkg.sh.args")" = "pkg $TEST_TMPDIR/out/prepared/pkg" ]
}

# === alert_issue_body ===

@test "alert_issue_body: lists every note of a held update" {
Expand Down
85 changes: 83 additions & 2 deletions tests/scripts.bats
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,43 @@ teardown() {
[[ "$output" == *"Package not found: "*"/packages/nonexistent.yml"* ]]
}

# setup_test_env exports AURTOMATOR_DATA_DIR, so env -u removes it
@test "lib.sh: AURTOMATOR_DATA_DIR defaults to the working directory" {
mkdir -p "$BATS_TEST_TMPDIR/data/packages"
touch "$BATS_TEST_TMPDIR/data/packages/foo.yml"

run env -u AURTOMATOR_DATA_DIR bash -c 'cd "$1" && source "$0/scripts/lib.sh" && pkg_file foo' "$TEST_TMPDIR" "$BATS_TEST_TMPDIR/data"
[ "$status" -eq 0 ]
[ "$output" = "$BATS_TEST_TMPDIR/data/packages/foo.yml" ]
}

@test "lib.sh: pkg_file and load_config read AURTOMATOR_DATA_DIR" {
mkdir -p "$BATS_TEST_TMPDIR/data/packages"
touch "$BATS_TEST_TMPDIR/data/packages/foo.yml"
echo "GIT_AUTHOR_NAME='x'" >"$BATS_TEST_TMPDIR/data/.aurtomator.conf"

AURTOMATOR_DATA_DIR="$BATS_TEST_TMPDIR/data" run bash -c 'source "$0/scripts/lib.sh" && load_config && pkg_file foo && echo "$GIT_AUTHOR_NAME"' "$TEST_TMPDIR"
[ "$status" -eq 0 ]
[ "${lines[0]}" = "$BATS_TEST_TMPDIR/data/packages/foo.yml" ]
[ "${lines[1]}" = x ]
}

@test "lib.sh: a wrong AURTOMATOR_DATA_DIR stops the script" {
AURTOMATOR_DATA_DIR="$BATS_TEST_TMPDIR/none" run bash -c 'source "$0/scripts/lib.sh"; echo reached' "$TEST_TMPDIR"
[ "$status" -eq 1 ]
[ "$output" = "AURTOMATOR_DATA_DIR is not a directory: $BATS_TEST_TMPDIR/none" ]
}

# Without -- cd takes -P as its option and goes to $HOME
@test "lib.sh: AURTOMATOR_DATA_DIR may start with a dash" {
mkdir -p "$BATS_TEST_TMPDIR/-P/packages"
touch "$BATS_TEST_TMPDIR/-P/packages/foo.yml"

run env AURTOMATOR_DATA_DIR=-P bash -c 'cd "$1" && source "$0/scripts/lib.sh" && pkg_file foo' "$TEST_TMPDIR" "$BATS_TEST_TMPDIR"
[ "$status" -eq 0 ]
[ "$output" = "$BATS_TEST_TMPDIR/-P/packages/foo.yml" ]
}

@test "lib.sh: pkg_get reads YAML field" {
create_test_package "mypkg" "github-release" "upstream:
type: github
Expand Down Expand Up @@ -1535,6 +1572,25 @@ EOF
[[ "$output" == *"Checked: 0"* ]]
}

# A skipped downgrade is logged with the name of its package
@test "check-all: reads the packages of AURTOMATOR_DATA_DIR and runs the strategies of the checkout" {
mkdir -p "$BATS_TEST_TMPDIR/data/packages"
cat >"$BATS_TEST_TMPDIR/data/packages/foo.yml" <<EOF
name: foo
strategy: github-release
upstream:
type: github
project: owner/repo
current: '3.0.0'
EOF

AURTOMATOR_DATA_DIR="$BATS_TEST_TMPDIR/data" run "$TEST_TMPDIR/scripts/check-all.sh"
[ "$status" -eq 0 ]
[[ "$output" == *"foo: DOWNGRADE detected"* ]]
[ "$(cat "$BATS_TEST_TMPDIR/data/.status/foo")" = "downgrade_skipped: 2.0.0" ]
[ ! -e "$TEST_TMPDIR/.status/foo" ]
}

# === project path with a space ===

# Helper: a project at "$TEST_TMPDIR/my project" with the scripts and
Expand All @@ -1550,7 +1606,7 @@ make_spaced_project() {

@test "check-all: finds the packages of a project whose path has a space" {
make_spaced_project
run "$SPACED/scripts/check-all.sh"
AURTOMATOR_DATA_DIR="$SPACED" run "$SPACED/scripts/check-all.sh"
[ "$status" -eq 0 ]
[[ "$output" == *"Checked: 1, Updated: 0, Errors: 0"* ]]
[ "$(cat "$SPACED/.status/pkg")" = "up_to_date" ]
Expand All @@ -1560,7 +1616,7 @@ make_spaced_project() {
make_spaced_project
printf '%s\n' '<!-- PACKAGES:START -->' '<!-- PACKAGES:END -->' >"$SPACED/README.md"
git -C "$SPACED" init -q
run "$SPACED/scripts/update-readme.sh"
AURTOMATOR_DATA_DIR="$SPACED" run "$SPACED/scripts/update-readme.sh"
[ "$status" -eq 0 ]
grep -qF '>pkg</a>' "$SPACED/README.md"
}
Expand Down Expand Up @@ -1644,6 +1700,31 @@ EOF
grep -q "failed" "$TEST_TMPDIR/README.md"
}

@test "update-readme: writes the README of AURTOMATOR_DATA_DIR from its packages and origin" {
local data="$BATS_TEST_TMPDIR/data"
mkdir -p "$data/packages" "$data/.status"
git -C "$data" init -q
git -C "$data" remote add origin "https://github.com/owner/data.git"
cat >"$data/packages/foo.yml" <<EOF
name: foo
strategy: github-release
upstream:
project: owner/repo
current: '1.0.0'
EOF
# Without this file the package reads as tracking
echo "new_version: 3.0.0" >"$data/.status/foo"
printf '%s\n' '# test' '<!-- BADGES:START -->' '<!-- BADGES:END -->' \
'<!-- PACKAGES:START -->' '<!-- PACKAGES:END -->' >"$data/README.md"

AURTOMATOR_DATA_DIR="$data" run "$TEST_TMPDIR/scripts/update-readme.sh"
[ "$status" -eq 0 ]
[[ "$output" == *"Badges updated (repo: owner/data)"* ]]
grep -qF 'https://github.com/owner/data/actions/workflows/ci.yml/badge.svg' "$data/README.md"
grep -q '>foo</a></td><td>1.0.0</td><td nowrap>github-release</td><td nowrap>-</td><td nowrap>.* 3.0.0 available</td></tr>' "$data/README.md"
[ ! -e "$TEST_TMPDIR/README.md" ]
}

# === lib.sh: warn_maintainer_line ===

@test "lib.sh: warn_maintainer_line warns when missing" {
Expand Down
Loading
Loading