This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Release

Release rules

The release tool generates release manifests/pages and deploys their files. OCI deployment uses Soras. SSH deployment uses the operator’s OpenSSH and rsync executables and requires rsync on the destination; it needs neither Soras nor Ansible. No custom receiver or upload service is installed.

al_release_bundle packages declared payloads as release.json and files/<filename> in a Bazel directory output. It reuses the manifest generator for file sizes and hashes and reads STABLE_VERSION from the versioning owner’s workspace status. Run its build through tools/versioning/cmd/versioning/versioning.sh bazel -- build --config=release. It does not contact deployment destinations or calculate another version.

The CLI equivalent is generate --project projects/<name> --version_file <status-file> --add_file <payload> --output_dir <empty-directory>. Repeat --add_file for multiple payloads. Missing or duplicate version values, unsafe path components, missing payloads, colliding filenames, and empty bundles fail. The output directory must be absent or empty. A completed manifest is written only after payload copying finishes.

The website’s //projects/alwaldend.com:release target consumes this rule; its owner documents the complete build and SSH publication commands.

A release directory contains release.json and files/<filename>. The manifest owns the version, project, and payload names. Pass an explicit SSH environment and destination, or a deployment JSON containing an ssh object. The download component provides preconfigured targets. These default to the existing ansible administrator and use sudo -n -u download for content operations. Host configuration from merged PR #102 provides the content account, storage, and server rsync package. Configure the selected host before publishing.

bazel_agent bazel run //infra/download:publish.local -- \
  --release_dir "$PWD/out/release"

bazel_agent bazel run //infra/download:publish.yandex -- \
  --release_dir "$PWD/out/site-release" --site_archive website.tar.gz \
  --steps upload,extract,link

For other SSH destinations:

bazel_agent bazel run //tools/release -- deploy \
  --release_dir "$PWD/out/release" --environment local \
  --ssh_host download-host --ssh_user admin --publish_user download \
  --ssh_root /srv/download

--ssh_deployment or --ssh_host publishes all manifest files through that SSH destination, regardless of their original OCI metadata. Otherwise, --environment selects matching SSH metadata attached to individual items. Omitting the environment selects existing OCI deployments and requires --soras_path. An empty selection fails.

Host trust and authentication use normal OpenSSH configuration, with strict host-key checks and noninteractive authentication. --ssh_config, --ssh_identity, --ssh_known_hosts, --ssh_port, and --ssh_user allow explicit local overrides. Credentials are not written into manifests. --ssh_path and --rsync_path select installed executables. The default deployment deadline is 30 minutes; --timeout overrides it.

The public project defaults to the manifest project after removing a leading projects/; --project overrides it. The tool validates each path component and uses the remote layout <root>/projects/<project>/releases/<version>/<filename>. Rsync updates matching filenames using checksums, normalizes directories to 0755 and files to 0644, and never deletes other files. A failed multi-file transfer can leave completed files published; rsync’s error and itemized output describe the transfer. Files are transferred through private staging on the same content filesystem, using rsync’s normal temporary-file rename.

Remote shell arguments use POSIX single-quote escaping to preserve literal values.

--steps selects an ordered subset of upload,extract,link; it defaults to upload. Each step can run alone. Unknown, repeated, empty, or out-of-order steps fail before a remote change. A release manifest still supplies the project and version for every step.

# Upload files only; archives remain ordinary downloadable files.
bazel_agent bazel run //infra/download:publish.yandex -- \
  --release_dir "$PWD/out/site-release" --steps upload

# Extract an already-published archive without changing current.
bazel_agent bazel run //infra/download:publish.yandex -- \
  --release_dir "$PWD/out/site-release" --steps extract \
  --site_archive website.tar.gz

# Select an existing extracted release; no local payload or archive is needed.
bazel_agent bazel run //infra/download:publish.yandex -- \
  --release_dir "$PWD/out/site-release" --steps link

Extraction accepts a published .tar.gz or .zip filename. It retrieves the archive into a private local temporary directory, validates and extracts it, then copies the site into private remote staging and promotes the completed directory to sites/<project>/releases/<version>. Local free space must hold both the archive and its extracted content. No archive helper is installed on the host. Existing completed site versions are retained without retransferring or reextracting their content.

