Skip to content

Commit fd10ea1

Browse files
authored
chore(scripts): add script to update list of experiments after release (#13872)
Fixes #13119
1 parent 687d953 commit fd10ea1

File tree

3 files changed

+187
-2
lines changed

3 files changed

+187
-2
lines changed

docs/contributing/feature-stages.md

+9-2
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,12 @@ coder server --experiments=feature1,feature2
2727
# Alternatively, use the `CODER_EXPERIMENTS` environment variable.
2828
```
2929

30-
For a list of all experiments, refer to the
31-
[codersdk reference](https://pkg.go.dev/github.com/coder/coder/v2/codersdk#Experiment).
30+
## Available experimental features
31+
32+
<!-- Code generated by scripts/release/docs_update_experiments.sh. DO NOT EDIT. -->
33+
<!-- BEGIN: available-experimental-features -->
34+
35+
Currently no experimental features are available in the latest mainline or
36+
stable release.
37+
38+
<!-- END: available-experimental-features -->

scripts/release.sh

+1
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ You can follow the release progress [here](https://github.com/coder/coder/action
374374
create_pr_stash=1
375375
fi
376376
maybedryrun "${dry_run}" git checkout -b "${pr_branch}" "${remote}/${branch}"
377+
maybedryrun "${dry_run}" execrelative ./release/docs_update_experiments.sh
377378
execrelative go run ./release autoversion --channel "${channel}" "${new_version}" --dry-run="${dry_run}"
378379
maybedryrun "${dry_run}" git add docs
379380
maybedryrun "${dry_run}" git commit -m "${title}"
+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#!/usr/bin/env bash
2+
3+
# Usage: ./docs_update_experiments.sh
4+
#
5+
# This script updates the available experimental features in the documentation.
6+
# It fetches the latest mainline and stable releases to extract the available
7+
# experiments and their descriptions. The script will update the
8+
# feature-stages.md file with a table of the latest experimental features.
9+
10+
set -euo pipefail
11+
# shellcheck source=scripts/lib.sh
12+
source "$(dirname "${BASH_SOURCE[0]}")/../lib.sh"
13+
cdroot
14+
15+
# From install.sh
16+
echo_latest_stable_version() {
17+
# https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c#gistcomment-2758860
18+
version="$(curl -fsSLI -o /dev/null -w "%{url_effective}" https://github.com/coder/coder/releases/latest)"
19+
version="${version#https://github.com/coder/coder/releases/tag/v}"
20+
echo "v${version}"
21+
}
22+
23+
echo_latest_mainline_version() {
24+
# Fetch the releases from the GitHub API, sort by version number,
25+
# and take the first result. Note that we're sorting by space-
26+
# separated numbers and without utilizing the sort -V flag for the
27+
# best compatibility.
28+
echo "v$(
29+
curl -fsSL https://api.github.com/repos/coder/coder/releases |
30+
awk -F'"' '/"tag_name"/ {print $4}' |
31+
tr -d v |
32+
tr . ' ' |
33+
sort -k1,1nr -k2,2nr -k3,3nr |
34+
head -n1 |
35+
tr ' ' .
36+
)"
37+
}
38+
39+
# For testing or including experiments from `main`.
40+
echo_latest_main_version() {
41+
echo origin/main
42+
}
43+
44+
sparse_clone_codersdk() {
45+
mkdir -p "${1}"
46+
cd "${1}"
47+
rm -rf "${2}"
48+
git clone --quiet --no-checkout "${PROJECT_ROOT}" "${2}"
49+
cd "${2}"
50+
git sparse-checkout set --no-cone codersdk
51+
git checkout "${3}" -- codersdk
52+
echo "${1}/${2}"
53+
}
54+
55+
parse_all_experiments() {
56+
# Go doc doesn't include inline array comments, so this parsing should be
57+
# good enough. We remove all whitespaces so that we can extract a plain
58+
# string that looks like {}, {ExpA}, or {ExpA,ExpB,}.
59+
#
60+
# Example: ExperimentsAll=Experiments{ExperimentNotifications,ExperimentAutoFillParameters,}
61+
go doc -all -C "${dir}" ./codersdk ExperimentsAll |
62+
tr -d $'\n\t ' |
63+
grep -E -o 'ExperimentsAll=Experiments\{[^}]*\}' |
64+
sed -e 's/.*{\(.*\)}.*/\1/' |
65+
tr ',' '\n'
66+
}
67+
68+
parse_experiments() {
69+
# Extracts the experiment name and description from the Go doc output.
70+
# The output is in the format:
71+
#
72+
# ||Add new experiments here!
73+
# ExperimentExample|example|This isn't used for anything.
74+
# ExperimentAutoFillParameters|auto-fill-parameters|This should not be taken out of experiments until we have redesigned the feature.
75+
# ExperimentMultiOrganization|multi-organization|Requires organization context for interactions, default org is assumed.
76+
# ExperimentCustomRoles|custom-roles|Allows creating runtime custom roles.
77+
# ExperimentNotifications|notifications|Sends notifications via SMTP and webhooks following certain events.
78+
# ExperimentWorkspaceUsage|workspace-usage|Enables the new workspace usage tracking.
79+
# ||ExperimentTest is an experiment with
80+
# ||a preceding multi line comment!?
81+
# ExperimentTest|test|
82+
#
83+
go doc -all -C "${1}" ./codersdk Experiment |
84+
sed \
85+
-e 's/\t\(Experiment[^ ]*\)\ \ *Experiment = "\([^"]*\)"\(.*\/\/ \(.*\)\)\?/\1|\2|\4/' \
86+
-e 's/\t\/\/ \(.*\)/||\1/' |
87+
grep '|'
88+
}
89+
90+
workdir=build/docs/experiments
91+
dest=docs/contributing/feature-stages.md
92+
93+
log "Updating available experimental features in ${dest}"
94+
95+
declare -A experiments=() experiment_tags=()
96+
97+
for channel in mainline stable; do
98+
log "Fetching experiments from ${channel}"
99+
100+
tag=$(echo_latest_"${channel}"_version)
101+
dir="$(sparse_clone_codersdk "${workdir}" "${channel}" "${tag}")"
102+
103+
declare -A all_experiments=()
104+
all_experiments_out="$(parse_all_experiments "${dir}")"
105+
if [[ -n "${all_experiments_out}" ]]; then
106+
readarray -t all_experiments_tmp <<<"${all_experiments_out}"
107+
for exp in "${all_experiments_tmp[@]}"; do
108+
all_experiments[$exp]=1
109+
done
110+
fi
111+
112+
# Track preceding/multiline comments.
113+
maybe_desc=
114+
115+
while read -r line; do
116+
line=${line//$'\n'/}
117+
readarray -d '|' -t parts <<<"$line"
118+
119+
# Missing var/key, this is a comment or description.
120+
if [[ -z ${parts[0]} ]]; then
121+
maybe_desc+="${parts[2]//$'\n'/ }"
122+
continue
123+
fi
124+
125+
var="${parts[0]}"
126+
key="${parts[1]}"
127+
desc="${parts[2]}"
128+
desc=${desc//$'\n'/}
129+
130+
# If desc (trailing comment) is empty, use the preceding/multiline comment.
131+
if [[ -z "${desc}" ]]; then
132+
desc="${maybe_desc% }"
133+
fi
134+
maybe_desc=
135+
136+
# Skip experiments not listed in ExperimentsAll.
137+
if [[ ! -v all_experiments[$var] ]]; then
138+
log "Skipping ${var}, not listed in ExperimentsAll"
139+
continue
140+
fi
141+
142+
# Don't overwrite desc, prefer first come, first served (i.e. mainline > stable).
143+
if [[ ! -v experiments[$key] ]]; then
144+
experiments[$key]="$desc"
145+
fi
146+
147+
# Track the release channels where the experiment is available.
148+
experiment_tags[$key]+="${channel}, "
149+
done < <(parse_experiments "${dir}")
150+
done
151+
152+
table="$(
153+
if [[ "${#experiments[@]}" -eq 0 ]]; then
154+
echo "Currently no experimental features are available in the latest mainline or stable release."
155+
exit 0
156+
fi
157+
158+
echo "| Feature | Description | Available in |"
159+
echo "|---------|-------------|--------------|"
160+
for key in "${!experiments[@]}"; do
161+
desc=${experiments[$key]}
162+
tags=${experiment_tags[$key]%, }
163+
echo "| \`$key\` | $desc | ${tags} |"
164+
done
165+
)"
166+
167+
# Use awk to print everything outside the BEING/END block and insert the
168+
# table in between.
169+
awk \
170+
-v table="${table}" \
171+
'BEGIN{include=1} /BEGIN: available-experimental-features/{print; print table; include=0} /END: available-experimental-features/{include=1} include' \
172+
"${dest}" \
173+
>"${dest}".tmp
174+
mv "${dest}".tmp "${dest}"
175+
176+
# Format the file for a pretty table (target single file for speed).
177+
(cd site && pnpm exec prettier --cache --write ../"${dest}")

0 commit comments

Comments
 (0)