zed/script/check-licenses
morgankrey 27c566c212
Relicense Zed source code under GPL (#57948)
## Summary

This moves the remaining first-party AGPL surface to GPL, a less
restrictive license for these components. Apache-2.0 components are
unchanged.

Changes:
- Updates the `collab` crate from `AGPL-3.0-or-later` to
`GPL-3.0-or-later`
- Removes the root AGPL license file and first-party crate AGPL symlinks
- Updates web, documentation, Flatpak, README, and terms references to
reflect the GPL/Apache licensing split
- Updates the open-source component example list in the terms and
regenerates the RTF copy; no other terms changes are intended
- Adds guardrails so first-party crates cannot declare AGPL licensing or
carry `LICENSE-AGPL` files

Release timing: preview during the week of June 1, 2026; stable during
the week of June 8, 2026.

## Residual AGPL/Affero references

- `LICENSE-GPL`: GPLv3's own compatibility clause; unchanged official
license text.
- `crates/json_schema_store/src/schemas/package.json`: generic npm
package-license schema value, not Zed licensing.
- `script/check-licenses`, `script/new-crate`,
`script/licenses/zed-licenses.toml`: guardrails that reject or warn
against reintroducing AGPL.

## Verification

- `script/check-licenses`
- `script/generate-licenses`
- `script/generate-terms-rtf`
- `script/new-crate license_probe_for_gpl`, then discarded generated
crate
- `script/new-crate license_probe_for_agpl agpl` fails as expected
- `mdbook build docs`
- `./script/clippy`
- `git grep -n -I -E "AGPL|Affero"`
- `git diff --check`

Release Notes:

- The `collab` crate, used to implement Zed's collaboration backend, is
now licensed under the GPL instead of the AGPL. The AGPL license is no
longer used in the zed repository.
2026-05-28 20:19:17 +00:00

86 lines
2.6 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
check_manifest_for_agpl () {
local cargo_toml="$1"
if grep -Eiq '(agpl|affero)' "$cargo_toml"; then
echo "Error: $cargo_toml references an AGPL license. First-party crates must use LICENSE-GPL or LICENSE-APACHE."
exit 1
fi
if grep -Eiq '^[[:space:]]*license-file[[:space:]]*=' "$cargo_toml"; then
echo "Error: $cargo_toml uses license-file. First-party crates must declare LICENSE-GPL or LICENSE-APACHE via the license field and symlink."
exit 1
fi
}
check_no_agpl_license_file () {
if [[ -e "LICENSE-AGPL" || -L "LICENSE-AGPL" ]]; then
echo "Error: LICENSE-AGPL exists. First-party code must use LICENSE-GPL or LICENSE-APACHE."
exit 1
fi
while IFS= read -r -d '' license_file; do
if [[ -e "$license_file" || -L "$license_file" ]]; then
echo "Error: $license_file exists. First-party crates must use LICENSE-GPL or LICENSE-APACHE."
exit 1
fi
done < <(git ls-files -z -- "*/LICENSE-AGPL")
}
check_symlink_target () {
local symlink_path="$1"
local license_name="$2"
local target=$(readlink "$symlink_path")
local dir=$(dirname "$symlink_path")
local depth=$(echo "$dir" | tr '/' '\n' | wc -l)
local expected_prefix=""
for ((i = 0; i < depth; i++)); do
expected_prefix="../$expected_prefix"
done
local expected_target="${expected_prefix}${license_name}"
if [[ "$target" != "$expected_target" ]]; then
echo "Error: $symlink_path points to '$target' but should point to '$expected_target'"
exit 1
fi
if [[ ! -e "$symlink_path" ]]; then
echo "Error: $symlink_path is a broken symlink (target '$target' does not exist)"
exit 1
fi
}
check_license () {
local dir="$1"
local allowed_licenses=("LICENSE-GPL" "LICENSE-APACHE")
for license in "${allowed_licenses[@]}"; do
if [[ -L "$dir/$license" ]]; then
check_symlink_target "$dir/$license" "$license"
return 0
elif [[ -e "$dir/$license" ]]; then
echo "Error: $dir/$license exists but is not a symlink."
exit 1
fi
done
echo "Error: $dir does not contain a LICENSE-GPL or LICENSE-APACHE symlink"
exit 1
}
check_no_agpl_license_file
git ls-files -z -- "Cargo.toml" "**/Cargo.toml" | while IFS= read -r -d '' cargo_toml; do
check_manifest_for_agpl "$cargo_toml"
if [[ "$cargo_toml" == */Cargo.toml ]]; then
check_license "$(dirname "$cargo_toml")"
fi
done
echo "check-licenses succeeded"