The extractor rejects traversal, absolute paths, links, device entries, duplicate file names, and missing root index.html. Archives may contain at most 100,000 entries. Archive ownership, executable bits, and extended attributes are not preserved. Server-created content inherits the destination’s configured SELinux labels.

Linking atomically replaces sites/<project>/current after checking the selected directory and its root index. A short flock serializes promotion and link changes. A failure in an earlier step leaves the current site unchanged, although completed ordinary uploads may already be public. Use a new version for changed website content; select an earlier retained version with --steps link. There is no separate rollback command or automatic deletion.

al_release_deployment accepts ssh_* metadata alongside its existing OCI variant. ssh_public_url supplies generated artifact URLs with the public project/version layout. al_release_binary can package a fixed SSH destination with oras = None, while taking --release_dir at runtime.

1 - Bzl

Bazel bindings for the release tool

1.1 - al_release

al_release

load("@com_alwaldend_src//tools/release/main/bzl:al_release.bzl", "al_release")

al_release(name, srcs, git_bundle, git_state, manifest, project, release_name, release_tool,
           root_prefix)

Rule describing a release

ATTRIBUTES

Name Description Type Mandatory Default
name A unique name for this target. Name required
srcs Sources List of labels optional []
git_bundle Deterministic Git bundle used to generate release metadata Label optional "@com_alwaldend_src_tools_git//:release_git_state"
git_state Additional declared Git state used to generate release metadata List of labels optional []
manifest Load manifest from a file instead of generating it from srcs Label optional None
project Project package_name String required
release_name Release name String required
release_tool Release tool Label optional "@com_alwaldend_src//tools/release/main/go"
root_prefix Root prefix String optional "content/docs"

1.2 - al_release_binary

al_release_binary

load("@com_alwaldend_src//tools/release/main/bzl:al_release_binary.bzl", "al_release_binary")

al_release_binary(name, oras, **kwargs)

Create a release command; oras=None omits the OCI executable.

PARAMETERS

Name Description Default Value
name Target name. none
oras OCI executable, or None for an SSH-only command. "//third_party/land_oras_oras:oras"
kwargs Remaining release rule attributes. none

1.3 - al_release_bundle

Package declared payloads and versioning metadata for the release publisher.

al_release_bundle

load("@com_alwaldend_src//tools/release/main/bzl:al_release_bundle.bzl", "al_release_bundle")

al_release_bundle(name, srcs, project, release_tool)

Emit release.json and files/ using STABLE_VERSION from the versioning bootstrap.

ATTRIBUTES

Name Description Type Mandatory Default
name A unique name for this target. Name required
srcs Payload files; basenames must be unique. List of labels required
project Canonical project subdirectory. String required
release_tool Manifest generator and bundle writer. Label optional "@com_alwaldend_src//tools/release/main/go"

1.4 - al_release_deployment

al_release_deployment

load("@com_alwaldend_src//tools/release/main/bzl:al_release_deployment.bzl", "al_release_deployment")

al_release_deployment(name, oci_repository, ssh_environment, ssh_host, ssh_project, ssh_public_url,
                      ssh_publish_user, ssh_root, ssh_site_archive, ssh_user)

Deployment info

ATTRIBUTES

Name Description Type Mandatory Default
name A unique name for this target. Name required
oci_repository OCI repository url String optional ""
ssh_environment Explicit environment selector String optional ""
ssh_host SSH hostname or SSH configuration alias String optional ""
ssh_project Public project name; empty removes projects/ from the manifest project String optional ""
ssh_public_url Public download origin for generated artifact links String optional ""
ssh_publish_user Content account selected through sudo -n -u String optional ""
ssh_root Provisioned content root String optional "/srv/download"
ssh_site_archive Optional website archive filename String optional ""
ssh_user Administrator login; empty uses SSH configuration String optional ""

1.5 - al_release_deployment_info

load("@com_alwaldend_src//tools/release/main/bzl:al_release_deployment_info.bzl", "AlReleaseDeploymentInfo")

AlReleaseDeploymentInfo(info, info_file)

