diff --git a/README.md b/README.md index cdcade5..8f7270c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Automated AUR package updates from a single GitHub repo. - +
PackageVersionStrategyUpdatedStatus
No packages configured————
No packages configured----
aurtomator 0.7.0 diff --git a/docs/WORKFLOW.md b/docs/WORKFLOW.md index 557b5fc..5f35f4b 100644 --- a/docs/WORKFLOW.md +++ b/docs/WORKFLOW.md @@ -302,7 +302,7 @@ upstream: date_format: '%Y%m%d' ``` -`validate-pkg.sh` refuses `date_format` with another `version_source` and a format whose output is not a valid version, such as `%Y-%m-%d`. It refuses `nightly_tag_regex` next to `nightly_tag` or `channel`, and one that bash cannot compile. It refuses `tag_version_regex` with a `version_source` other than `tag`. It refuses a `version_source` other than `tag`, `release_body`, `tag_date` or `published_date`, `release_body` without `version_pattern`, a `version_pattern` that `grep -P` cannot compile, and `version_pattern` with another `version_source`. It refuses `tag_date` with the fixed tag of pattern A: such a tag has no dash and so no `YYYY-MM-DD` date. It refuses `nightly_tag` next to `channel`: `nightly_tag: latest` leaves `channel` unread, and `channel` leaves any other `nightly_tag` unread. +`validate-pkg.sh` refuses `date_format` with another `version_source` and a format whose output is not a valid version, such as `%Y-%m-%d`. It refuses `nightly_tag_regex` next to `nightly_tag` or `channel`, and one that bash cannot compile. It refuses `tag_version_regex` and `tag_version_replace` with a `version_source` other than `tag`. It refuses a `version_source` other than `tag`, `release_body`, `tag_date` or `published_date`, `release_body` without `version_pattern`, a `version_pattern` that `grep -P` cannot compile, and `version_pattern` with another `version_source`. It refuses `tag_date` with the fixed tag of pattern A: such a tag has no dash and so no `YYYY-MM-DD` date. It refuses `nightly_tag` next to `channel`: `nightly_tag: latest` leaves `channel` unread, and `channel` leaves any other `nightly_tag` unread. **Authentication:** same as `github-release`. @@ -610,7 +610,7 @@ strategy: repology | `upstream.archpkg` | no | Package name in the official repos. Defaults to the package `name`. | | `upstream.testing` | no | `true` also reads `core-testing`, `extra-testing` and `multilib-testing`. Default `false`. | -**Version:** reads the entries of `core`, `extra` and `multilib` and takes the newest by `vercmp`, the epoch included. It prints its `pkgver`, the version without `epoch` and `pkgrel`: ffmpeg `2:9.0.2-2` gives `9.0.2`. A package without an entry in these repositories fails with `Package not found in core, extra, multilib: `. A rebuild in the official repos raises only `pkgrel`, so it gives no new version, and an update of this strategy never raises `pkgrel` alone, see [SUPPORTED-PACKAGES.md](SUPPORTED-PACKAGES.md#packages-needing-a-pkgrel-bump). +**Version:** reads the entries of `core`, `extra` and `multilib` and takes the newest by `vercmp`, the epoch included. It prints its `pkgver`, the version without `epoch` and `pkgrel`: ffmpeg `2:9.0.2-2` gives `9.0.2`. When the official package raises its epoch, as `1:2.0` to `2:1.0`, the strategy gives `1.0` after `2.0`, and the check skips it as a downgrade, see [4.3](#43-downgrade-behavior). aurtomator does not write an `epoch`: the maintainer raises it in the AUR package, publishes `1.0` by hand and sets `current` to it. A package without an entry in these repositories fails with `Package not found in core, extra, multilib: `. A rebuild in the official repos raises only `pkgrel`, so it gives no new version, and an update of this strategy never raises `pkgrel` alone, see [SUPPORTED-PACKAGES.md](SUPPORTED-PACKAGES.md#packages-needing-a-pkgrel-bump). With `testing: true` the strategy also reads `core-testing`, `extra-testing` and `multilib-testing`. It takes the build in testing while that build is newer than the stable one, and the stable build otherwise. A build that moves from testing to the stable repository keeps its version and gives no new update. `gnome-unstable` and `kde-unstable` stay out. `validate-pkg.sh` refuses a `testing` that is not `true` or `false`, and `testing` with another strategy. @@ -868,7 +868,7 @@ A PKGBUILD is a bash script, and every step that reads it executes it: the audit 2. Clone `https://aur.archlinux.org/.git` anonymously with `--no-checkout`. When `HEAD` is not `base`, the AUR repo moved after the update was prepared: exit code 3. The entries at the top of `HEAD` are written to a separate directory with `git ls-tree` and `git cat-file`, so git applies none of the links, attributes or filters of the repo: a regular file with its content, a symlink as a link to nowhere, anything else as an empty directory. The steps below read the AUR copy there. 3. `PKGBUILD` and `.SRCINFO` in the AUR copy must be regular files. The prepared files must hold no NUL byte and pass steps 4 and 5 of publish below, with the prepared `pkgver` as `` and, for a package with `upstream.asset_var`, the value of its line in the prepared `PKGBUILD` as the asset value. From here on, every source URL in the prepared `.SRCINFO` follows from the AUR copy. 4. Each checksum array of the prepared `PKGBUILD` must hold the same values as the same key in the prepared `.SRCINFO`. -5. Every checksum other than `SKIP` must match its source, computed as makepkg does with `sum`. The file is the one makepkg uses. A file in the AUR repo with the name of the source comes first and must be a regular file. Otherwise a remote source is downloaded with curl, retried as makepkg does and limited to `http`, `https` and `ftp`, redirects included. A git source at `#tag=` or `#commit=` is cloned as a mirror over `https` or `http`, and its checksum is that of `git archive --format tar` of the tag or commit, with `export-subst` and `export-ignore` turned off, as makepkg computes it. A checksum for any other source, another VCS for example, cannot be checked and stops the verify. +5. Every checksum other than `SKIP` must match its source, computed as makepkg does with `sum`. The file is the one makepkg uses. A file in the AUR repo with the name of the source comes first and must be a regular file. Otherwise a remote source is downloaded with curl, retried and with the cookie engine on as makepkg does, and limited to `http`, `https` and `ftp`, redirects included. A git source at `#tag=` or `#commit=` is cloned as a mirror over `https` or `http`, and its checksum is that of `git archive --format tar` of the tag or commit, with `export-subst` and `export-ignore` turned off, as makepkg computes it. A checksum for any other source, another VCS for example, cannot be checked and stops the verify. 6. Any mismatch stops the verify with exit code 1. Otherwise the exit code is 0. **Publish**, `publish-pkg.sh /`, never sources the PKGBUILD and never runs `makepkg`. It treats the prepared files as untrusted: @@ -909,7 +909,7 @@ alerts: | `when` | one of `when`, `from`, `match` | `major`: the first number of the new version is greater than the first number of `current`, as in `28+25 → 29+1` | | `from` | one of `when`, `from`, `match` | A version: the new version is at or above it, and `current` is below it | | `match` | one of `when`, `from`, `match` | An ERE: the new version matches it, and `current` does not | -| `note` | yes | One line for the maintainer | +| `note` | yes | One line of text for the maintainer. A number, a boolean or a date goes in quotes, as in `note: '2024'` | | `hold` | no | `true` pauses the update. Default `false` | A rule fires when the new version meets its condition and `current` does not, so it fires once at each crossing. A `from` rule can stay in the file after the release it names, and a `when: major` rule fires again at the next major. The versions are in `pkgver` form, as `current` holds them, after `pkgver_dash` and `pkgver_format`. `vercmp` compares a version with `from` and the first numbers for `when: major`, so `9 → 10` is a new major. A package without `current` fires no rule. @@ -925,7 +925,7 @@ A skipped downgrade or version jump comes first, see [4.3](#43-downgrade-behavio Every rule that fires writes its note to `.status/_alerts`, and the run opens an issue from it, see [5.6](#56-issues). A held update gets the issue `✋ : update held` with the notes of every rule that fired, because after the hand publish a rule without `hold` no longer fires. The run closes it once the version is in the AUR. A published update gets the issue `🔔 : notice` with its notes, and the maintainer closes it once the edit is done. -`validate-pkg.sh` refuses an entry with any other key, without exactly one of `when`, `from` and `match`, with `when` other than `major`, with a `from` that is not a version, a `match` that bash does not accept as an ERE, a `note` that is not one line, or a `hold` that is not a boolean. It refuses `when: major` together with `pkgver_format`, because the fixed text of a format such as `4.%s` holds the first number of every version. `check-all.sh` reads the rules on every run. A rule it cannot evaluate, or a `note` that is not one line, fails the check of the package and never lets a held update through. +`validate-pkg.sh` refuses an entry with any other key, without exactly one of `when`, `from` and `match`, with `when` other than `major`, with a `from` that is not a version, a `match` that bash does not accept as an ERE, a `note` that is not one line of text, or a `hold` that is not a boolean. It refuses `when: major` together with `pkgver_format`, because the fixed text of a format such as `4.%s` holds the first number of every version. `check-all.sh` reads the rules on every run. A rule it cannot evaluate, or a `note` that is not one line of text, fails the check of the package and never lets a held update through. ### 4.6 Values from release asset names @@ -1186,7 +1186,7 @@ GitHub starts a `workflow_run` workflow only from its file on the default branch `update-readme.sh` writes the version under the package table, and with `newer:` a link to the release: ```text -aurtomator 0.6.0 · [0.7.0 available](https://github.com/staticwire/aurtomator/releases/tag/v0.7.0) +aurtomator 0.6.0 ([0.7.0 available](https://github.com/staticwire/aurtomator/releases/tag/v0.7.0)) ``` The comment marks the line for the release PR of aurtomator, which writes the new version there in the README of the upstream repository. Its check run then finds the README as `update-readme.sh` writes it, and has nothing to commit to a `main` that only takes pull requests. A run that could not read the release writes the line without the link. diff --git a/scripts/check-asset.sh b/scripts/check-asset.sh index 5cf0d05..904abb9 100755 --- a/scripts/check-asset.sh +++ b/scripts/check-asset.sh @@ -91,7 +91,7 @@ if ((${#found[@]} == 0)); then exit 1 fi if ((${#found[@]} > 1)); then - log_err "Tags ${found[*]} of ${project} all give version ${PKGVER}" + log_err "Tags ${found[*]} of ${project} all give version ${PKGVER}; set upstream.tag_version_regex to match one of them" exit 1 fi tag="${found[0]}" diff --git a/scripts/lib/alerts.sh b/scripts/lib/alerts.sh index a7505a5..84ecf9f 100644 --- a/scripts/lib/alerts.sh +++ b/scripts/lib/alerts.sh @@ -40,6 +40,15 @@ alert_note() { printf '%s\n' "$note" } +# Prints the error for a note that alert_note refuses. YAML reads a bare +# number, boolean or date as another type than text. +# Args: $1=package file, $2=index of the alert +alert_note_error() { + local value + value=$(pkg_get "$1" ".alerts[$2].note | select(tag == \"!!int\" or tag == \"!!float\" or tag == \"!!bool\" or tag == \"!!timestamp\")") + printf 'note must be one line of text%s\n' "${value:+: put $value in quotes}" +} + # The alerts of a package that fire on the step from current to the new # version, one per line in file order: hold or notice, a tab and the note. # Fails on a rule it cannot evaluate and on a note that is not one line @@ -60,7 +69,7 @@ fired_alerts() { return 1 fi if ! note=$(alert_note "$file" "$i"); then - log_err "alerts[$i].note must be one line of text" + log_err "alerts[$i].$(alert_note_error "$file" "$i")" return 1 fi rc=0 diff --git a/scripts/lib/common.sh b/scripts/lib/common.sh index 4cc8f6c..2ff19e4 100644 --- a/scripts/lib/common.sh +++ b/scripts/lib/common.sh @@ -459,7 +459,7 @@ latest_tag_version() { fi version=$(tag_versions "$regex" "$replace" <<<"$tags" | newest_version) if [[ -z "$version" ]]; then - echo "No matching tags found" >&2 + echo "No tag gives a version with upstream.tag_version_regex '$regex', tags read: $(grep -c . <<<"$1")" >&2 return 1 fi echo "$version" diff --git a/scripts/lib/sums.sh b/scripts/lib/sums.sh index 11fc65f..050d788 100644 --- a/scripts/lib/sums.sh +++ b/scripts/lib/sums.sh @@ -37,9 +37,11 @@ _source_file() { return 1 else file="${3}/$(printf '%s' "$url" | sha256sum | cut -d' ' -f1)" - # Retried as makepkg does. Redirects may only lead to the protocols above. + # Retried and with the cookie engine on, as makepkg does, so a cookie set + # on a redirect goes with the next request. Redirects may only lead to + # the protocols above. if [[ ! -f "$file" ]] && - ! curl -qgfsSL --retry 3 --retry-delay 3 --proto '=http,https,ftp' \ + ! curl -qgfsSL -b '' --retry 3 --retry-delay 3 --proto '=http,https,ftp' \ --proto-redir '=http,https,ftp' -o "$file" "$url"; then rm -f "$file" log_err "Could not download $url" diff --git a/scripts/setup.sh b/scripts/setup.sh index 78b261d..91dae44 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -165,8 +165,8 @@ setup_ssh() { if [[ -z "$AUR_SSH_KEY" ]]; then AUR_SSH_KEY=$(ask "Path to SSH private key for AUR" "$HOME/.ssh/aur_ed25519") fi - # Expand ~ to home dir - AUR_SSH_KEY="${AUR_SSH_KEY/#\~/$HOME}" + # Expand ~/ to the home dir. ~user/ stays as it is. + AUR_SSH_KEY="${AUR_SSH_KEY/#\~\//$HOME/}" check_ssh_key || return 1 ok "SSH key: $AUR_SSH_KEY" diff --git a/scripts/update-readme.sh b/scripts/update-readme.sh index 12e36d1..3cb5300 100755 --- a/scripts/update-readme.sh +++ b/scripts/update-readme.sh @@ -64,8 +64,13 @@ if grep -qxF -- "$BADGES_START" "$README"; then has_badges=true fi -# Detect repo from git origin -repo_url=$(git -C "$AURTOMATOR_DIR" remote get-url origin 2>/dev/null | sed 's|.*github.com[:/]||; s|\.git$||' || true) +# 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) +if [[ "$origin_url" =~ [/@]github\.com[:/]([A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+) ]]; then + repo_url="${BASH_REMATCH[1]%.git}" +fi # ============================================================================= # BADGES SECTION @@ -135,9 +140,9 @@ for pkg_file in "${AURTOMATOR_DIR}"/packages/*.yml; do [[ -f "$pkg_file" ]] || continue name=$(pkg_get "$pkg_file" .name) - current=$(pkg_get "$pkg_file" '.current // "—"') + current=$(pkg_get "$pkg_file" '.current // "-"') strategy=$(pkg_get "$pkg_file" .strategy) - last_updated=$(pkg_get "$pkg_file" '.last_updated // "—"') + last_updated=$(pkg_get "$pkg_file" '.last_updated // "-"') # Determine status from .status/ dir or YAML status_file="${STATUS_DIR}/${name}" @@ -197,9 +202,9 @@ for pkg_file in "${AURTOMATOR_DIR}"/packages/*.yml; do ((pkg_ok++)) || true ;; esac - elif [[ "$current" == "—" || "$current" == "null" ]]; then + elif [[ "$current" == "-" || "$current" == "null" ]]; then status="✨ new" - current="—" + current="-" ((pkg_ok++)) || true else status="✅ tracking" @@ -237,7 +242,7 @@ table+=" ${table_header}" if [[ "$pkg_count" -eq 0 ]]; then - table+=$(table_row "No packages configured" — — — —) + table+=$(table_row "No packages configured" - - - -) else table+="$table_rows" fi @@ -253,7 +258,7 @@ if [[ -n "$version" ]]; then [[ ! -f "${STATUS_DIR}/_upstream" ]] || upstream=$(<"${STATUS_DIR}/_upstream") table+=$'\n\n'"aurtomator ${version}" if [[ "$upstream" =~ ^newer:\ ([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then - table+=" · [${BASH_REMATCH[1]} available](https://github.com/${AURTOMATOR_UPSTREAM}/releases/tag/v${BASH_REMATCH[1]})" + table+=" ([${BASH_REMATCH[1]} available](https://github.com/${AURTOMATOR_UPSTREAM}/releases/tag/v${BASH_REMATCH[1]}))" fi table+=" " fi diff --git a/scripts/validate-pkg.sh b/scripts/validate-pkg.sh index 0b0979f..fd25ea6 100755 --- a/scripts/validate-pkg.sh +++ b/scripts/validate-pkg.sh @@ -45,6 +45,18 @@ readonly UPSTREAM_KEYS=( "kde-tarball: project path" ) +# Succeeds when $1 is one of the words of $2. A substring match would pass +# a key such as "name strategy". +# Args: $1=word, $2=words separated by spaces +in_words() { + local words word + read -ra words <<<"$2" + for word in "${words[@]}"; do + [[ "$word" != "$1" ]] || return 0 + done + return 1 +} + # Prints the upstream keys of a strategy, or fails when UPSTREAM_KEYS has # no line for it # Args: $1=strategy @@ -66,7 +78,7 @@ upstream_keys() { key_strategies() { local line names=() list i for line in "${UPSTREAM_KEYS[@]}"; do - [[ " ${line#*: } " != *" $1 "* ]] || names+=("${line%%:*}") + ! in_words "$1" "${line#*: }" || names+=("${line%%:*}") done case ${#names[@]} in 0) return 1 ;; @@ -126,7 +138,7 @@ validate_alert() { fi if ! alert_note "$file" "$i" >/dev/null; then - log_err "$rule.note must be one line of text" + log_err "$rule.$(alert_note_error "$file" "$i")" errors=1 fi @@ -191,7 +203,7 @@ validate_pkg() { local keys key unknown=() list strategy_keys where mapfile -t keys < <(pkg_get "$file" 'keys | .[]') for key in "${keys[@]}"; do - [[ " $PACKAGE_KEYS " == *" $key "* ]] || unknown+=("$key") + in_words "$key" "$PACKAGE_KEYS" || unknown+=("$key") done if ((${#unknown[@]} > 0)); then printf -v list '%s, ' "${unknown[@]}" @@ -210,7 +222,7 @@ validate_pkg() { ((errors++)) elif ((${#keys[@]} > 0)); then for key in "${keys[@]}"; do - [[ " $strategy_keys " != *" $key "* ]] || continue + ! in_words "$key" "$strategy_keys" || continue if where=$(key_strategies "$key"); then log_err "$file: upstream.$key applies to $where only" else @@ -353,7 +365,10 @@ validate_pkg() { local tag_version_replace tag_version_replace=$(pkg_get "$file" '.upstream.tag_version_replace // ""') if [[ -n "$tag_version_replace" ]]; then - if [[ -z "$tag_version_regex" ]]; then + if [[ "$strategy" == "github-nightly" && $(pkg_get "$file" '.upstream.version_source // "tag"') != "tag" ]]; then + log_err "$file: upstream.tag_version_replace applies to version_source tag only" + ((errors++)) + elif [[ -z "$tag_version_regex" ]]; then log_err "$file: upstream.tag_version_replace needs upstream.tag_version_regex" ((errors++)) elif [[ ! "$tag_version_replace" =~ ^([A-Za-z0-9._+]|\\[1-9])+$ ]]; then @@ -451,7 +466,11 @@ validate_pkg() { fi # nightly_tag: latest wins over channel, and channel over any other tag if [[ $(pkg_get "$file" '.upstream | (has("nightly_tag") and has("channel"))') == true ]]; then - log_err "$file: upstream.channel takes the place of nightly_tag" + if [[ "$nightly_tag" == latest ]]; then + log_err "$file: upstream.nightly_tag latest takes the place of channel" + else + log_err "$file: upstream.channel takes the place of nightly_tag" + fi ((errors++)) fi fi diff --git a/tests/publish.bats b/tests/publish.bats index 283f7c8..f7afbee 100644 --- a/tests/publish.bats +++ b/tests/publish.bats @@ -875,6 +875,15 @@ commit_aur_state() { grep -q -- '--proto =http,https,ftp --proto-redir =http,https,ftp .* https://example.com/demo-1.1.0.tar.gz$' "$TEST_TMPDIR/curl.args" } +# makepkg runs curl with -b "", so a cookie set on a redirect goes with the +# next request +@test "verify-pkg: downloads with the cookie engine on, as makepkg does" { + setup_verify + run "$TEST_TMPDIR/scripts/verify-pkg.sh" demo "$PREPARED" + [ "$status" -eq 0 ] + grep -qF -- ' -b --retry 3 ' "$TEST_TMPDIR/curl.args" +} + @test "verify-pkg: refuses a checksum that does not match the download" { setup_verify write_pkgbuild "$PREPARED/PKGBUILD" 1.1.0 1 "sha256sums=('$H3' '$SUM_LOCAL')" diff --git a/tests/scripts.bats b/tests/scripts.bats index 62daa28..d07b6a5 100644 --- a/tests/scripts.bats +++ b/tests/scripts.bats @@ -1201,6 +1201,15 @@ run_alert_fires() { done } +@test "lib.sh: fired_alerts asks for quotes around a note that YAML reads as a number" { + create_test_package "pkg" "github-release" "alerts: + - from: '0.4.0' + note: 2024" + run bash -c 'source "$0/scripts/lib.sh"; fired_alerts "$1" 0.3 29+1' "$TEST_TMPDIR" "$TEST_TMPDIR/packages/pkg.yml" + [ "$status" -eq 1 ] + [[ "$output" == *"alerts[0].note must be one line of text: put 2024 in quotes"* ]] +} + # === version of aurtomator === @test "lib.sh: aurtomator_version prints VERSION, or nothing without it" { @@ -1305,7 +1314,7 @@ EOF git -C "$TEST_TMPDIR" init -q "$TEST_TMPDIR/scripts/update-readme.sh" 2>/dev/null - grep -qxF 'aurtomator 0.6.0 · [0.7.0 available](https://github.com/staticwire/aurtomator/releases/tag/v0.7.0) ' "$TEST_TMPDIR/README.md" + grep -qxF 'aurtomator 0.6.0 ([0.7.0 available](https://github.com/staticwire/aurtomator/releases/tag/v0.7.0)) ' "$TEST_TMPDIR/README.md" } @test "update-readme: links no release for aurtomator at its release or for another _upstream" { @@ -2088,7 +2097,7 @@ EOF "$TEST_TMPDIR/scripts/update-readme.sh" 2>/dev/null [ "$(sed -n '//,$p' "$TEST_TMPDIR/README.md")" = '
- +
PackageVersionStrategyUpdatedStatus
No packages configured————
No packages configured----
' ] } @@ -2271,6 +2280,25 @@ current: '1.0.0'" [[ "$badges" != *"Lint & Test"* && "$badges" != *"codecov"* ]] } +@test "update-readme: an origin outside GitHub, or a local path, gives only the static badges" { + create_test_package "pkg-a" "github-release" "upstream: + project: owner/repo +current: '1.0.0'" + git -C "$TEST_TMPDIR" init -q + git -C "$TEST_TMPDIR" remote add origin "https://gitlab.com/someone/fork.git" + local origin + for origin in "https://gitlab.com/someone/fork.git" "https://notgithub.com/someone/fork.git" "$TEST_TMPDIR/clone"; do + git -C "$TEST_TMPDIR" remote set-url origin "$origin" + readme_with_badges + run "$TEST_TMPDIR/scripts/update-readme.sh" + echo "$origin: $output" + [ "$status" -eq 0 ] + [[ "$output" == *"Badges updated (repo: unknown)"* ]] + ! grep -qF -e 'someone/fork' -e "$TEST_TMPDIR" "$TEST_TMPDIR/README.md" + [[ "$(sed -n '3p' "$TEST_TMPDIR/README.md")" != *"Lint & Test"* ]] + done +} + @test "update-readme: an unknown status reads as tracking" { create_test_package "pkg-a" "github-release" "upstream: project: owner/repo @@ -2281,7 +2309,7 @@ current: '1.0.0'" run "$TEST_TMPDIR/scripts/update-readme.sh" [ "$status" -eq 0 ] - grep -qF '1.0.0github-release—✅ tracking' "$TEST_TMPDIR/README.md" + grep -qF '1.0.0github-release-✅ tracking' "$TEST_TMPDIR/README.md" grep -qF 'packages-1%2F1-brightgreen' "$TEST_TMPDIR/README.md" } @@ -2293,7 +2321,7 @@ current: '1.0.0'" run "$TEST_TMPDIR/scripts/update-readme.sh" [ "$status" -eq 0 ] - grep -qF 'pkg-new—github-release—✨ new' "$TEST_TMPDIR/README.md" + grep -qF 'pkg-new-github-release-✨ new' "$TEST_TMPDIR/README.md" } # A package that has not been checked yet has failed nothing @@ -2343,7 +2371,7 @@ current: '1.0.0'" EOF git -C "$TEST_TMPDIR" init -q "$TEST_TMPDIR/scripts/update-readme.sh" 2>/dev/null - grep -qF 'github-release—' "$TEST_TMPDIR/README.md" + grep -qF 'github-release-' "$TEST_TMPDIR/README.md" } # === update-pkg.sh: argument validation === @@ -3601,7 +3629,7 @@ pkgver_dash: ''" asset_var: _twin" run "$TEST_TMPDIR/scripts/check-asset.sh" twin 1.0.0 [ "$status" -eq 1 ] - [[ "$output" == *"Tags v1.0.0 1.0.0 of asset-owner/twin-repo all give version 1.0.0"* ]] + [[ "$output" == *"Tags v1.0.0 1.0.0 of asset-owner/twin-repo all give version 1.0.0; set upstream.tag_version_regex to match one of them"* ]] } @test "check-asset: fails when the release cannot be read" { diff --git a/tests/setup.bats b/tests/setup.bats index d78a799..bb84843 100644 --- a/tests/setup.bats +++ b/tests/setup.bats @@ -352,6 +352,15 @@ EOF [[ "$output" == *"SSH key:"* ]] } +# The home directory of another user is not $HOME +@test "setup ssh: leaves a tilde with a user name as it is" { + HOME="$TEST_TMPDIR/fakehome" run "$TEST_TMPDIR/scripts/setup.sh" ssh \ + --ssh-key "~nobody/keys/aur.pem" \ + --non-interactive + [ "$status" -ne 0 ] + [[ "$output" == *"SSH key not found: ~nobody/keys/aur.pem"* ]] +} + @test "setup ssh: nonexistent key rejected" { run "$TEST_TMPDIR/scripts/setup.sh" ssh \ --ssh-key "/nonexistent/path/key.pem" \ diff --git a/tests/strategies.bats b/tests/strategies.bats index 315eb93..b56baf7 100644 --- a/tests/strategies.bats +++ b/tests/strategies.bats @@ -2126,7 +2126,7 @@ EOF # The mock returns v2.0.0, v1.9.0 and v1.0.0, and none matches ^release- run "$TEST_TMPDIR/strategies/github-tag.sh" "test-filter" [ "$status" -eq 1 ] - [[ "$output" == *"No matching tags found"* ]] + [[ "$output" == *"No tag gives a version with upstream.tag_version_regex '^release-(.+)\$', tags read: 3"* ]] } @test "gitlab-tag: tag_version_regex filters out all tags" { @@ -2137,7 +2137,7 @@ EOF run "$TEST_TMPDIR/strategies/gitlab-tag.sh" "test-filter" [ "$status" -eq 1 ] - [[ "$output" == *"No matching tags found"* ]] + [[ "$output" == *"No tag gives a version with upstream.tag_version_regex '^release-(.+)\$', tags read: 3"* ]] } @test "gitea-tag: tag_version_regex filters out all tags" { @@ -2148,7 +2148,7 @@ EOF run "$TEST_TMPDIR/strategies/gitea-tag.sh" "test-filter" [ "$status" -eq 1 ] - [[ "$output" == *"No matching tags found"* ]] + [[ "$output" == *"No tag gives a version with upstream.tag_version_regex '^release-(.+)\$', tags read: 2"* ]] } # A pin to one release line leaves out v2.0.0 and the v2.1.0 rc tags diff --git a/tests/validate-pkg.bats b/tests/validate-pkg.bats index 6cead8d..5805fa9 100644 --- a/tests/validate-pkg.bats +++ b/tests/validate-pkg.bats @@ -398,6 +398,17 @@ pkgver_dashes: _" [[ "$output" == *"mypkg.yml has an unknown key: allow_downgrades, pkgver_dashes"* ]] } +@test "validate: a key made of two known names rejected" { + create_test_package "mypkg" "github-release" "upstream: + project: owner/repo + \"project tag_version_regex\": x +\"name strategy\": x" + run "$TEST_TMPDIR/scripts/validate-pkg.sh" "mypkg" + [ "$status" -eq 1 ] + [[ "$output" == *"mypkg.yml has an unknown key: name strategy"* ]] + [[ "$output" == *"mypkg.yml: upstream.project tag_version_regex is not a field of any strategy"* ]] +} + # The keys come from the reads of the scripts, so a key that a script # starts to read cannot be refused @test "validate: every top-level key a script reads passes" { @@ -771,18 +782,21 @@ pkgver_dashes: _" } # nightly_tag: latest wins over channel, and channel over any other tag -@test "validate: nightly_tag next to channel rejected" { - local tag - for tag in latest nightly; do - create_test_package "mypkg" "github-nightly" "upstream: +@test "validate: nightly_tag next to channel rejected with the field that is read" { + create_test_package "mypkg" "github-nightly" "upstream: project: owner/repo - nightly_tag: $tag + nightly_tag: latest channel: Nightly" - run "$TEST_TMPDIR/scripts/validate-pkg.sh" "mypkg" - echo "$tag: $output" - [ "$status" -eq 1 ] - [[ "$output" == *"mypkg.yml: upstream.channel takes the place of nightly_tag"* ]] - done + run "$TEST_TMPDIR/scripts/validate-pkg.sh" "mypkg" + [ "$status" -eq 1 ] + [[ "$output" == *"mypkg.yml: upstream.nightly_tag latest takes the place of channel"* ]] + create_test_package "mypkg" "github-nightly" "upstream: + project: owner/repo + nightly_tag: nightly + channel: Nightly" + run "$TEST_TMPDIR/scripts/validate-pkg.sh" "mypkg" + [ "$status" -eq 1 ] + [[ "$output" == *"mypkg.yml: upstream.channel takes the place of nightly_tag"* ]] } @test "validate: pypi fails without upstream.registry" { @@ -1121,7 +1135,7 @@ alerts: local note for note in "" "note: ''" "note: | First line - Second line" "note: [a, b]" "note: {text: x}" "note: 42"; do + Second line" "note: [a, b]" "note: {text: x}"; do create_test_package "mypkg" "github-release" "upstream: project: owner/repo alerts: @@ -1130,6 +1144,21 @@ alerts: run "$TEST_TMPDIR/scripts/validate-pkg.sh" "mypkg" [ "$status" -ne 0 ] [[ "$output" == *"alerts[0].note must be one line of text"* ]] + [[ "$output" != *"in quotes"* ]] + done +} + +@test "validate: an alert note that YAML reads as a number, a boolean or a date asks for quotes" { + local value + for value in 2024 1.5 true 2024-10-30; do + create_test_package "mypkg" "github-release" "upstream: + project: owner/repo +alerts: + - when: major + note: $value" + run "$TEST_TMPDIR/scripts/validate-pkg.sh" "mypkg" + [ "$status" -ne 0 ] + [[ "$output" == *"alerts[0].note must be one line of text: put $value in quotes"* ]] done } @@ -1374,11 +1403,13 @@ pkgver_dash: _" create_test_package "mypkg" "github-release" "upstream: project: owner/repo version_source: release_body - tag_version_regex: '^v(.+)$'" + tag_version_regex: '^v(.+)$' + tag_version_replace: '\\1'" run "$TEST_TMPDIR/scripts/validate-pkg.sh" "mypkg" [ "$status" -eq 1 ] [[ "$output" == *"upstream.version_source applies to the github-nightly strategy only"* ]] [[ "$output" != *"tag_version_regex applies to version_source tag only"* ]] + [[ "$output" != *"tag_version_replace applies to version_source tag only"* ]] } @test "validate: tag_version_regex for github-nightly with another version_source rejected" { @@ -1395,6 +1426,23 @@ pkgver_dash: _" done } +# A tag_version_regex there is refused as well, so asking for one would +# send the author in a circle +@test "validate: tag_version_replace for github-nightly with another version_source rejected" { + local source + for source in release_body tag_date published_date; do + create_test_package "mypkg" "github-nightly" "upstream: + project: owner/repo + version_source: $source + version_pattern: 'v\\K\\S+' + tag_version_replace: '\\1'" + run "$TEST_TMPDIR/scripts/validate-pkg.sh" "mypkg" + [ "$status" -eq 1 ] + [[ "$output" == *"upstream.tag_version_replace applies to version_source tag only"* ]] + [[ "$output" != *"needs upstream.tag_version_regex"* ]] + done +} + # === tag_version_replace validation === @test "validate: tag_version_replace with the groups of the regex passes" {