From 3a59b83309c9635c52c0f23c83a08edcb402e565 Mon Sep 17 00:00:00 2001 From: noctuum <25441068+noctuum@users.noreply.github.com> Date: Wed, 21 Oct 2026 05:44:54 +0500 Subject: [PATCH] feat(scripts): push downgrades only when allowed Without allow_downgrade: true, a lower version gets downgrade_skipped. --- README.md | 2 +- docs/WORKFLOW.md | 32 ++++++++++++++-------- scripts/check-all.sh | 19 ++++++++++--- scripts/update-readme.sh | 4 +++ scripts/validate-pkg.sh | 9 +++++++ tests/publish.bats | 42 ++++++++++++++++++++++++++++- tests/scripts.bats | 58 ++++++++++++++++++++++++++++++++++++---- tests/validate-pkg.bats | 20 ++++++++++++++ tests/workflows.bats | 2 ++ 9 files changed, 166 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 9dbec3d..f1c8397 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ Patches in `source=()` trigger a warning and are not blocked. ## Downgrades -aurtomator follows upstream when it publishes a version older than the tracked one, for example after a tag is deleted and recreated. Upstream is the source of truth. A downgrade is logged with the literal keyword `DOWNGRADE` and shown in the package table with a `⬇️` icon. It counts as a successful run, so the badge stays green. Details are in [docs/WORKFLOW.md section 4.3](docs/WORKFLOW.md#43-downgrade-behavior). +aurtomator publishes a version older than the tracked one only when the package YAML sets `allow_downgrade: true`. Without it, the downgrade is skipped: the latest release of a GitHub project can be a maintenance release of an older line. A downgrade is logged with the literal keyword `DOWNGRADE` and shown in the package table with a `⬇️` icon. It counts as a successful run, so the badge stays green. Details are in [docs/WORKFLOW.md section 4.3](docs/WORKFLOW.md#43-downgrade-behavior). ## Resource usage diff --git a/docs/WORKFLOW.md b/docs/WORKFLOW.md index bb1346d..4c75dc7 100644 --- a/docs/WORKFLOW.md +++ b/docs/WORKFLOW.md @@ -76,6 +76,7 @@ Each package has a file at `packages/.yml`. The file name, the `name` fiel | `upstream` | depends | Strategy-specific settings. `archpkg`, `repology` and `kde-tarball` need none. | | `current` | no | Currently tracked version. Written after every push. | | `last_updated` | no | Date of the last push, `YYYY-MM-DD`. Written after every push. | +| `allow_downgrade` | no | `true` publishes an upstream version lower than `current`. Default `false`, see [4.3](#43-downgrade-behavior). | Example: @@ -572,19 +573,25 @@ check-all.sh [--update | --prepare | --verify | --publish ] [-- ### 4.3 Downgrade behavior -aurtomator follows upstream when it publishes a version older than the tracked one, and does **not** block it. Upstream is the source of truth: a packager that refuses a re-published older release only drifts out of sync. A downgrade is logged and shown, and it does not count as a failure. +An upstream version lower than `current` reaches the AUR only when the package YAML sets `allow_downgrade: true`. Without it, `check-all.sh` skips the version, writes `downgrade_skipped: ` and pushes nothing. A skipped downgrade opens no issue and does not count as a failure. `--prepare` and `--publish` apply the same rule, so a downgrade of a package without the flag is never prepared or published. + +The default guards against a lower version that upstream does not mean as a step back. `github-release` reads `/releases/latest`, and GitHub picks that release by the date of the commit it was made from, not by the date it was published. A maintenance release of an older line, made from a commit newer than the one of the current release, becomes the latest release. Without the flag, aurtomator would push it as a downgrade and push the newer version again at the next release. + +`allow_downgrade: true` fits a package whose upstream does mean it, for example one that rolls back a broken release and the AUR package should follow. #### When does this happen? +- Upstream publishes a maintenance release of an older line, and `/releases/latest` returns it. - Upstream deletes and recreates a release tag. In the gap, `/releases/latest` returns the previous release, so a cycle like `v1.2.1 → v1.2.0 → v1.2.1` can take only minutes. - Upstream rolls back a broken release and removes its tag. - Upstream marks an older release line as latest again, for example when a 2.x release is pulled and 1.x becomes the newest release. #### How to detect downgrades in logs -Every comparison that finds the current version newer than the latest one (`vercmp "$current" "$latest"` returns `1`) logs the literal token `DOWNGRADE`. In a CI run, `check-all.sh` logs: +Every comparison that finds the current version newer than the latest one (`vercmp "$current" "$latest"` returns `1`) logs the literal token `DOWNGRADE`. In a CI run, `check-all.sh` logs the first line for a package without `allow_downgrade: true` and the second for one with it: ```text +! myapp-bin: DOWNGRADE detected 1.2.1 → 1.2.0, skipped: allow_downgrade is not set ! myapp-bin: DOWNGRADE detected 1.2.1 → 1.2.0 (mirroring upstream) ``` @@ -598,19 +605,21 @@ Every comparison that finds the current version newer than the latest one (`verc #### Status values and README icons -`check-all.sh` writes two status tokens for downgrades to `.status/`: +`check-all.sh` writes three status tokens for downgrades to `.status/`: -| Token | Meaning | -|-------------------------------|---------------------------------------------------| -| `downgrade: ` | `--update` mode: the downgrade was pushed to the AUR | -| `available_downgrade: ` | Check-only mode: a downgrade is available and not applied | +| Token | Meaning | +|--------------------------------|----------------------------------------------------------------| +| `downgrade_skipped: ` | A downgrade was found for a package without `allow_downgrade: true`. Nothing is pushed | +| `available_downgrade: ` | A downgrade the package allows was found and is not pushed yet | +| `downgrade: ` | The downgrade was pushed to the AUR | `update-readme.sh` renders them as: -- `downgrade: 1.2.0` → `⬇️ downgraded to 1.2.0` +- `downgrade_skipped: 1.2.0` → `⬇️ 1.2.0 skipped (downgrade)` - `available_downgrade: 1.2.0` → `⬇️ 1.2.0 available (downgrade)` +- `downgrade: 1.2.0` → `⬇️ downgraded to 1.2.0` -Both count toward `pkg_ok`, so the packages badge stays `brightgreen`. Only `check_failed` and `update_failed` turn it red. +All three count toward `pkg_ok`, so the packages badge stays `brightgreen`. Only `check_failed` and `update_failed` turn it red. ### 4.4 Prepare and publish @@ -640,11 +649,11 @@ A PKGBUILD is a bash script, and every step that reads it executes it: the audit 5. Each `source` line of the prepared `.SRCINFO`, with or without an arch suffix, must be the line of the AUR copy with the old version replaced by ``. A source that is `SKIP` in every checksum array of its arch may also change the digits in the name it is saved under, the part before `::`, as `neovim-20261014.tar.gz` becomes `neovim-20261016.tar.gz` in a PKGBUILD that names a nightly download by `$(date -u +%Y%m%d)`. Its URL after `::` must still be the AUR URL with the version replaced. Verify never downloads a `SKIP` source, and makepkg takes the sources from the `PKGBUILD`. Any other line must either equal the line of the AUR copy or be that line with the version replaced in the same way, because a license, a dependency or a description can hold the old version without taking it from `pkgver`, as `GPL-2.0` does in a package at version `2.0`. The replacement also covers three forms a PKGBUILD often derives from `pkgver`: dots turned into underscores (`1_86_0`), the part before the first `+` (`0.13.0` of `0.13.0+dev+1853+g6edb38ca98`), and the version without its last component (`6.19` of `6.19.0`, as in `frameworks/${pkgver%.*}/` of KDE Frameworks). The last form counts only while it keeps a dot. Each part of a line is replaced at most once, so `5.1` inside an already replaced `5.10.0` stays. A line built from any other form of the version, a lone major version for example, stops the publish, and so does a line that has the version replaced in one place and kept in another. The package then needs a manual update. `pkgrel` and the checksums follow the rules of step 4. 6. Any other difference, and a NUL byte in either file, stops the publish with exit code 1. Otherwise the index of the clone takes the tree of `HEAD`, and the two prepared files enter it byte for byte through `git hash-object --no-filters` and `git update-index`, so the commit keeps every other file of the AUR repo. `git add` would pass them through the attributes of the AUR repo, and `working-tree-encoding=UTF-7` there turns `+AAo-` in a comment into a new line that the checks above never saw. Steps 10 to 13 of [4.2](#42-step-by-step) follow. When the prepared files equal the AUR copy, only `current` is written to the YAML and the exit code is 2. -`check-all.sh --prepare ` runs no strategy and needs no `GITHUB_TOKEN`. It takes the versions from the statuses that a check run, `check-all.sh` without a mode, wrote to `.status/` before it, and reads them before the first PKGBUILD runs. It prepares every package with `new_version` or `available_downgrade` into `/prepared/` and copies the statuses to `/status/`. A failed preparation becomes `update_failed`, and a package without a status from the check run becomes `check_failed`. The other statuses stay as the check run wrote them. +`check-all.sh --prepare ` runs no strategy and needs no `GITHUB_TOKEN`. It takes the versions from the statuses that a check run, `check-all.sh` without a mode, wrote to `.status/` before it, and reads them before the first PKGBUILD runs. It prepares every package with `new_version` or `available_downgrade` into `/prepared/` and copies the statuses to `/status/`. A downgrade of a package without `allow_downgrade: true` gets `downgrade_skipped` instead, see [4.3](#43-downgrade-behavior). A failed preparation becomes `update_failed`, and a package without a status from the check run becomes `check_failed`. The other statuses stay as the check run wrote them. `check-all.sh --verify ` runs `verify-pkg.sh` for every package in `packages/` that has a directory in `/prepared/`, and runs no strategy. An update that fails is removed from `/prepared/`, its status in `/status/` becomes `update_failed`, and `/status/_error_count` grows by one. Exit code 3 counts as a failure as well: the prepare run writes `base` for every package, so a moved AUR repo looks the same as a wrong `base`. The next run prepares the package again. -`check-all.sh --publish ` takes the statuses of the check run from `.status/`, as `--prepare` does, and writes `.status/` anew. `up_to_date` and `check_failed` stay as they are. A missing status, and one the check run does not write, become `check_failed`. For a package with `new_version` or `available_downgrade` and a directory in `/prepared/`, it publishes the version in that status and runs no strategy, so nothing contacts an upstream host while the AUR and GPG keys are in place. Exit code 3, an AUR repo that moved, leaves the status at `new_version` or `available_downgrade` without an error, and the next run prepares the package again. A package with `new_version` or `available_downgrade` and no prepared directory gets the `update_failed` status that the prepare or the verify run wrote for it to `/status/`, or `update_failed: prepare and verify handed over no update`. Nothing else is taken from `/status/`, and only a regular file without a NUL byte: the prepare run executes PKGBUILDs, and code from one of them can write the files of every package. `_error_count` is the number of `check_failed` and `update_failed` statuses. +`check-all.sh --publish ` takes the statuses of the check run from `.status/`, as `--prepare` does, and writes `.status/` anew. `up_to_date`, `check_failed` and `downgrade_skipped` stay as they are, and a downgrade of a package without `allow_downgrade: true` gets `downgrade_skipped` and is not published. A missing status, and one the check run does not write, become `check_failed`. For a package with `new_version` or `available_downgrade` and a directory in `/prepared/`, it publishes the version in that status and runs no strategy, so nothing contacts an upstream host while the AUR and GPG keys are in place. Exit code 3, an AUR repo that moved, leaves the status at `new_version` or `available_downgrade` without an error, and the next run prepares the package again. A package with `new_version` or `available_downgrade` and no prepared directory gets the `update_failed` status that the prepare or the verify run wrote for it to `/status/`, or `update_failed: prepare and verify handed over no update`. Nothing else is taken from `/status/`, and only a regular file without a NUL byte: the prepare run executes PKGBUILDs, and code from one of them can write the files of every package. `_error_count` is the number of `check_failed` and `update_failed` statuses. ## 5. CI Workflow: check-updates.yml @@ -733,6 +742,7 @@ Steps 9 and 10 run as root with `GH_TOKEN` set to the workflow token, `github.to | `.status/` | `new_version: 2.0.0` | Update found, not pushed yet | | `.status/` | `downgrade: 1.2.0` | Downgrade pushed to the AUR | | `.status/` | `available_downgrade: 1.2.0` | Downgrade found, not pushed yet | +| `.status/` | `downgrade_skipped: 1.2.0` | Downgrade found, not allowed by the YAML | | `.status/` | `check_failed: ` | The strategy failed | | `.status/` | `update_failed: ` | The update failed | | `.status/_error_count` | `0` | Total error count of the run | diff --git a/scripts/check-all.sh b/scripts/check-all.sh index d7ec6b1..6b88b4f 100755 --- a/scripts/check-all.sh +++ b/scripts/check-all.sh @@ -179,11 +179,12 @@ checked=0 errors=0 # The version the check run found for a package, printed the way -# check-update.sh prints it: nothing when up to date, an error on failure +# check-update.sh prints it: nothing when up to date, an error on failure. +# A skipped downgrade prints its version, and the check below skips it again. checked_version() { local status="${CHECKED[$1]:-}" case "$status" in - "new_version: "* | "available_downgrade: "*) + "new_version: "* | "available_downgrade: "* | "downgrade_skipped: "*) echo "${status#*: }" ;; up_to_date) ;; @@ -218,7 +219,7 @@ for pkg_file in $(printf '%s\n' "${AURTOMATOR_DIR}"/packages/*.yml | sort); do continue fi ;; - up_to_date | check_failed:*) + up_to_date | check_failed:* | "downgrade_skipped: "*) printf '%s\n' "$found" >"${STATUS_DIR}/${pkg_name}" continue ;; @@ -267,11 +268,21 @@ for pkg_file in $(printf '%s\n' "${AURTOMATOR_DIR}"/packages/*.yml | sort); do cmp=$(vercmp "$current" "$latest") if [[ "$cmp" -gt 0 ]]; then is_downgrade=true - log_warn "$pkg_name: DOWNGRADE detected $current → $latest (mirroring upstream)" fi fi + # A lower version reaches the AUR only for a package that allows it. The + # latest release of a GitHub project can be a maintenance release of an + # older line. + if [[ "$is_downgrade" == "true" ]] && + [[ "$(pkg_get "$pkg_file" '.allow_downgrade // false')" != "true" ]]; then + log_warn "$pkg_name: DOWNGRADE detected $current → $latest, skipped: allow_downgrade is not set" + echo "downgrade_skipped: ${latest}" >"${STATUS_DIR}/${pkg_name}" + continue + fi + if [[ "$is_downgrade" == "true" ]]; then + log_warn "$pkg_name: DOWNGRADE detected $current → $latest (mirroring upstream)" available="available_downgrade: ${latest}" pushed="downgrade: ${latest}" else diff --git a/scripts/update-readme.sh b/scripts/update-readme.sh index e6f98db..689353f 100755 --- a/scripts/update-readme.sh +++ b/scripts/update-readme.sh @@ -126,6 +126,10 @@ for pkg_file in $(printf '%s\n' "${AURTOMATOR_DIR}"/packages/*.yml | sort); do status="⬇️ ${run_status#available_downgrade: } available (downgrade)" ((pkg_ok++)) || true ;; + downgrade_skipped:*) + status="⬇️ ${run_status#downgrade_skipped: } skipped (downgrade)" + ((pkg_ok++)) || true + ;; check_failed:* | update_failed:*) status="❌ failed" ((pkg_fail++)) || true diff --git a/scripts/validate-pkg.sh b/scripts/validate-pkg.sh index 9eed683..45eb89d 100755 --- a/scripts/validate-pkg.sh +++ b/scripts/validate-pkg.sh @@ -61,6 +61,15 @@ validate_pkg() { return 1 fi + # --- Optional fields --- + + local allow_downgrade + allow_downgrade=$(pkg_get "$file" '.allow_downgrade | tag') + if [[ "$allow_downgrade" != "!!null" && "$allow_downgrade" != "!!bool" ]]; then + log_err "$file: allow_downgrade must be true or false" + ((errors++)) + fi + # --- Strategy-specific fields --- # Validate optional tag_pattern as regex (used by *-tag strategies) diff --git a/tests/publish.bats b/tests/publish.bats index 5eccfb0..68b924c 100644 --- a/tests/publish.bats +++ b/tests/publish.bats @@ -694,7 +694,8 @@ EOF current: '1.0.0'" create_test_package "older" "github-release" "upstream: project: owner/repo -current: '1.0.0'" +current: '1.0.0' +allow_downgrade: true" echo "new_version: 2.1.0" >"$TEST_TMPDIR/.status/pkg" echo "available_downgrade: 0.9.0" >"$TEST_TMPDIR/.status/older" stub_script check-update.sh 1 "strategy ran" @@ -732,6 +733,19 @@ current: '1.0.0'" [ "$(cat "$TEST_TMPDIR/out/status/_error_count")" = "2" ] } +@test "check-all --prepare: prepares no downgrade the check run skipped" { + create_test_package "older" "github-release" "upstream: + project: owner/repo +current: '1.0.0'" + echo "downgrade_skipped: 0.9.0" >"$TEST_TMPDIR/.status/older" + stub_script update-pkg.sh 0 + run "$TEST_TMPDIR/scripts/check-all.sh" --prepare "$TEST_TMPDIR/out" + [ "$status" -eq 0 ] + [ ! -e "$TEST_TMPDIR/update-pkg.sh.args" ] + [ "$(cat "$TEST_TMPDIR/out/status/older")" = "downgrade_skipped: 0.9.0" ] + [ "$(cat "$TEST_TMPDIR/out/status/_error_count")" = "0" ] +} + @test "check-all --prepare: records a failed preparation" { create_test_package "pkg" "github-release" "upstream: project: owner/repo @@ -779,6 +793,32 @@ current: '2.0.0'" [ "$(cat "$TEST_TMPDIR/.status/_error_count")" = "1" ] } +@test "check-all --publish: keeps a skipped downgrade and publishes nothing" { + create_test_package "older" "github-release" "upstream: + project: owner/repo +current: '1.0.0'" + checked_status older "downgrade_skipped: 0.9.0" + stub_script publish-pkg.sh 0 + run "$TEST_TMPDIR/scripts/check-all.sh" --publish "$TEST_TMPDIR/out" + [ "$status" -eq 0 ] + [ ! -e "$TEST_TMPDIR/publish-pkg.sh.args" ] + [ "$(cat "$TEST_TMPDIR/.status/older")" = "downgrade_skipped: 0.9.0" ] + [ "$(cat "$TEST_TMPDIR/.status/_error_count")" = "0" ] +} + +@test "check-all --publish: publishes no downgrade of a package that does not allow it" { + create_test_package "older" "github-release" "upstream: + project: owner/repo +current: '1.0.0'" + checked_status older "available_downgrade: 0.9.0" + mkdir -p "$TEST_TMPDIR/out/prepared/older" + stub_script publish-pkg.sh 0 + run "$TEST_TMPDIR/scripts/check-all.sh" --publish "$TEST_TMPDIR/out" + [ "$status" -eq 0 ] + [ ! -e "$TEST_TMPDIR/publish-pkg.sh.args" ] + [ "$(cat "$TEST_TMPDIR/.status/older")" = "downgrade_skipped: 0.9.0" ] +} + @test "check-all --publish: marks a package the check run left out" { create_test_package "pkg" "github-release" "upstream: project: owner/repo diff --git a/tests/scripts.bats b/tests/scripts.bats index 18fd238..44ddd1d 100644 --- a/tests/scripts.bats +++ b/tests/scripts.bats @@ -1729,7 +1729,7 @@ EOF [[ "$output" != *"Updating checksums"* ]] } -# === downgrade detection (observability only) === +# === downgrades === @test "check-update: detects downgrade when current is newer than latest" { # Mock github-release returns v2.0.0. Current 3.0.0 > 2.0.0 = downgrade. @@ -1742,7 +1742,7 @@ current: '3.0.0'" [ "$status" -eq 0 ] # stderr (captured into $output by `run`) carries the DOWNGRADE log line. [[ "$output" == *"DOWNGRADE 3.0.0"*"2.0.0"* ]] - # The version is still printed to stdout (mirror upstream blindly). + # The version is still printed to stdout; check-all.sh decides on it. [[ "$output" == *"2.0.0"* ]] } @@ -1760,25 +1760,55 @@ current: '1.0.0'" [[ "$output" == *"2.0.0"* ]] } -@test "check-all: writes 'available_downgrade:' status in check-only mode" { +@test "check-all: writes 'available_downgrade:' for a package that allows downgrades" { # Mock returns v2.0.0. Current 3.0.0 > 2.0.0 = downgrade. create_test_package "pkg-down" "github-release" "upstream: type: github project: owner/repo -current: '3.0.0'" +current: '3.0.0' +allow_downgrade: true" "$TEST_TMPDIR/scripts/check-all.sh" 2>/dev/null || true [ -f "$TEST_TMPDIR/.status/pkg-down" ] [ "$(cat "$TEST_TMPDIR/.status/pkg-down")" = "available_downgrade: 2.0.0" ] } +@test "check-all: skips a downgrade without allow_downgrade" { + create_test_package "pkg-down" "github-release" "upstream: + type: github + project: owner/repo +current: '3.0.0'" + + run "$TEST_TMPDIR/scripts/check-all.sh" + [ "$status" -eq 0 ] + [[ "$output" == *"DOWNGRADE detected 3.0.0 → 2.0.0, skipped: allow_downgrade is not set"* ]] + [ "$(cat "$TEST_TMPDIR/.status/pkg-down")" = "downgrade_skipped: 2.0.0" ] + [ "$(cat "$TEST_TMPDIR/.status/_error_count")" = "0" ] +} + +@test "check-all --update: runs no update to a lower version without allow_downgrade" { + create_test_package "pkg-down" "github-release" "upstream: + type: github + project: owner/repo +current: '3.0.0'" + rm -f "$TEST_TMPDIR/scripts/update-pkg.sh" + printf '#!/usr/bin/env bash\necho "$*" >>"%s/update-pkg.args"\n' "$TEST_TMPDIR" >"$TEST_TMPDIR/scripts/update-pkg.sh" + chmod +x "$TEST_TMPDIR/scripts/update-pkg.sh" + + run "$TEST_TMPDIR/scripts/check-all.sh" --update + [ "$status" -eq 0 ] + [ ! -e "$TEST_TMPDIR/update-pkg.args" ] + [ "$(cat "$TEST_TMPDIR/.status/pkg-down")" = "downgrade_skipped: 2.0.0" ] +} + @test "check-all: writes 'downgrade:' status after successful --update causing downgrade" { # A stub update-pkg.sh in the temp workspace always succeeds, so the test # covers only how check-all.sh writes the status. create_test_package "pkg-down-upd" "github-release" "upstream: type: github project: owner/repo -current: '3.0.0'" +current: '3.0.0' +allow_downgrade: true" # Replace the symlinked update-pkg.sh with a stub that exits 0. rm -f "$TEST_TMPDIR/scripts/update-pkg.sh" @@ -1832,6 +1862,24 @@ EOF grep -q "brightgreen" "$TEST_TMPDIR/README.md" } +@test "update-readme: renders a skipped downgrade and keeps the badge green" { + create_test_package "pkg-down" "github-release" "upstream: + project: owner/repo +current: '3.0.0'" + + echo "downgrade_skipped: 1.0.0" >"$TEST_TMPDIR/.status/pkg-down" + + cat >"$TEST_TMPDIR/README.md" <<'EOF' + + +EOF + git -C "$TEST_TMPDIR" init -q + "$TEST_TMPDIR/scripts/update-readme.sh" 2>/dev/null + + grep -q "⬇️ 1.0.0 skipped (downgrade)" "$TEST_TMPDIR/README.md" + grep -q "brightgreen" "$TEST_TMPDIR/README.md" +} + @test "check-all: writes 'updated:' status after --update on normal upgrade (regression)" { # Current 1.0.0 < latest 2.0.0: the normal upgrade path. # Verifies the is_downgrade=false branch of the new status-writing logic. diff --git a/tests/validate-pkg.bats b/tests/validate-pkg.bats index ad67c97..8d92b36 100644 --- a/tests/validate-pkg.bats +++ b/tests/validate-pkg.bats @@ -398,6 +398,26 @@ EOF [[ "$output" == *"not valid ERE regex"* ]] } +@test "validate: allow_downgrade true passes" { + create_test_package "mypkg" "github-release" "upstream: + project: owner/repo +allow_downgrade: true" + run "$TEST_TMPDIR/scripts/validate-pkg.sh" "mypkg" + [ "$status" -eq 0 ] +} + +@test "validate: allow_downgrade that is not a boolean rejected" { + local value + for value in yes '"true"' 1; do + create_test_package "mypkg" "github-release" "upstream: + project: owner/repo +allow_downgrade: $value" + run "$TEST_TMPDIR/scripts/validate-pkg.sh" "mypkg" + [ "$status" -ne 0 ] + [[ "$output" == *"allow_downgrade must be true or false"* ]] + done +} + @test "validate: tag_pattern valid glob accepted" { create_test_package "mypkg" "github-tag" "upstream: project: owner/repo diff --git a/tests/workflows.bats b/tests/workflows.bats index 4f85bf4..8c39dc0 100644 --- a/tests/workflows.bats +++ b/tests/workflows.bats @@ -212,6 +212,8 @@ run_decide_step() { README_CHANGED=1 run run_decide_step pkg="check_failed: API down" [ "$status" -eq 0 ] [ "$output" = $'prepare=false\nwork=true' ] + README_CHANGED=1 run run_decide_step pkg="downgrade_skipped: 1.0.0" + [ "$output" = $'prepare=false\nwork=true' ] } @test "check-updates: Decide does nothing when nothing changed" {