Deployment info

FIELDS

Name Description
info Deployment info struct
info_file Deployment info file

1.6 - al_release_deps

al_release_deps

load("@com_alwaldend_src//tools/release/main/bzl:al_release_deps.bzl", "al_release_deps")

al_release_deps(name, srcs, visibility, **kwargs)

Generate a dependency diagram using genquery

PARAMETERS

Name Description Default Value
name name none
srcs list of labels to generate deps for (should be full labels) none
visibility visibility None
kwargs kwargs for al_release_files none

1.7 - al_release_files

al_release_files

load("@com_alwaldend_src//tools/release/main/bzl:al_release_files.bzl", "al_release_files")

al_release_files(name, deps, srcs, deployments, ignore_suffixes, release_tool)

ATTRIBUTES

Name Description Type Mandatory Default
name A unique name for this target. Name required
deps Deps List of labels optional []
srcs Sources List of labels optional []
deployments Deployment info List of labels optional []
ignore_suffixes Ignore src files ending with these suffixes List of strings optional []
release_tool Release tool Label optional "@com_alwaldend_src//tools/release/main/go"

1.8 - al_release_files_info

load("@com_alwaldend_src//tools/release/main/bzl:al_release_files_info.bzl", "AlReleaseFilesInfo")

AlReleaseFilesInfo(files, manifest)

Release files

FIELDS

Name Description
files File dict, keys are filenames, values are Files
manifest Release manifest for srcs

1.9 - al_release_info

load("@com_alwaldend_src//tools/release/main/bzl:al_release_info.bzl", "AlReleaseInfo")

AlReleaseInfo(release_name, project, files, manifest)

Release information

FIELDS

Name Description
release_name Release name (string)
project Project subdir (string)
files File dict, keys are filenames, values are Files
manifest Release manifest (File)

2 - Go

Golang code for the release tool

3 - Proto

Protobuf contracts

3.1 - contracts

Proto docs for contracts.proto
load("@rules_java//java:defs.bzl", "java_library")

java_library(
    name = "name",
    deps = [
        "@com_alwaldend_src//tools/release/main/proto/contracts:contracts_java_library",
    ],
)
load("@rules_go//go:def.bzl", "go_library")

go_library(
    name = "name",
    deps = [
        "@com_alwaldend_src//tools/release/main/proto/contracts:contracts",
    ],
)
syntax = "proto3";

package release;

import "tools/git/main/proto/contracts/contracts.proto";

option go_package = "git.alwaldend.com/alwaldend/src/tools/release/main/proto/contracts";

message ReleaseHash {
  string algo = 1;
  string content = 2;
}

message ReleaseFile {
  repeated ReleaseHash hashes = 1;
  string name = 2;
  string safe_name = 6;
  string url = 3;
  int64 size = 4;
  string local_path = 5;
}

message ReleaseItem {
  ReleaseFile file = 1;
  repeated ReleaseDeployment deployments = 2;
}

message Project {
  string subdir = 1;
  string safe_subdir = 2;
}

message Git {
  git.GitCommit revision = 1;
  repeated git.GitCommit commits = 2;
}

message ReleasePageSectionItemAttr {
  string name = 1;
  string content = 2;
}

message ReleasePageSectionItem {
  string content = 1;
  string content_url = 2;
  repeated ReleasePageSectionItemAttr attrs = 3;
}

message ReleasePageSection {
  string title = 1;
  repeated ReleasePageSectionItem items = 2;
}

message ReleasePage {
  repeated ReleasePageSection sections = 1;
}

message ReleaseDeploymentOci {
  string repository = 1;
  repeated string tags = 2;
}

message ReleaseDeployment {
  ReleaseDeploymentOci oci = 1;
  ReleaseDeploymentSsh ssh = 2;
}

message ReleaseDeploymentSsh {
  string environment = 1;
  string host = 2;
  string user = 3;
  string root = 4;
  string project = 5;
  string site_archive = 6;
  string publish_user = 7;
  string public_url = 8;
}

message Release {
  repeated ReleaseItem items = 1;
  string name = 2;
  Project project = 3;
  Git git = 4;
}