mirror of
https://github.com/obi1kenobi/cargo-semver-checks-action.git
synced 2024-11-21 15:49:30 +01:00
Add input exclude
, allow list in package
(#40)
* Add exclude, allow lists in package * Add test for input exclude * Second dummy crate in test workspace * New tests * Fix cache key * Forgot about flat() * Reflect changes in docs * New key in cache test * Shorter job name * Allowed to fail -> expected to fail * Update README.md Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com> * Hash inputs in cache key * Update cache test * Update README --------- Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com>
This commit is contained in:
parent
7eca687541
commit
8b981cde1a
10 changed files with 114 additions and 40 deletions
|
@ -14,10 +14,12 @@ runs:
|
|||
persist-credentials: true
|
||||
path: ref_slice
|
||||
- name: Create dummy crate
|
||||
# This crate does not have a matching baseline on crates.io, so any try
|
||||
# of checking it should make cargo-semver-checks fail.
|
||||
run: cargo new cargo-semver-action-dummy --lib
|
||||
# This crates do not have matching baselines on crates.io, so any try
|
||||
# of checking them should make cargo-semver-checks fail.
|
||||
run: |
|
||||
cargo new cargo-semver-action-dummy --lib
|
||||
cargo new cargo-semver-action-dummy-2 --lib
|
||||
shell: bash
|
||||
- name: Create workspace Cargo.toml
|
||||
run: echo -e "[workspace]\nmembers=['ref_slice','cargo-semver-action-dummy']" > Cargo.toml
|
||||
run: echo -e "[workspace]\nmembers=['ref_slice','cargo-semver-action-dummy','cargo-semver-action-dummy-2']" > Cargo.toml
|
||||
shell: bash
|
||||
|
|
2
.github/workflows/test-action.yml
vendored
2
.github/workflows/test-action.yml
vendored
|
@ -36,7 +36,7 @@ jobs:
|
|||
run: |
|
||||
git fetch origin major_change
|
||||
git checkout major_change
|
||||
- name: Run the action (allowed to fail)
|
||||
- name: Run the action (expected to fail)
|
||||
id: action_major
|
||||
uses: ./action/
|
||||
with:
|
||||
|
|
2
.github/workflows/test-cache.yml
vendored
2
.github/workflows/test-cache.yml
vendored
|
@ -95,7 +95,7 @@ jobs:
|
|||
run: |
|
||||
RUSTC=$(rustc --version | sed -e 's/\s\+/-/g')
|
||||
SEMVER_CHECKS=$(cargo semver-checks --version | sed -e 's/\s\+/-/g')
|
||||
echo "KEY=testprefix-test-cache-exists-default-ref_slice-8e11dadaa21a8bf3112b6c764012883b-linux-$RUSTC-$SEMVER_CHECKS-da39a3ee5e6b4b0d3255bfef95601890afd80709-semver-checks-rustdoc" >> $GITHUB_OUTPUT
|
||||
echo "KEY=testprefix-test-cache-exists-default-d45618ed191f0a73-linux-$RUSTC-$SEMVER_CHECKS-da39a3ee5e6b4b0d3255bfef95601890afd80709-semver-checks-rustdoc" >> $GITHUB_OUTPUT
|
||||
- name: Download saved cache
|
||||
uses: actions/cache/restore@v3
|
||||
with:
|
||||
|
|
75
.github/workflows/test-inputs.yml
vendored
75
.github/workflows/test-inputs.yml
vendored
|
@ -26,7 +26,7 @@ jobs:
|
|||
uses: ./action/
|
||||
with:
|
||||
package: ref_slice
|
||||
- name: Run the action on the whole workspace (allowed to fail)
|
||||
- name: Run the action on the whole workspace (expected to fail)
|
||||
id: action_all
|
||||
uses: ./action/
|
||||
continue-on-error: true
|
||||
|
@ -35,6 +35,17 @@ jobs:
|
|||
run: |
|
||||
echo "Error! The action should have failed because of checking the dummy crate, but it has not!"
|
||||
exit 1
|
||||
- name: Run the action on ref_slice fork and one dummy crate (expected to fail)
|
||||
id: action_one_dummy
|
||||
uses: ./action/
|
||||
with:
|
||||
package: ref_slice, cargo-semver-action-dummy
|
||||
continue-on-error: true
|
||||
- name: Fail if the action has not returned any errors (but it should have)
|
||||
if: steps.action_one_dummy.outcome != 'failure'
|
||||
run: |
|
||||
echo "Error! The action should have failed because of checking the dummy crate, but it has not!"
|
||||
exit 1
|
||||
|
||||
test-package-major:
|
||||
name: Test input package (major change)
|
||||
|
@ -48,7 +59,7 @@ jobs:
|
|||
uses: ./action/.github/workflows/setup-test-workspace
|
||||
with:
|
||||
ref-slice-ref: major_change
|
||||
- name: Run the action on ref_slice major change (allowed to fail)
|
||||
- name: Run the action on ref_slice major change (expected to fail)
|
||||
id: action_major
|
||||
uses: ./action/
|
||||
with:
|
||||
|
@ -60,6 +71,56 @@ jobs:
|
|||
echo "Error! The action should have failed because of the breaking change, but it has not."
|
||||
exit 1
|
||||
|
||||
test-package-exclude-rio:
|
||||
name: Test inputs package and exclude on Rio library
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the Rio repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: oxigraph/rio
|
||||
ref: 3bd01c2c977a0b01c918f6840cd05356477db358 # branch main
|
||||
- name: Checkout the action
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: action
|
||||
- name: Run the action using input package
|
||||
uses: ./action/
|
||||
with:
|
||||
package: rio_api, rio_turtle, rio_xml
|
||||
- name: Run the action using input exclude
|
||||
uses: ./action/
|
||||
with:
|
||||
exclude: rio_testsuite
|
||||
|
||||
test-exclude:
|
||||
name: Test input exclude
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the action
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: action
|
||||
- name: Setup the workspace with ref_slice patch change
|
||||
uses: ./action/.github/workflows/setup-test-workspace
|
||||
with:
|
||||
ref-slice-ref: patch_change
|
||||
- name: Run the action excluding both dummy crates
|
||||
uses: ./action/
|
||||
with:
|
||||
exclude: cargo-semver-action-dummy, cargo-semver-action-dummy-2
|
||||
- name: Run the action excluding only one of the dummy crates (expected to fail)
|
||||
id: action_major
|
||||
uses: ./action/
|
||||
with:
|
||||
exclude: cargo-semver-action-dummy
|
||||
continue-on-error: true
|
||||
- name: Fail if the action has not returned any errors (but it should have)
|
||||
if: steps.action_major.outcome != 'failure'
|
||||
run: |
|
||||
echo "Error! The action should have failed because of the breaking change, but it has not."
|
||||
exit 1
|
||||
|
||||
test-verbose:
|
||||
# There is currently no way of asserting that the output is indeed verbose,
|
||||
# so we at least check if the action runs without an error when the
|
||||
|
@ -101,7 +162,7 @@ jobs:
|
|||
uses: ./action/
|
||||
with:
|
||||
manifest-path: ref_slice
|
||||
- name: Run the action on the whole workspace (Cargo.toml path, allowed to fail)
|
||||
- name: Run the action on the whole workspace (Cargo.toml path, expected to fail)
|
||||
id: action_all_cargo_toml
|
||||
uses: ./action/
|
||||
with:
|
||||
|
@ -125,7 +186,7 @@ jobs:
|
|||
uses: ./action/.github/workflows/setup-test-workspace
|
||||
with:
|
||||
ref-slice-ref: major_change
|
||||
- name: Run the action on ref_slice major change (Cargo.toml path, allowed to fail)
|
||||
- name: Run the action on ref_slice major change (Cargo.toml path, expected to fail)
|
||||
id: action_major_cargo_toml
|
||||
uses: ./action/
|
||||
with:
|
||||
|
@ -136,7 +197,7 @@ jobs:
|
|||
run: |
|
||||
echo "Error! The action should have failed because of the breaking change, but it has not."
|
||||
exit 1
|
||||
- name: Run the action on ref_slice major change (crate path, allowed to fail)
|
||||
- name: Run the action on ref_slice major change (crate path, expected to fail)
|
||||
id: action_major_crate
|
||||
uses: ./action/
|
||||
with:
|
||||
|
@ -174,7 +235,7 @@ jobs:
|
|||
cd "ref slice"
|
||||
git fetch origin major_change
|
||||
git checkout major_change
|
||||
- name: Run the action (allowed to fail)
|
||||
- name: Run the action (expected to fail)
|
||||
id: action_major
|
||||
uses: ./action/
|
||||
with:
|
||||
|
@ -310,7 +371,7 @@ jobs:
|
|||
exit 1
|
||||
- name: Uninstall Rust
|
||||
run: rustup self uninstall -y
|
||||
- name: Run the action with manual rust-toolchain (allowed to fail)
|
||||
- name: Run the action with manual rust-toolchain (expected to fail)
|
||||
id: action_without_rust
|
||||
uses: ./action/
|
||||
with:
|
||||
|
|
24
README.md
24
README.md
|
@ -16,11 +16,12 @@ Every argument is optional.
|
|||
|
||||
| Input | Description | Default |
|
||||
|--------------------|-----------------------------------------------------------------------------------------------------------------------------------|---------|
|
||||
| `package` | The package whose API to check for semver (in Package Id Specification format, see https://doc.rust-lang.org/cargo/reference/pkgid-spec.html for reference). If not set, all packages defined in the Cargo.toml file are processed. | |
|
||||
| `package` | Comma-separated list of the packages whose API to check for semver (in Package Id Specification format, see https://doc.rust-lang.org/cargo/reference/pkgid-spec.html for reference). If not set, all packages defined in the Cargo.toml file are processed. | |
|
||||
| `exclude` | Comma-separated list of the packages that will be excluded from being processed. Has effect only if the input `package` is not specified. | |
|
||||
| `manifest-path` | Path to Cargo.toml of crate or workspace to check. If not specified, the action assumes the manifest is under the default [`GITHUB_WORKSPACE`](https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables) path. | |
|
||||
| `verbose` | Enables verbose output of `cargo-semver-checks`. | `false` |
|
||||
| `rust-toolchain` | Rust toolchain name to use, e.g. `stable`, `nightly` or `1.68.0`. It will be installed if necessary and used regardless of local overrides and the `rust-toolchain.toml` file. However, if the input is set to `manual`, the action assumes some Rust toolchain is already installed and uses the default one. | `stable` |
|
||||
| `shared-key` | A cache key that will be used instead of the automatic key based on the name of the GitHub job and values of the inputs `package` and `manifest-path`. Might be provided e.g. to share the cache between the jobs. | |
|
||||
| `shared-key` | A cache key that will be used instead of the automatic key based on the name of the GitHub job and values of the inputs `package`, `exclude` and `manifest-path`. Might be provided e.g. to share the cache between the jobs. | |
|
||||
| `prefix-key` | Additional prefix of the cache key, can be set to start a new cache manually. | |
|
||||
| `github-token` | The `GITHUB_TOKEN` secret used to download precompiled binaries from GitHub API. If not specified, the [automatic GitHub token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication) provided to the workflow will be used. The token may be alternatively passed in an environment variable `GITHUB_TOKEN`. | `${{ github.token }}` |
|
||||
|
||||
|
@ -38,14 +39,23 @@ The action will work out-of-the-box if it is run inside the package root directo
|
|||
|
||||
# Use in workspaces with more than one crate
|
||||
|
||||
By default, if workspace contains multiple crates, all of them are checked for semver violations. You can specify a single crate to be checked instead using `package` or `manifest-path`.
|
||||
By default, if workspace contains multiple crates, all of them are checked for semver violations. You can specify one or more crates to be checked instead using `package`, `exclude` or `manifest-path`.
|
||||
|
||||
For example, this will check `my-crate`:
|
||||
For example, this will check `my-crate-api` and `my-crate-core`:
|
||||
```yaml
|
||||
- name: Check semver for my-crate from the current workspace
|
||||
- name: Check semver for my-crate-api and my-crate-core
|
||||
uses: obi1kenobi/cargo-semver-checks-action@v2
|
||||
with:
|
||||
package: my-crate
|
||||
package: my-crate-api, my-crate-core
|
||||
- name: Publish my-crate to crates.io
|
||||
run: # your `cargo publish` code here
|
||||
```
|
||||
And this will process all crates from the current workspace except `my-crate-tests`:
|
||||
```yaml
|
||||
- name: Check semver for all crates except my-crate-tests
|
||||
uses: obi1kenobi/cargo-semver-checks-action@v2
|
||||
with:
|
||||
exclude: my-crate-tests
|
||||
- name: Publish my-crate to crates.io
|
||||
run: # your `cargo publish` code here
|
||||
```
|
||||
|
@ -76,7 +86,7 @@ The two above might be also used together:
|
|||
The action caches the baseline rustdoc for each package in the workspace. The keys used to distinguish the caches consist of four components:
|
||||
|
||||
- `prefix-key` input, which defaults to an empty string,
|
||||
- `shared-key` input if provided, otherwise a concatenation of the value of environmental variable `GITHUB_JOB`, the value of `package` and the hashed value of the `manifest-path` variable (not the file it points to),
|
||||
- `shared-key` input if provided, otherwise the value of environmental variable `GITHUB_JOB` concatenated with a hash of the values of inputs `package`, `exclude` and `manifest-path` (we hash the path itself, not the file it points to),
|
||||
- internal, unchangable component, being a concatenation of the runner OS, `rustc` version, `cargo-semver-checks` version and hash of all `Cargo.lock` files in the current workspace,
|
||||
- constant suffix `"semver-checks-rustdoc"`.
|
||||
|
||||
|
|
|
@ -5,7 +5,10 @@ branding:
|
|||
color: 'green'
|
||||
inputs:
|
||||
package:
|
||||
description: 'The package whose API to check for semver (in Package Id Specification format, see https://doc.rust-lang.org/cargo/reference/pkgid-spec.html for reference). If not set, all packages defined in the Cargo.toml file are processed.'
|
||||
description: 'Comma-separated list of the packages whose API to check for semver (in Package Id Specification format, see https://doc.rust-lang.org/cargo/reference/pkgid-spec.html for reference). If not set, all packages defined in the Cargo.toml file are processed.'
|
||||
required: false
|
||||
exclude:
|
||||
description: 'Comma-separated list of the packages that will be excluded from being processed. Has effect only if the input `package` is not specified.'
|
||||
required: false
|
||||
manifest-path:
|
||||
description: 'Path to Cargo.toml of crate or workspace to check. If not specified, the action assumes the manifest is under the default `GITHUB_WORKSPACE` path.'
|
||||
|
@ -19,7 +22,7 @@ inputs:
|
|||
description: 'Rust toolchain name to use, e.g. `stable`, `nightly` or `1.68.0`. It will be installed if necessary and used regardless of local overrides and the `rust-toolchain.toml` file. However, if the input is set to `manual`, the action assumes some Rust toolchain is already installed and uses the default one.'
|
||||
default: 'stable'
|
||||
shared-key:
|
||||
description: 'A cache key that will be used instead of the automatic key based on the name of the GitHub job and values of the inputs `package` and `manifest-path`. Might be provided e.g. to share the cache between the jobs.'
|
||||
description: 'A cache key that will be used instead of the automatic key based on the name of the GitHub job and values of the inputs `package`, `exclude` and `manifest-path`. Might be provided e.g. to share the cache between the jobs.'
|
||||
required: false
|
||||
default: ''
|
||||
prefix-key:
|
||||
|
|
2
dist/index.js
vendored
2
dist/index.js
vendored
File diff suppressed because one or more lines are too long
|
@ -9,6 +9,7 @@ import {
|
|||
getErrorMessage,
|
||||
getPlatformMatchingTarget,
|
||||
getRustcVersion,
|
||||
optionFromList,
|
||||
optionIfValueProvided,
|
||||
} from "./utils";
|
||||
import { RustdocCache } from "./rustdoc-cache";
|
||||
|
@ -17,7 +18,8 @@ const CARGO_TARGET_DIR = path.join("semver-checks", "target");
|
|||
|
||||
function getCheckReleaseArguments(): string[] {
|
||||
return [
|
||||
optionIfValueProvided("--package", rustCore.input.getInput("package")),
|
||||
optionFromList("--package", rustCore.input.getInputList("package")),
|
||||
optionFromList("--exclude", rustCore.input.getInputList("exclude")),
|
||||
optionIfValueProvided("--manifest-path", rustCore.input.getInput("manifest-path")),
|
||||
rustCore.input.getInputBool("verbose") ? ["--verbose"] : [],
|
||||
].flat();
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
import os = require("os");
|
||||
|
||||
import * as path from "path";
|
||||
import * as crypto from "crypto";
|
||||
import * as cache from "@actions/cache";
|
||||
import * as core from "@actions/core";
|
||||
import * as rustCore from "@actions-rs/core";
|
||||
|
||||
import {
|
||||
getCargoSemverChecksVersion,
|
||||
getRustcVersion,
|
||||
hashFilesOrEmpty,
|
||||
hashIfNotEmpty,
|
||||
} from "./utils";
|
||||
import { getCargoSemverChecksVersion, getRustcVersion, hashFilesOrEmpty } from "./utils";
|
||||
|
||||
export class RustdocCache {
|
||||
private readonly cargo;
|
||||
|
@ -71,11 +67,12 @@ export class RustdocCache {
|
|||
}
|
||||
|
||||
private getRunDependentKey(): string {
|
||||
return [
|
||||
process.env["GITHUB_JOB"] || "",
|
||||
rustCore.input.getInput("package"),
|
||||
hashIfNotEmpty(rustCore.input.getInput("manifest-path")),
|
||||
].join("-");
|
||||
const hasher = crypto.createHash("md5");
|
||||
hasher.update(JSON.stringify({ package: rustCore.input.getInputList("package").sort() }));
|
||||
hasher.update(JSON.stringify({ exclude: rustCore.input.getInputList("exclude").sort() }));
|
||||
hasher.update(JSON.stringify({ manifest_path: rustCore.input.getInput("manifest-path") }));
|
||||
|
||||
return [process.env["GITHUB_JOB"] || "", hasher.digest("hex").substring(0, 16)].join("-");
|
||||
}
|
||||
|
||||
private getLocalCacheHash(): string {
|
||||
|
|
|
@ -3,7 +3,6 @@ import hashFiles = require("hash-files");
|
|||
|
||||
import * as exec from "@actions/exec";
|
||||
import * as rustCore from "@actions-rs/core";
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
export function getErrorMessage(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
|
@ -31,6 +30,10 @@ export function optionIfValueProvided(option: string, value?: string): string[]
|
|||
return value ? [option, value] : [];
|
||||
}
|
||||
|
||||
export function optionFromList(option: string, values: string[]): string[] {
|
||||
return values.map((value) => [option, value]).flat();
|
||||
}
|
||||
|
||||
export function hashFilesOrEmpty(patterns: string[]): string {
|
||||
try {
|
||||
return hashFiles.sync({ files: patterns });
|
||||
|
@ -39,10 +42,6 @@ export function hashFilesOrEmpty(patterns: string[]): string {
|
|||
}
|
||||
}
|
||||
|
||||
export function hashIfNotEmpty(str: string): string {
|
||||
return createHash("md5").update(str).digest("hex");
|
||||
}
|
||||
|
||||
function makeExecOptions(stdout: { s: string }): exec.ExecOptions {
|
||||
return {
|
||||
listeners: {
|
||||
|
|
Loading…
Reference in a new issue