diff --git a/.github/workflows/dependency-scan.yml b/.github/workflows/dependency-scan.yml index a6436ccc..83a1abc5 100644 --- a/.github/workflows/dependency-scan.yml +++ b/.github/workflows/dependency-scan.yml @@ -4,21 +4,12 @@ on: push jobs: analyze: runs-on: ubuntu-latest - steps: - uses: actions/checkout@v3 - - name: Install fossa-cli from github - run: | - curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install-latest.sh | bash - - - name: Run FOSSA dependency scan + - run: curl https://raw.githubusercontent.com/fossas/fossa-cli/master/install-latest.sh | bash + - run: fossa analyze env: FOSSA_API_KEY: ${{ secrets.FOSSA_API_KEY }} - run: | - fossa analyze --only-target cargo . - - - name: Gate PR on license compliance + - run: fossa test env: FOSSA_API_KEY: ${{ secrets.FOSSA_API_KEY }} - run: | - fossa test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..32cd9032 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,150 @@ +# CI that: +# +# * checks for a Git Tag that looks like a release ("v1.2.0") +# * creates a Github Release™️ +# * builds binaries/packages with cargo-dist +# * uploads those packages to the Github Release™️ +# +# Note that the Github Release™️ will be created before the packages, +# so there will be a few minutes where the release has no packages +# and then they will slowly trickle in, possibly failing. To make +# this more pleasant we mark the release as a "draft" until all +# artifacts have been successfully uploaded. This allows you to +# choose what to do with partial successes and avoids spamming +# anyone with notifications before the release is actually ready. +name: Release + +permissions: + contents: write + +# This task will run whenever you push a git tag that looks like +# a version number. We just look for `v` followed by at least one number +# and then whatever. so `v1`, `v1.0.0`, and `v1.0.0-prerelease` all work. +# +# If there's a prerelease-style suffix to the version then the Github Release™️ +# will be marked as a prerelease (handled by taiki-e/create-gh-release-action). +# +# Note that when generating links to uploaded artifacts, cargo-dist will currently +# assume that your git tag is always v{VERSION} where VERSION is the version in +# the published package's Cargo.toml (this is the default behaviour of cargo-release). +# In the future this may be made more robust/configurable. +on: + push: + tags: + - v[0-9]+.* + +env: + ALL_CARGO_DIST_TARGET_ARGS: --target=x86_64-unknown-linux-gnu --target=x86_64-apple-darwin --target=x86_64-pc-windows-msvc + ALL_CARGO_DIST_INSTALLER_ARGS: --installer=github-powershell --installer=github-shell + +jobs: + # Create the Github Release™️ so the packages have something to be uploaded to + create-release: + runs-on: ubuntu-latest + outputs: + tag: ${{ steps.create-gh-release.outputs.computed-prefix }}${{ steps.create-gh-release.outputs.version }} + steps: + - uses: actions/checkout@v3 + - id: create-gh-release + uses: taiki-e/create-gh-release-action@v1 + with: + draft: true + # (required) GitHub token for creating GitHub Releases. + token: ${{ secrets.GITHUB_TOKEN }} + + + # Build and packages all the things + upload-artifacts: + needs: create-release + strategy: + matrix: + # For these target platforms + include: + - target: x86_64-unknown-linux-gnu + os: ubuntu-20.04 + install-dist: curl --proto '=https' --tlsv1.2 -L -sSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.2/installer.sh | sh + - target: x86_64-apple-darwin + os: macos-11 + install-dist: curl --proto '=https' --tlsv1.2 -L -sSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.2/installer.sh | sh + - target: x86_64-pc-windows-msvc + os: windows-2019 + install-dist: irm 'https://github.com/axodotdev/cargo-dist/releases/download/v0.0.2/installer.ps1' | iex + runs-on: ${{ matrix.os }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v3 + - name: Install Rust + run: rustup update stable && rustup default stable + - name: Install cargo-dist + run: ${{ matrix.install-dist }} + - name: Run cargo-dist + # This logic is a bit janky because it's trying to be a polyglot between + # powershell and bash since this will run on windows, macos, and linux! + # The two platforms don't agree on how to talk about env vars but they + # do agree on 'cat' and '$()' so we use that to marshal values between commmands. + run: | + # Actually do builds and make zips and whatnot + cargo dist --target=${{ matrix.target }} --output-format=json > dist-manifest.json + echo "dist ran successfully" + cat dist-manifest.json + # Parse out what we just built and upload it to the Github Release™️ + cat dist-manifest.json | jq --raw-output ".releases[].artifacts[].path" > uploads.txt + echo "uploading..." + cat uploads.txt + gh release upload ${{ needs.create-release.outputs.tag }} $(cat uploads.txt) + echo "uploaded!" + + # Compute and upload the manifest for everything + upload-manifest: + needs: create-release + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v3 + - name: Install Rust + run: rustup update stable && rustup default stable + - name: Install cargo-dist + run: curl --proto '=https' --tlsv1.2 -L -sSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.2/installer.sh | sh + - name: Run cargo-dist manifest + run: | + # Generate a manifest describing everything + cargo dist manifest --no-local-paths --output-format=json $ALL_CARGO_DIST_TARGET_ARGS $ALL_CARGO_DIST_INSTALLER_ARGS > dist-manifest.json + echo "dist manifest ran successfully" + cat dist-manifest.json + # Upload the manifest to the Github Release™️ + gh release upload ${{ needs.create-release.outputs.tag }} dist-manifest.json + echo "uploaded manifest!" + # Edit the Github Release™️ title/body to match what cargo-dist thinks it should be + CHANGELOG_TITLE=$(cat dist-manifest.json | jq --raw-output ".releases[].changelog_title") + cat dist-manifest.json | jq --raw-output ".releases[].changelog_body" > new_dist_changelog.md + gh release edit ${{ needs.create-release.outputs.tag }} --title="$CHANGELOG_TITLE" --notes-file=new_dist_changelog.md + echo "updated release notes!" + - name: Run cargo-dist --installer=... + run: | + # Run cargo dist with --no-builds to get agnostic artifacts like installers + cargo dist --output-format=json --no-builds $ALL_CARGO_DIST_INSTALLER_ARGS > dist-manifest.json + echo "dist ran successfully" + cat dist-manifest.json + # Grab the installers that were generated and upload them. + # This filter is working around the fact that --no-builds is kinds hacky + # and still makes/reports malformed zips that we don't want to upload. + cat dist-manifest.json | jq --raw-output '.releases[].artifacts[] | select(.kind == "installer") | .path' > uploads.txt + echo "uploading..." + cat uploads.txt + gh release upload ${{ needs.create-release.outputs.tag }} $(cat uploads.txt) + echo "uploaded installers!" + + # Mark the Github Release™️ as a non-draft now that everything has succeeded! + publish-release: + needs: [create-release, upload-artifacts, upload-manifest] + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v3 + - name: mark release as non-draft + run: | + gh release edit ${{ needs.create-release.outputs.tag }} --draft=false + diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 542d918f..67d1d656 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -57,3 +57,19 @@ jobs: toolchain: stable - uses: Swatinem/rust-cache@v2 - run: cargo build + + # Ensure dependencies are up to date + updated: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + - uses: Swatinem/rust-cache@v2 + - uses: taiki-e/install-action@v2 + with: + tool: cargo-upgrades,cargo-edit + - run: cargo upgrade + - run: git diff --exit-code diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fb2beff9..a3b15d6a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -4,7 +4,6 @@ on: push jobs: all: runs-on: ubuntu-latest - steps: - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 @@ -12,5 +11,7 @@ jobs: profile: minimal toolchain: stable - uses: Swatinem/rust-cache@v2 - - uses: taiki-e/install-action@nextest + - uses: taiki-e/install-action@v2 + with: + tool: nextest - run: cargo nextest run diff --git a/Cargo.lock b/Cargo.lock index e72e4001..830d291f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,7 +10,7 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "broker" -version = "0.1.0" +version = "0.0.1" dependencies = [ "clap", ] @@ -23,9 +23,9 @@ checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "clap" -version = "4.1.4" +version = "4.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" +checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" dependencies = [ "bitflags", "clap_derive", @@ -127,9 +127,9 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "once_cell" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "os_str_bytes" diff --git a/Cargo.toml b/Cargo.toml index c9d2c3e2..42808ec2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,20 @@ [package] name = "broker" -version = "0.1.0" +version = "0.0.1" edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +description = "The bridge between FOSSA and internal DevOps services" +readme = "README.md" +homepage = "https://github.com/fossas/broker" +repository = "https://github.com/fossas/broker" +license = "Apache-2.0" +exclude = [ "docs", ".github" ] +publish = false # rather than publishing this to crates.io, we'll provide releases here on GitHub. [dependencies] -clap = { version = "4.1.4", features = ["derive"] } +clap = { version = "4.1.6", features = ["derive"] } + +# generated by 'cargo dist init' +[profile.dist] +inherits = "release" +debug = true +split-debuginfo = "packed" diff --git a/README.md b/README.md index 162cfd26..c877d2db 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,35 @@ # Broker -The bridge between FOSSA and internal DevOps services. +The bridge between FOSSA and internal projects. -Using Broker, FOSSA users may scan local projects in internal DevOps hosts, +FOSSA users use Broker to scan local projects, importing them into the FOSSA service (including FOSSA in the cloud) -without sharing access to the source code of the project. +without sharing access to the source code of the project! ## Quickstart 1. Install Broker: `TODO: add command` 2. Initialize Broker: `broker init` -3. Configure the `.broker.yml` with your DevOps host or project URLs +3. Configure the `.broker.yml` with your projects 4. Run Broker: `broker run` -5. View your projects in FOSSA! +5. Wait a little bit for import magic to happen and then view your projects in FOSSA! For more information, see the [User Manual](./docs/README.md). -## Supported DevOps Hosts +## Supported Projects -DevOps hosts are services which host many repositories. -Broker supports the following DevOps hosts: - -| Host | Supported | Details | -|------------|-----------|-----------------------------| -| github.com | ⌛️ | The GitHub SaaS application | -| gitlab.com | ⌛️ | The GitLab SaaS application | - -Additionally, Broker supports arbitrary project URLs: +Broker supports arbitrary project URLs: | Kind | Supported | Details | |-------|-----------|---------------------------------------| | `git` | ⌛️ | Any project reachable via `git clone` | + +_Legend:_ +- _✅: Supported_ +- _⌛️: In Development_ +- _🛑: Not Planned_ + +## Contributing + +If you're interested in contributing, check out our [developer guide](./docs/dev/README.md). +PRs are welcome and appreciated! diff --git a/docs/README.md b/docs/README.md index d4ff84c8..13249412 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ # User Manual -_TODO: Fill this out_ +_TODO: Fill this out as we add functionality_ ## Subcommands diff --git a/docs/dev/README.md b/docs/dev/README.md new file mode 100644 index 00000000..8941b1be --- /dev/null +++ b/docs/dev/README.md @@ -0,0 +1,100 @@ + +# development + +Tags denote releases. +Any commit merged to `main` is expected to be release ready, +with the exception of the `version` in `Cargo.toml`. +For more detail, see the [release process](#release-process). + +Broker follows [semver](https://semver.org/): +- MAJOR version indicates a user facing breaking change. +- MINOR version indicates backwards compatible functionality improvement. +- PATCH version indicates backwards compatible bug fixes. + +The initial beta releases of Broker use `0` as the major version; when this changes to `1` +it will not necessarily indicate a breaking change, but future major version increases will. + +## compatibility + +Broker: +- Tracks the latest version of the Rust compiler and associated tooling at all times. +- Tracks the latest Rust language edition. +- Aggressively upgrades dependencies. We rely on testing to validate our dependencies work. + +## setting up your development environment + +We recommend Visual Studio Code with the `rust-analyzer` extension. +Install Rust here: https://www.rust-lang.org/tools/install + +For any contributors, we recommend the following tools, although they're not required: +``` +cargo edit # https://lib.rs/crates/cargo-edit +cargo nextest # https://nexte.st/ +cargo upgrade # https://lib.rs/crates/cargo-upgrades +``` + +If you're a FOSSA employee who'll be performing releases, we use `cargo-dist` and `cargo-release`: +``` +cargo dist # https://github.com/axodotdev/cargo-dist +cargo release # https://github.com/crate-ci/cargo-release +``` + +Our release process is generated with `cargo dist`. +To regenerate it, run: +``` +cargo dist generate-ci github \ + --installer github-powershell \ + --installer github-shell +``` + +## style guide + +Make your code look like the code around it. Consistency is the name of the game. + +You should submit changes to this doc if you think you can improve it, +or if a case should be covered by this doc, but currently is not. + +Use `rustfmt` for formatting. +Our CI setup enforces that all changes pass a `rustfmt` run with no differences. + +Our CI systems ensure that all patches pass `clippy` checks. + +Comments should describe the "why", type signatures should describe the "what", and the code should describe the "how". + +We use the [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/about.html) +during code review; if you want to get ahead of the curve check it out! + +Ideally, every PR should check for updated dependencies and update them if applicable; +if this is not realistic at minimum every non-bugfix release **must** ensure dependencies are up to date. + +## release process + +While in a pre-release state, the `version` field in `Cargo.toml` displays at least the +minimal next version with a pre-release indicator. + +For example, if version `0.1.0` was just released, the next merge into `main` must set `version` to +at least `0.1.1-pre`. If the next release is known to be a specific version, that's okay to use as well: +for example if we know `0.2.0` is the next planned release, we can set it to `0.2.0-pre`. + +When the final commit for that version is merged, it must ensure `version` is accurate. +Reusing the previous example, after a slew of PRs, the final one would set `version` to `0.2.0`. + +After this commit is merged to `main`, push a tag (recommended: using `cargo release tag`) +matching the `version` field, with a `v` prefix. + +**It is recommended** to instead use `cargo release`, which automates much of this process and has +some safety checks (for example it ensures you're tagging on `main`): + +``` +cargo release tag # Review the planned actions +cargo release tag -x # Execute the planned actions +``` + +If instead you wish to do this manually, this is an example of what to do: + +``` +git checkout main # Ensure you're on main +git pull # Ensure you're tagging the latest commit +git tag v0.2.0 # Validate this is correct, and don't forget the `v` +git push --tags # Push the new tag to the remote. +``` diff --git a/src/main.rs b/src/main.rs index 5c465ecf..c7ece640 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ fn main() { } fn hello_text() -> String { - "Hello, world!".to_string() + "Hello from Broker!".to_string() } #[cfg(test)] @@ -13,6 +13,6 @@ mod tests { #[test] fn hello_world_text() { - assert_eq!(hello_text(), "Hello, world!".to_string()); + assert_eq!(hello_text(), "Hello from Broker!".to_string()); } }