Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Add v1.30 blog post. #1733

Merged
merged 4 commits into from
Nov 25, 2024
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
3 changes: 2 additions & 1 deletion crates/app/src/commands/docker/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ fn get_base_image_from_platform(platform: &PlatformType) -> &str {
PlatformType::Bun => "oven/bun:latest",
PlatformType::Deno => "denoland/deno:latest",
PlatformType::Node => "node:latest",
PlatformType::Python => "python:latest",
PlatformType::Rust => "rust:latest",
_ => "scratch",
PlatformType::System | PlatformType::Unknown => "scratch",
}
}
10 changes: 5 additions & 5 deletions crates/config/src/toolchain/python_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ pub struct PythonConfig {
#[setting(nested)]
pub pip: Option<PipConfig>,

/// Defines the virtual environment name which will be created on workspace root.
/// Project dependencies will be installed into this. Defaults to `.venv`
#[setting(default = ".venv")]
pub venv_name: String,

/// Assumes only the root `requirements.txt` is used for dependencies.
/// Can be used to support the "one version policy" pattern.
#[setting(default = true)]
pub root_requirements_only: bool,

/// Defines the virtual environment name, which will be created in the workspace root.
/// Project dependencies will be installed into this.
#[setting(default = ".venv")]
pub venv_name: String,

/// The version of Python to download, install, and run `python` tasks with.
#[setting(env = "MOON_PYTHON_VERSION")]
pub version: Option<UnresolvedVersionSpec>,
Expand Down
35 changes: 24 additions & 11 deletions crates/task-runner/src/output_hydrater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl<'task> OutputHydrater<'task> {
digest: &Digest,
operation: &mut Operation,
) -> miette::Result<bool> {
match from {
let result = match from {
// Only hydrate when the hash is different from the previous build,
// as we can assume the outputs from the previous build still exist?
HydrateFrom::PreviousOutput => Ok(true),
Expand All @@ -43,6 +43,7 @@ impl<'task> OutputHydrater<'task> {
// Otherwise write to local cache, then download archive from moonbase
HydrateFrom::LocalCache | HydrateFrom::Moonbase => {
let archive_file = self.app.cache_engine.hash.get_archive_path(&digest.hash);
let mut hydrated = false;

if self.app.cache_engine.is_readable() {
debug!(
Expand All @@ -61,15 +62,7 @@ impl<'task> OutputHydrater<'task> {
if archive_file.exists() {
self.unpack_local_archive(&digest.hash, &archive_file)?;

read_stdlog_state_files(
self.app
.cache_engine
.state
.get_target_dir(&self.task.target),
operation,
)?;

return Ok(true);
hydrated = true
}
} else {
debug!(
Expand All @@ -79,8 +72,28 @@ impl<'task> OutputHydrater<'task> {
);
}

Ok(false)
Ok(hydrated)
}
};

match result {
Ok(hydrated) => {
// If not from the remote cache, we need to read the
// locally cached stdout/stderr into the operation
// so that it can be replayed in the console
if !matches!(from, HydrateFrom::RemoteCache) {
read_stdlog_state_files(
self.app
.cache_engine
.state
.get_target_dir(&self.task.target),
operation,
)?;
}

Ok(hydrated)
}
Err(error) => Err(error),
}
}

Expand Down
7 changes: 5 additions & 2 deletions crates/task-runner/src/task_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -725,9 +725,12 @@ impl<'task> TaskRunner<'task> {

let mut operation = Operation::task_execution(&self.task.command);

if let (Some(output), Some(error)) = (operation.get_output_mut(), report) {
if let Some(output) = operation.get_output_mut() {
output.exit_code = Some(-1);
output.set_stderr(error.to_string());

if let Some(error) = report {
output.set_stderr(error.to_string());
}
}

operation.finish(ActionStatus::Aborted);
Expand Down
163 changes: 163 additions & 0 deletions website/blog/2024-11-25_moon-v1.30.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
---
slug: moon-v1.30
title: moon v1.30 - Python support, self-hosted remote caching, task graph, and more!
authors: [milesj]
tags: [affected, detection, tracker, task, graph, self-hosted, remote, cache, python, toolchain]
image: ./img/moon/v1.30.png
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

It's been almost 2 months since our last release, and we're excited to announce some major features
requested by the community!

<!--truncate-->

## Experimental Python tier 2 and 3 support

Thanks to a contribution from [@harlequin](https://github.com/harlequin), we now provide Python tier
[2](/docs/how-it-works/languages#tier-2--platform) and
[3](/docs/how-it-works/languages#tier-3--toolchain) support. Python is a very popular language, so
it was about time that we officially supported it in some capacity. When enabling Python in moon,
the following functionality will be enabled:

- Will download and install Python into the toolchain (if `python.version` is defined).
- Will parse `requirements.txt` to extract dependency and version information for hashing.
- Will automatically activate virtual environments and setup `PATH` for tasks.
- Will automatically install dependencies for `requirements.txt` via pip.
- And a handful of internal interoperability features.

However, we're still marking this implementation as experimental, as it hasn't been thoroughly
tested, and we're not 100% positive the workflows are what users expect. So please provide any
feedback, good or bad!

Furthermore, as mentioned above, we install dependencies with pip (the version of pip that comes
pre-installed with the current Python version). At this time, _we do not support_ other package
managers like Poetry, Hatch, PDM, Rye, or uv, but we will in the future!

### New `python` configurations

Languages in
[moon are enabled through configuration](/docs/how-it-works/languages#enabling-a-language) blocks in
[`.moon/toolchain.yml`](/docs/config/toolchain), and Python is no different. We now support a
[`python`](/docs/config/toolchain#python) toolchain setting
([view all available settings](/docs/config/toolchain)).

```yaml title=".moon/toolchain.yml"
python:
version: '3.14.0'
```

When the `python` setting is defined, it will enable the language and
[deep platform integration](/docs/how-it-works/languages#tier-2--platform), and when the
`python.version` field is defined, it will further enable
[toolchain support](/docs/how-it-works/languages#tier-3--toolchain). Both of these features provide
heavy automation, improving the overall developer experience.

This is fantastic, but what if another Python project in the monorepo requires a different toolchain
channel/version? If so, they can use the new [`toolchain.python`](/docs/config/project#python)
setting in [`moon.yml`](/docs/config/project) to define project-level overrides.

```yaml title="<project>/moon.yml"
toolchain:
python:
version: '3.12.0'
```

### Built-in virtual environments

Of course we also have support for Python virtual environments. When running a task, moon will
automatically enable the virtual environment in the workspace root or a project root (depending on
config)! The name of the venv can be customized with the
[`python.venvName`](/docs/config/toolchain#venvname) setting, otherwise it defaults to `.venv`.

```yaml title=".moon/toolchain.yml"
python:
venvName: '.venvcustom'
```

## Unstable self-hosted remote caching

This has been a request from the community for a very long time, and we get it, not every user wants
to store their build artifacts (not source code) in a third-party cloud provider. While we're proud
of our [moonbase service](/moonbase), it wasn't a viable option for many companies because of their
proprietary requirements. We spent a few months reworking moonbase to work as a self-hosted service,
so users can host it as on-prem solution, but it has been a very costly initiative. During this
process, we came to the conclusion that spending our time and resources on moonbase simply isn't
worth it, so we made the hard decision to sunset moonbase in the future.

So what does that mean for remote caching? Simply put, you can now host your own remote caching
service! Instead of building a custom API for consumers to implement, we opted to implement the
[Bazel Remote Execution API](https://github.com/bazelbuild/remote-apis/blob/main/build/bazel/remote/execution/v2/remote_execution.proto),
which supports a content addressable storage (CAS) API, and is used by other popular build tools,
like Bazel, Buck, Pants, and more!

Because we opted for a community solution, we can now focus all our efforts on [moon](/moon) and
[proto](/proto)! Additionally, adopting RE API allows you, the user, to use an off-the-shelf
solution, like [`bazel-remote`](https://github.com/buchgr/bazel-remote), instead of building your
own custom caching server! For example, to make use of remote caching, simply serve `bazel-remote`:

```shell
bazel-remote --dir /path/to/moon-cache --max_size 10 --storage_mode uncompressed --grpc_address 0.0.0.0:9092
```

And then configure the new [`unstable_remote`](/docs/config/workspace#unstable_remote) setting in
[`.moon/workspace.yml`](/docs/config/workspace).

```yaml title=".moon/workspace.yml"
unstable_remote:
host: 'grpc://your-host.com:9092'
```

Pretty awesome right? Jump to the
[official remote caching](/docs/guides/remote-cache#self-hosted-unstable) documentation for more
information on this implementation.

### Unsupported features

Since this is a new feature, we're marking it as unstable, as it hasn't been thoroughly tested, and
_does not_ support the entire Bazel RE API. The following features _have not_ been implemented, but
will be in the future.

- HTTP(S) host (we only support gRPC(S))
- Digest hashing functions besides SHA256
- Compression formats (we only support identity/uncompressed right now)
- Write/read bytestream for large blobs (4mb is the current limit)
- Better TLS/mTLS support (it has some issues)
- Directory blob types

## New task graph and improved affected tracker

In our [last release](./moon-v1.29#new-affected-projects-tracker), we announced a new affected
tracker for projects, but _not_ for tasks. The reason behind this was simple, we couldn't! Up until
now, we had no concept of a task graph, we had a project graph (that had tasks) and an action graph
(that ran tasks), but the relationships between tasks were split across both of these graphs.

This made it complicated to support tasks for the new affected tracker, as the action graph
_consumes_ the tracker, not the other way around. To remedy this issue, we now support an official
task graph, which is derived from the project graph, and then feeds into the action graph. Since the
task graph sits outside of the action graph, we're now able to support tasks in the affected
tracker!

Because of the new task graph, the following improvements have been introduced:

- Tasks are now supported in the affected tracker (as mentioned).
- We can now properly query dependencies and dependents of specific tasks.
- We can now associate types to relationships (graph edges). For example, in the future we can add
optional, cleanup, and other kinds of dependencies.
- We've added a new command, [`moon task-graph`](/docs/commands/task-graph), that can visualize
tasks in isolation.
- We've updated the [`moon query tasks`](/docs/commands/query/tasks) to derive information from the
task graph.

## Other changes

View the [official release](https://github.com/moonrepo/moon/releases/tag/v1.30.0) for a full list
of changes.

- Added basic support for Git submodules, and will now extract touched files from all submodules.
- Added 7 new token variables: `$arch`, `$os`, `$osFamily`, `$vcsBranch`, `$vcsRepository`,
`$vcsRevision`, `$workingDir`
- Added a `rust.binstallVersion` setting to `.moon/toolchain.yml`.
- Updated Pkl configurations to support `read()` for environment variables.
Binary file added website/blog/img/moon/v1.30.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions website/docs/commands/project-graph.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: project-graph
---

The `moon project-graph [name]` (or `moon pg`) command will generate and serve a visual graph of all
The `moon project-graph [id]` (or `moon pg`) command will generate and serve a visual graph of all
configured projects as nodes, with dependencies between as edges, and can also output the graph in
[Graphviz DOT format](https://graphviz.org/doc/info/lang.html).

Expand All @@ -14,7 +14,7 @@ $ moon project-graph
$ moon project-graph --dot > graph.dot
```

> A project name can be passed to focus the graph to only that project and it's dependencies. For
> A project name can be passed to focus the graph to only that project and its dependencies. For
> example, `moon project-graph app`.

### Arguments
Expand Down
22 changes: 14 additions & 8 deletions website/docs/commands/query/tasks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,24 @@ passing the `--json` flag. The output has the following structure:

#### Affected

- `--affected` - Filter projects that have been affected by touched files.
- `--affected` - Filter tasks that have been affected by touched files.
- `--downstream` - Include downstream dependents of queried tasks. Supports "none" (default),
"direct", "deep".
<VersionLabel version="1.30.0" />
- `--upstream` - Include upstream dependencies of queried tasks. Supports "none", "direct", "deep"
(default).
<VersionLabel version="1.30.0" />

#### Filters
#### Filters<VersionLabel version="1.30.0" />

All option values are case-insensitive regex patterns.

- `--alias <regex>` - Filter projects that match this alias.
- `--id <regex>` - Filter projects that match this ID/name.
- `--language <regex>` - Filter projects of this programming language.
- `--source <regex>` - Filter projects that match this source path.
- `--tasks <regex>` - Filter projects that have the following tasks.
- `--type <regex>` - Filter project of this type.
- `--command <regex>` - Filter tasks that match this command.
- `--id <regex>` - Filter tasks that match this ID.
- `--platform <regex>` - Filter tasks of this platform.
- `--project <regex>` - Filter tasks that belong to this project.
- `--script <regex>` - Filter tasks that match this script.
- `--type <regex>` - Filter tasks of this type.

### Configuration

Expand Down
47 changes: 47 additions & 0 deletions website/docs/commands/task-graph.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
title: task-graph
---

import VersionLabel from '@site/src/components/Docs/VersionLabel';

<VersionLabel version="1.30.0" header />

The `moon task-graph [target]` (or `moon tg`) command will generate and serve a visual graph of all
configured tasks as nodes, with dependencies between as edges, and can also output the graph in
[Graphviz DOT format](https://graphviz.org/doc/info/lang.html).

```shell
# Run the visualizer locally
$ moon task-graph

# Export to DOT format
$ moon task-graph --dot > graph.dot
```

> A task target can be passed to focus the graph to only that task and its dependencies. For
> example, `moon task-graph app:build`.

### Arguments

- `[target]` - Optional target of task to focus.

### Options

- `--dependents` - Include direct dependents of the focused task.
- `--dot` - Print the graph in DOT format.
- `--json` - Print the graph in JSON format.

## Example output

The following output is an example of the graph in DOT format.

```dot
digraph {
0 [ label="types:build" style=filled, shape=oval, fillcolor=gray, fontcolor=black]
1 [ label="runtime:build" style=filled, shape=oval, fillcolor=gray, fontcolor=black]
2 [ label="website:build" style=filled, shape=oval, fillcolor=gray, fontcolor=black]
1 -> 0 [ label="required" arrowhead=box, arrowtail=box]
2 -> 1 [ label="required" arrowhead=box, arrowtail=box]
2 -> 0 [ label="required" arrowhead=box, arrowtail=box]
}
```
Loading
Loading